blob: f1de140b5596bf6b31477342f985b6cec1f680f7 [file]
---
title: Security policy enforcement
authors:
- "@gnodet"
reviewers: []
approvers: []
creation-date: 2026-03-27
last-updated: 2026-03-27
status: implementable
see-also: []
replaces: []
superseded-by: []
---
== Summary
Apache Camel now includes a built-in security policy enforcement mechanism that detects insecure
configuration at startup time. It covers four categories of security concerns: plain-text secrets,
insecure SSL/TLS settings, insecure deserialization, and development-only features enabled in
production. The mechanism is annotation-driven, flows through the existing build pipeline, and
enforces configurable policies (allow/warn/fail) at startup.
== Motivation
Camel applications often handle sensitive data and run in production environments where
misconfiguration can lead to security vulnerabilities. Common issues include:
- Plain-text passwords in configuration files instead of using vault references or environment variables
- Disabling SSL certificate verification (`trustAllCertificates=true`) for convenience
- Enabling Java object deserialization on messaging endpoints, which is a known attack vector
- Leaving development/debug features enabled in production (dev console, debug logging endpoints)
These misconfigurations are easy to make and hard to catch in code review. A framework-level
detection mechanism catches them early and consistently.
== Goals
- Detect insecure configuration at startup time, before the application processes any messages
- Provide clear, actionable warnings or errors that tell users exactly which property is problematic
and how to fix it
- Support per-category policy levels so users can selectively enforce or relax checks
- Integrate with Camel's profile system so production deployments default to strict enforcement
- Use the existing annotation and code generation pipeline — no new build plugins or metadata formats
- Make it easy for component authors to annotate new security-sensitive parameters
== Non-Goals
- Runtime monitoring of configuration changes (this is startup-time only)
- Network-level security scanning or vulnerability detection
- Replacing external secret management solutions (Vault, AWS Secrets Manager, etc.)
- Enforcing authentication/authorization policies on Camel routes
== Context
Camel already has a `secret = true` attribute on `@UriParam` and `@Metadata` annotations, used
primarily for masking values in the dev console and logging. The security policy framework extends
this existing annotation model with a new `security` attribute and adds a startup-time enforcement
layer.
=== Security Categories
The framework defines four security violation categories:
[cols="1,3,2"]
|===
| Category | Description | Example Properties
| `secret`
| Plain-text sensitive values that should use property placeholders, vault references, or `RAW()`
| `*.password`, `*.apiKey`, `*.token`, `*.secretKey`
| `insecure:ssl`
| SSL/TLS settings that weaken transport security
| `trustAllCertificates`, `hostnameVerificationEnabled=false`, `sslEnabled=false`
| `insecure:serialization`
| Enabling Java object deserialization, a known attack vector
| `allowJavaSerializedObject=true`, `transferException=true`
| `insecure:dev`
| Development/debug features that should not be enabled in production
| `devConsoleEnabled=true`, `debugBreakpoints`
|===
=== Policy Levels
Each category can be configured to one of three enforcement levels:
- **`allow`** — silently permit the configuration (no warning, no error)
- **`warn`** — log a warning but allow startup to continue (this is the default)
- **`fail`** — prevent application startup with a clear error message listing all violations
== Proposal
=== Annotation Model
Component authors annotate security-sensitive parameters using existing annotations:
==== Secret parameters
Use `secret = true` on `@UriParam` or `@Metadata`:
[source,java]
----
@UriParam(label = "security", secret = true,
description = "The password for authentication")
private String password;
----
==== Insecure configuration flags
Use the `security` attribute on `@UriParam`:
[source,java]
----
@UriParam(label = "security", security = "insecure:ssl",
description = "Whether to trust all SSL certificates")
private boolean trustAllCertificates;
----
Valid `security` values: `insecure:ssl`, `insecure:serialization`, `insecure:dev`.
=== Build Pipeline
The annotations flow through the existing build pipeline:
1. **Component JSON generation** — `camel-package-maven-plugin` reads `@UriParam(security=...)`
and writes it to the component JSON metadata (e.g., `components/http.json`)
2. **Catalog aggregation** — `camel-catalog` collects all component JSONs
3. **SecurityUtils generation** — `UpdateSensitizeHelper` mojo scans all component JSONs and
generates `SecurityUtils.java` in `camel-util`, containing a static map of property patterns
to security categories
4. **Runtime detection** — at startup, `SecurityUtils.detectViolations()` checks all resolved
properties against the generated map
No new build plugins are needed. The existing `@UriParam` → JSON → code generation pipeline
handles everything.
=== Configuration Properties
Users configure policies via standard Camel properties:
[source,properties]
----
# Global default policy (applies to all categories unless overridden)
camel.security.policy = warn
# Per-category overrides
camel.security.secretPolicy = fail
camel.security.insecureSslPolicy = warn
camel.security.insecureSerializationPolicy = fail
camel.security.insecureDevPolicy = allow
# Exempt specific properties from all checks
camel.security.allowedProperties = camel.ssl.trustAllCertificates,camel.component.http.password
----
These are modeled by `SecurityConfigurationProperties` under the `camel.security.*` namespace.
=== Profile-Aware Defaults
When using the `prod` profile (`camel.main.profile = prod`), the global policy automatically
defaults to `fail` — production applications refuse to start with insecure configurations unless
the user explicitly overrides the policy.
The `dev` profile keeps the default `warn` behavior.
=== Detection Logic
`SecurityUtils.detectViolations()` is the core detection method. It:
1. Iterates over all resolved properties
2. Skips `camel.security.*` properties (policy configuration itself)
3. Checks each property against the generated insecure-property map (for `insecure:*` categories)
4. Checks if the value looks like a plain-text secret (for `secret` category) using heuristics:
- Is the key a known secret key (matches `*.password`, `*.apiKey`, etc.)?
- Does the value look like a literal (not a placeholder like `${env:...}`, `{{...}}`, `RAW()`)?
5. Applies the configured policy for each category
6. Returns a list of `SecurityViolation` records
Values that use property placeholders (`${...}`), vault references (`{{...}}`), environment
variable references (`${env:...}`), or `RAW()` wrapping are considered safe and not flagged.
=== Startup Enforcement
The enforcement runs in `BaseMainSupport.enforceSecurityPolicies()` during startup,
after property resolution but before route startup:
1. Resolve the effective policy for each category (category-specific overrides > global > profile default)
2. Call `SecurityUtils.detectViolations()` with the resolved properties
3. For `warn` violations: log each violation at WARN level
4. For `fail` violations: collect all violations and throw `RuntimeCamelException` with a summary
5. Store the `SecurityPolicyResult` as a context plugin for programmatic access
=== SecurityPolicyResult
The result of security policy evaluation is stored as a `ContextPlugin` on the `CamelContext`,
accessible via:
[source,java]
----
SecurityPolicyResult result = context.getCamelContextExtension()
.getContextPlugin(SecurityPolicyResult.class);
if (result.hasViolations()) {
// handle violations programmatically
}
----
This allows health checks, management endpoints, and custom code to inspect security status.
== Development
=== For Component Authors
When adding new endpoint parameters:
1. **Passwords, tokens, API keys** — always add `secret = true` on `@UriParam` or `@Metadata`
2. **SSL bypass flags** — add `security = "insecure:ssl"` on `@UriParam`
3. **Serialization flags** — add `security = "insecure:serialization"` on `@UriParam`
4. **Dev/debug features** — add `security = "insecure:dev"` on `@UriParam`
After annotating, rebuild the component and regenerate the catalog to update `SecurityUtils.java`.
=== For Core Contributors
Key files in the implementation:
- `core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java` — detection logic and
generated property map
- `core/camel-util/src/main/java/org/apache/camel/util/SecurityViolation.java` — violation record
- `core/camel-main/src/main/java/org/apache/camel/main/SecurityConfigurationProperties.java` —
configuration model
- `core/camel-main/src/main/java/org/apache/camel/main/SecurityPolicyResult.java` — result stored
as context plugin
- `core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java` —
`enforceSecurityPolicies()` method
- `tooling/maven/camel-package-maven-plugin/.../UpdateSensitizeHelper.java` — code generation
from component JSONs
== Shared SecureRandom
=== Rationale
`java.security.SecureRandom` is thread-safe but heavyweight to instantiate: each `new SecureRandom()`
call gathers OS entropy (reads from `/dev/urandom` on Linux, `CryptGenRandom` on Windows). Creating
a fresh instance per call is wasteful and measurably slows down startup when many components
initialize cryptographic material (e.g., `camel-pqc` had ~40 separate allocations).
Since Java 9, the default `SecureRandom` implementation uses DRBG (Deterministic Random Bit
Generator) which handles concurrent access efficiently. A single shared instance is both safe and
performant.
=== Usage
`SecureRandomHelper` in `camel-util` provides a shared instance via a static getter:
[source,java]
----
import org.apache.camel.util.SecureRandomHelper;
// Use the shared instance instead of new SecureRandom()
keygen.init(SecureRandomHelper.getSecureRandom());
kpGen.initialize(paramSpec, SecureRandomHelper.getSecureRandom());
SecureRandomHelper.getSecureRandom().nextBytes(nonce);
----
=== When to use
- **Internal Camel code** that needs cryptographic randomness with the platform default algorithm:
key generation, nonce creation, certificate serial numbers, cipher initialization.
- **Component and data format implementations** that call JCA APIs (`KeyPairGenerator.initialize()`,
`KeyGenerator.init()`, `KEMGenerateSpec`, etc.).
=== When NOT to use
- **User-configurable secure random**: when the user needs to pick a specific algorithm or provider
(e.g., FIPS-certified PRNG), use `SecureRandomParameters` from the JSSE utility
(`org.apache.camel.support.jsse.SecureRandomParameters`) instead.
- **`SecureRandom.getInstanceStrong()`**: for cases requiring the strongest available entropy source
(may block on Linux), create a dedicated instance — the shared one uses the platform default, which
is non-blocking.
- **Test code**: if deterministic randomness is needed for reproducible tests, inject a seeded
`SecureRandom` directly rather than using the shared instance.
=== Future Work
- **Broader annotation audit**: Systematically audit all 300+ components for missing `secret=true`
and `security` attributes
- **Route-level URI scanning**: Detect plain-text secrets embedded in endpoint URIs
(e.g., `smtp://user:password@host`)
- **Camel CLI integration**: `camel security-audit` command for offline configuration analysis
- **Custom violation categories**: Allow users to define additional security categories and patterns
=== Completed
- **Health check integration**: `SecurityPolicyHealthCheck` exposes security policy status via
Camel's health check API. Reports DOWN only for `fail`-level violations; `warn`-level violations
report UP with details.