This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 1d2cba763707 CAMEL-24730: camel-spiffe - do not let inbound headers
choose the operation or the validated audience
1d2cba763707 is described below
commit 1d2cba7637072aece5aca8f83a6cdb904e08e1e8
Author: Andrea Cosentino <[email protected]>
AuthorDate: Tue Sep 15 06:52:12 2026 +0200
CAMEL-24730: camel-spiffe - do not let inbound headers choose the operation
or the validated audience
SpiffeProducer read both the operation and the audience from message
headers in
preference to the endpoint configuration. For validateJwtSvid the audience
is the
check itself, so CamelSpiffeAudience let a token minted for another service
validate
successfully, and CamelSpiffeOperation could turn a validator endpoint into
a minter
that returned the workload's own JWT-SVID.
validateJwtSvid now uses the configured audience only (fetchJwtSvid still
honours the
header, where a per-message audience is legitimate). A new
allowOperationHeader
option, default false and marked security = "insecure:dev", gates
CamelSpiffeOperation so camel.main.profile=prod flags routes that enable
it. Header
javadoc and a Security notes docs section describe when each header is
honoured.
main only: camel-spiffe is new in the unreleased 4.23.0.
Closes #26420
Co-Authored-By: Claude Opus 5 <[email protected]>
---
.../apache/camel/catalog/components/spiffe.json | 10 +-
.../camel/catalog/docs/spiffe-component.adoc | 19 ++++
.../spiffe/SpiffeComponentConfigurer.java | 6 ++
.../component/spiffe/SpiffeEndpointConfigurer.java | 6 ++
.../component/spiffe/SpiffeEndpointUriFactory.java | 3 +-
.../org/apache/camel/component/spiffe/spiffe.json | 10 +-
.../src/main/docs/spiffe-component.adoc | 19 ++++
.../component/spiffe/SpiffeConfiguration.java | 18 ++++
.../camel/component/spiffe/SpiffeConstants.java | 9 +-
.../camel/component/spiffe/SpiffeProducer.java | 32 ++++--
.../component/spiffe/SpiffeHeaderOverrideTest.java | 111 +++++++++++++++++++++
.../java/org/apache/camel/util/SecurityUtils.java | 1 +
.../dsl/SpiffeComponentBuilderFactory.java | 22 ++++
.../endpoint/dsl/SpiffeEndpointBuilderFactory.java | 48 ++++++++-
14 files changed, 294 insertions(+), 20 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spiffe.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spiffe.json
index 82dc8b9cc87d..1b8c1a3c3731 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spiffe.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spiffe.json
@@ -30,11 +30,12 @@
"operation": { "index": 3, "kind": "property", "displayName": "Operation",
"group": "producer", "label": "", "required": false, "type": "enum",
"javaType": "org.apache.camel.component.spiffe.SpiffeOperation", "enum": [
"fetchX509Svid", "fetchJwtSvid", "validateJwtSvid" ], "deprecated": false,
"autowired": false, "secret": false, "defaultValue": "fetchX509Svid",
"configurationClass": "org.apache.camel.component.spiffe.SpiffeConfiguration",
"configurationField": "configuration", "descr [...]
"autowiredEnabled": { "index": 4, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching t [...]
"workloadApiClient": { "index": 5, "kind": "property", "displayName":
"Workload Api Client", "group": "advanced", "label": "advanced", "required":
false, "type": "object", "javaType": "io.spiffe.workloadapi.WorkloadApiClient",
"deprecated": false, "deprecationNote": "", "autowired": true, "secret": false,
"configurationClass": "org.apache.camel.component.spiffe.SpiffeConfiguration",
"configurationField": "configuration", "description": "An existing
WorkloadApiClient to use. When set, [...]
- "spiffeSocketPath": { "index": 6, "kind": "property", "displayName":
"Spiffe Socket Path", "group": "security", "label": "security", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.spiffe.SpiffeConfiguration", "configurationField":
"configuration", "description": "The address of the SPIFFE Workload API
endpoint (for example {code unix:\/\/\/tmp\/agent.sock} [...]
+ "allowOperationHeader": { "index": 6, "kind": "property", "displayName":
"Allow Operation Header", "group": "security", "label": "security", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "security": "insecure:dev",
"defaultValue": false, "configurationClass":
"org.apache.camel.component.spiffe.SpiffeConfiguration", "configurationField":
"configuration", "description": "Whether the CamelSpiffeOperation header may
[...]
+ "spiffeSocketPath": { "index": 7, "kind": "property", "displayName":
"Spiffe Socket Path", "group": "security", "label": "security", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.spiffe.SpiffeConfiguration", "configurationField":
"configuration", "description": "The address of the SPIFFE Workload API
endpoint (for example {code unix:\/\/\/tmp\/agent.sock} [...]
},
"headers": {
- "CamelSpiffeOperation": { "index": 0, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"org.apache.camel.component.spiffe.SpiffeOperation or String", "deprecated":
false, "deprecationNote": "", "autowired": false, "secret": false,
"description": "Overrides the operation to be used by the producer.",
"constantName": "org.apache.camel.component.spiffe.SpiffeConstants#OPERATION" },
- "CamelSpiffeAudience": { "index": 1, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The comma-separated audience(s) for the
fetchJwtSvid and validateJwtSvid operations.", "constantName":
"org.apache.camel.component.spiffe.SpiffeConstants#AUDIENCE" },
+ "CamelSpiffeOperation": { "index": 0, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"org.apache.camel.component.spiffe.SpiffeOperation or String", "deprecated":
false, "deprecationNote": "", "autowired": false, "secret": false,
"description": "Overrides the operation to be used by the producer. Ignored
unless the endpoint sets allowOperationHeader=true, because the operation
decides whether the endpoint validates a token [...]
+ "CamelSpiffeAudience": { "index": 1, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The comma-separated audience(s) for the
fetchJwtSvid operation. Ignored by validateJwtSvid, which always validates
against the configured audience: there the audience is the check that binds the
token to this workload, not a parameter [...]
"CamelSpiffeToken": { "index": 2, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The JWT-SVID token to validate, for the
validateJwtSvid operation.", "constantName":
"org.apache.camel.component.spiffe.SpiffeConstants#TOKEN" },
"CamelSpiffeSpiffeId": { "index": 3, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The SPIFFE ID of the returned SVID.",
"constantName": "org.apache.camel.component.spiffe.SpiffeConstants#SPIFFE_ID" },
"CamelSpiffeExpiry": { "index": 4, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"java.util.Date", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The expiry of the returned JWT-SVID.",
"constantName": "org.apache.camel.component.spiffe.SpiffeConstants#EXPIRY" }
@@ -45,6 +46,7 @@
"operation": { "index": 2, "kind": "parameter", "displayName":
"Operation", "group": "producer", "label": "", "required": false, "type":
"enum", "javaType": "org.apache.camel.component.spiffe.SpiffeOperation",
"enum": [ "fetchX509Svid", "fetchJwtSvid", "validateJwtSvid" ], "deprecated":
false, "autowired": false, "secret": false, "defaultValue": "fetchX509Svid",
"configurationClass": "org.apache.camel.component.spiffe.SpiffeConfiguration",
"configurationField": "configuration", "desc [...]
"lazyStartProducer": { "index": 3, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produc [...]
"workloadApiClient": { "index": 4, "kind": "parameter", "displayName":
"Workload Api Client", "group": "advanced", "label": "advanced", "required":
false, "type": "object", "javaType": "io.spiffe.workloadapi.WorkloadApiClient",
"deprecated": false, "deprecationNote": "", "autowired": true, "secret": false,
"configurationClass": "org.apache.camel.component.spiffe.SpiffeConfiguration",
"configurationField": "configuration", "description": "An existing
WorkloadApiClient to use. When set [...]
- "spiffeSocketPath": { "index": 5, "kind": "parameter", "displayName":
"Spiffe Socket Path", "group": "security", "label": "security", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.spiffe.SpiffeConfiguration", "configurationField":
"configuration", "description": "The address of the SPIFFE Workload API
endpoint (for example {code unix:\/\/\/tmp\/agent.sock [...]
+ "allowOperationHeader": { "index": 5, "kind": "parameter", "displayName":
"Allow Operation Header", "group": "security", "label": "security", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "security": "insecure:dev",
"defaultValue": false, "configurationClass":
"org.apache.camel.component.spiffe.SpiffeConfiguration", "configurationField":
"configuration", "description": "Whether the CamelSpiffeOperation header ma
[...]
+ "spiffeSocketPath": { "index": 6, "kind": "parameter", "displayName":
"Spiffe Socket Path", "group": "security", "label": "security", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.spiffe.SpiffeConfiguration", "configurationField":
"configuration", "description": "The address of the SPIFFE Workload API
endpoint (for example {code unix:\/\/\/tmp\/agent.sock [...]
}
}
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/spiffe-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/spiffe-component.adoc
index 93f8dafde435..17b45a0a1888 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/spiffe-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/spiffe-component.adoc
@@ -117,3 +117,22 @@ from("direct:start")
------------------------------------------------------------
include::spring-boot:partial$starter.adoc[]
+
+== Security notes
+
+* *The operation comes from the endpoint.* `CamelSpiffeOperation` is ignored
unless the endpoint sets
+ `allowOperationHeader=true`. The operation decides whether this endpoint
*validates* a token or *mints* one, so a
+ message able to set it could turn a validator into an endpoint that hands
out this workload's own JWT-SVID.
+* *A validation always uses the configured audience.* `CamelSpiffeAudience` is
honoured by `fetchJwtSvid`, where the
+ audience is a genuine per-message parameter ("mint me a token for X"), and
ignored by `validateJwtSvid`, where the
+ audience is the check that binds the token to this workload. Letting a
message choose it would allow a JWT-SVID
+ minted for a different service to validate successfully.
+* *Strip the component's headers on untrusted ingress.* As with any Camel
component, a consumer that does not apply
+ a `HeaderFilterStrategy` blocking `Camel*` lets a sender populate the header
map. Call
+ `removeHeaders("CamelSpiffe*")` before the `spiffe:` endpoint when the
message comes from an untrusted producer.
+* *Key material reaches the message.* `fetchX509Svid` places an `X509Svid` -
which carries the private key - on the
+ body, and `fetchJwtSvid` places the bearer token. Do not log or trace the
body for those operations.
+* *Constrain the peer.* `SpiffeSSLContextParameters` requires either an
`acceptedSpiffeIds` allow-list or
+ `acceptAnySpiffeId=true`; it fails closed when neither is given. Prefer the
allow-list -
+ `acceptAnySpiffeId` accepts any SVID that chains to the trust bundle, which
authenticates the trust domain but not
+ the peer.
diff --git
a/components/camel-spiffe/src/generated/java/org/apache/camel/component/spiffe/SpiffeComponentConfigurer.java
b/components/camel-spiffe/src/generated/java/org/apache/camel/component/spiffe/SpiffeComponentConfigurer.java
index 67a411d84847..c5f39f05820e 100644
---
a/components/camel-spiffe/src/generated/java/org/apache/camel/component/spiffe/SpiffeComponentConfigurer.java
+++
b/components/camel-spiffe/src/generated/java/org/apache/camel/component/spiffe/SpiffeComponentConfigurer.java
@@ -30,6 +30,8 @@ public class SpiffeComponentConfigurer extends
PropertyConfigurerSupport impleme
public boolean configure(CamelContext camelContext, Object obj, String
name, Object value, boolean ignoreCase) {
SpiffeComponent target = (SpiffeComponent) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "allowoperationheader":
+ case "allowOperationHeader":
getOrCreateConfiguration(target).setAllowOperationHeader(property(camelContext,
boolean.class, value)); return true;
case "audience":
getOrCreateConfiguration(target).setAudience(property(camelContext,
java.lang.String.class, value)); return true;
case "autowiredenabled":
case "autowiredEnabled":
target.setAutowiredEnabled(property(camelContext, boolean.class, value));
return true;
@@ -53,6 +55,8 @@ public class SpiffeComponentConfigurer extends
PropertyConfigurerSupport impleme
@Override
public Class<?> getOptionType(String name, boolean ignoreCase) {
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "allowoperationheader":
+ case "allowOperationHeader": return boolean.class;
case "audience": return java.lang.String.class;
case "autowiredenabled":
case "autowiredEnabled": return boolean.class;
@@ -72,6 +76,8 @@ public class SpiffeComponentConfigurer extends
PropertyConfigurerSupport impleme
public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
SpiffeComponent target = (SpiffeComponent) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "allowoperationheader":
+ case "allowOperationHeader": return
getOrCreateConfiguration(target).isAllowOperationHeader();
case "audience": return getOrCreateConfiguration(target).getAudience();
case "autowiredenabled":
case "autowiredEnabled": return target.isAutowiredEnabled();
diff --git
a/components/camel-spiffe/src/generated/java/org/apache/camel/component/spiffe/SpiffeEndpointConfigurer.java
b/components/camel-spiffe/src/generated/java/org/apache/camel/component/spiffe/SpiffeEndpointConfigurer.java
index afa1dd20067f..0eedcc77671a 100644
---
a/components/camel-spiffe/src/generated/java/org/apache/camel/component/spiffe/SpiffeEndpointConfigurer.java
+++
b/components/camel-spiffe/src/generated/java/org/apache/camel/component/spiffe/SpiffeEndpointConfigurer.java
@@ -23,6 +23,8 @@ public class SpiffeEndpointConfigurer extends
PropertyConfigurerSupport implemen
public boolean configure(CamelContext camelContext, Object obj, String
name, Object value, boolean ignoreCase) {
SpiffeEndpoint target = (SpiffeEndpoint) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "allowoperationheader":
+ case "allowOperationHeader":
target.getConfiguration().setAllowOperationHeader(property(camelContext,
boolean.class, value)); return true;
case "audience":
target.getConfiguration().setAudience(property(camelContext,
java.lang.String.class, value)); return true;
case "lazystartproducer":
case "lazyStartProducer":
target.setLazyStartProducer(property(camelContext, boolean.class, value));
return true;
@@ -43,6 +45,8 @@ public class SpiffeEndpointConfigurer extends
PropertyConfigurerSupport implemen
@Override
public Class<?> getOptionType(String name, boolean ignoreCase) {
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "allowoperationheader":
+ case "allowOperationHeader": return boolean.class;
case "audience": return java.lang.String.class;
case "lazystartproducer":
case "lazyStartProducer": return boolean.class;
@@ -59,6 +63,8 @@ public class SpiffeEndpointConfigurer extends
PropertyConfigurerSupport implemen
public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
SpiffeEndpoint target = (SpiffeEndpoint) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "allowoperationheader":
+ case "allowOperationHeader": return
target.getConfiguration().isAllowOperationHeader();
case "audience": return target.getConfiguration().getAudience();
case "lazystartproducer":
case "lazyStartProducer": return target.isLazyStartProducer();
diff --git
a/components/camel-spiffe/src/generated/java/org/apache/camel/component/spiffe/SpiffeEndpointUriFactory.java
b/components/camel-spiffe/src/generated/java/org/apache/camel/component/spiffe/SpiffeEndpointUriFactory.java
index ad61739085cb..38ae3005bca9 100644
---
a/components/camel-spiffe/src/generated/java/org/apache/camel/component/spiffe/SpiffeEndpointUriFactory.java
+++
b/components/camel-spiffe/src/generated/java/org/apache/camel/component/spiffe/SpiffeEndpointUriFactory.java
@@ -24,7 +24,8 @@ public class SpiffeEndpointUriFactory extends
org.apache.camel.support.component
private static final Set<String> ENDPOINT_IDENTITY_PROPERTY_NAMES;
private static final Map<String, String> MULTI_VALUE_PREFIXES;
static {
- Set<String> props = new HashSet<>(6);
+ Set<String> props = new HashSet<>(7);
+ props.add("allowOperationHeader");
props.add("audience");
props.add("label");
props.add("lazyStartProducer");
diff --git
a/components/camel-spiffe/src/generated/resources/META-INF/org/apache/camel/component/spiffe/spiffe.json
b/components/camel-spiffe/src/generated/resources/META-INF/org/apache/camel/component/spiffe/spiffe.json
index 82dc8b9cc87d..1b8c1a3c3731 100644
---
a/components/camel-spiffe/src/generated/resources/META-INF/org/apache/camel/component/spiffe/spiffe.json
+++
b/components/camel-spiffe/src/generated/resources/META-INF/org/apache/camel/component/spiffe/spiffe.json
@@ -30,11 +30,12 @@
"operation": { "index": 3, "kind": "property", "displayName": "Operation",
"group": "producer", "label": "", "required": false, "type": "enum",
"javaType": "org.apache.camel.component.spiffe.SpiffeOperation", "enum": [
"fetchX509Svid", "fetchJwtSvid", "validateJwtSvid" ], "deprecated": false,
"autowired": false, "secret": false, "defaultValue": "fetchX509Svid",
"configurationClass": "org.apache.camel.component.spiffe.SpiffeConfiguration",
"configurationField": "configuration", "descr [...]
"autowiredEnabled": { "index": 4, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching t [...]
"workloadApiClient": { "index": 5, "kind": "property", "displayName":
"Workload Api Client", "group": "advanced", "label": "advanced", "required":
false, "type": "object", "javaType": "io.spiffe.workloadapi.WorkloadApiClient",
"deprecated": false, "deprecationNote": "", "autowired": true, "secret": false,
"configurationClass": "org.apache.camel.component.spiffe.SpiffeConfiguration",
"configurationField": "configuration", "description": "An existing
WorkloadApiClient to use. When set, [...]
- "spiffeSocketPath": { "index": 6, "kind": "property", "displayName":
"Spiffe Socket Path", "group": "security", "label": "security", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.spiffe.SpiffeConfiguration", "configurationField":
"configuration", "description": "The address of the SPIFFE Workload API
endpoint (for example {code unix:\/\/\/tmp\/agent.sock} [...]
+ "allowOperationHeader": { "index": 6, "kind": "property", "displayName":
"Allow Operation Header", "group": "security", "label": "security", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "security": "insecure:dev",
"defaultValue": false, "configurationClass":
"org.apache.camel.component.spiffe.SpiffeConfiguration", "configurationField":
"configuration", "description": "Whether the CamelSpiffeOperation header may
[...]
+ "spiffeSocketPath": { "index": 7, "kind": "property", "displayName":
"Spiffe Socket Path", "group": "security", "label": "security", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.spiffe.SpiffeConfiguration", "configurationField":
"configuration", "description": "The address of the SPIFFE Workload API
endpoint (for example {code unix:\/\/\/tmp\/agent.sock} [...]
},
"headers": {
- "CamelSpiffeOperation": { "index": 0, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"org.apache.camel.component.spiffe.SpiffeOperation or String", "deprecated":
false, "deprecationNote": "", "autowired": false, "secret": false,
"description": "Overrides the operation to be used by the producer.",
"constantName": "org.apache.camel.component.spiffe.SpiffeConstants#OPERATION" },
- "CamelSpiffeAudience": { "index": 1, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The comma-separated audience(s) for the
fetchJwtSvid and validateJwtSvid operations.", "constantName":
"org.apache.camel.component.spiffe.SpiffeConstants#AUDIENCE" },
+ "CamelSpiffeOperation": { "index": 0, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"org.apache.camel.component.spiffe.SpiffeOperation or String", "deprecated":
false, "deprecationNote": "", "autowired": false, "secret": false,
"description": "Overrides the operation to be used by the producer. Ignored
unless the endpoint sets allowOperationHeader=true, because the operation
decides whether the endpoint validates a token [...]
+ "CamelSpiffeAudience": { "index": 1, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The comma-separated audience(s) for the
fetchJwtSvid operation. Ignored by validateJwtSvid, which always validates
against the configured audience: there the audience is the check that binds the
token to this workload, not a parameter [...]
"CamelSpiffeToken": { "index": 2, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The JWT-SVID token to validate, for the
validateJwtSvid operation.", "constantName":
"org.apache.camel.component.spiffe.SpiffeConstants#TOKEN" },
"CamelSpiffeSpiffeId": { "index": 3, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The SPIFFE ID of the returned SVID.",
"constantName": "org.apache.camel.component.spiffe.SpiffeConstants#SPIFFE_ID" },
"CamelSpiffeExpiry": { "index": 4, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"java.util.Date", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The expiry of the returned JWT-SVID.",
"constantName": "org.apache.camel.component.spiffe.SpiffeConstants#EXPIRY" }
@@ -45,6 +46,7 @@
"operation": { "index": 2, "kind": "parameter", "displayName":
"Operation", "group": "producer", "label": "", "required": false, "type":
"enum", "javaType": "org.apache.camel.component.spiffe.SpiffeOperation",
"enum": [ "fetchX509Svid", "fetchJwtSvid", "validateJwtSvid" ], "deprecated":
false, "autowired": false, "secret": false, "defaultValue": "fetchX509Svid",
"configurationClass": "org.apache.camel.component.spiffe.SpiffeConfiguration",
"configurationField": "configuration", "desc [...]
"lazyStartProducer": { "index": 3, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produc [...]
"workloadApiClient": { "index": 4, "kind": "parameter", "displayName":
"Workload Api Client", "group": "advanced", "label": "advanced", "required":
false, "type": "object", "javaType": "io.spiffe.workloadapi.WorkloadApiClient",
"deprecated": false, "deprecationNote": "", "autowired": true, "secret": false,
"configurationClass": "org.apache.camel.component.spiffe.SpiffeConfiguration",
"configurationField": "configuration", "description": "An existing
WorkloadApiClient to use. When set [...]
- "spiffeSocketPath": { "index": 5, "kind": "parameter", "displayName":
"Spiffe Socket Path", "group": "security", "label": "security", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.spiffe.SpiffeConfiguration", "configurationField":
"configuration", "description": "The address of the SPIFFE Workload API
endpoint (for example {code unix:\/\/\/tmp\/agent.sock [...]
+ "allowOperationHeader": { "index": 5, "kind": "parameter", "displayName":
"Allow Operation Header", "group": "security", "label": "security", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "security": "insecure:dev",
"defaultValue": false, "configurationClass":
"org.apache.camel.component.spiffe.SpiffeConfiguration", "configurationField":
"configuration", "description": "Whether the CamelSpiffeOperation header ma
[...]
+ "spiffeSocketPath": { "index": 6, "kind": "parameter", "displayName":
"Spiffe Socket Path", "group": "security", "label": "security", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.spiffe.SpiffeConfiguration", "configurationField":
"configuration", "description": "The address of the SPIFFE Workload API
endpoint (for example {code unix:\/\/\/tmp\/agent.sock [...]
}
}
diff --git a/components/camel-spiffe/src/main/docs/spiffe-component.adoc
b/components/camel-spiffe/src/main/docs/spiffe-component.adoc
index 93f8dafde435..17b45a0a1888 100644
--- a/components/camel-spiffe/src/main/docs/spiffe-component.adoc
+++ b/components/camel-spiffe/src/main/docs/spiffe-component.adoc
@@ -117,3 +117,22 @@ from("direct:start")
------------------------------------------------------------
include::spring-boot:partial$starter.adoc[]
+
+== Security notes
+
+* *The operation comes from the endpoint.* `CamelSpiffeOperation` is ignored
unless the endpoint sets
+ `allowOperationHeader=true`. The operation decides whether this endpoint
*validates* a token or *mints* one, so a
+ message able to set it could turn a validator into an endpoint that hands
out this workload's own JWT-SVID.
+* *A validation always uses the configured audience.* `CamelSpiffeAudience` is
honoured by `fetchJwtSvid`, where the
+ audience is a genuine per-message parameter ("mint me a token for X"), and
ignored by `validateJwtSvid`, where the
+ audience is the check that binds the token to this workload. Letting a
message choose it would allow a JWT-SVID
+ minted for a different service to validate successfully.
+* *Strip the component's headers on untrusted ingress.* As with any Camel
component, a consumer that does not apply
+ a `HeaderFilterStrategy` blocking `Camel*` lets a sender populate the header
map. Call
+ `removeHeaders("CamelSpiffe*")` before the `spiffe:` endpoint when the
message comes from an untrusted producer.
+* *Key material reaches the message.* `fetchX509Svid` places an `X509Svid` -
which carries the private key - on the
+ body, and `fetchJwtSvid` places the bearer token. Do not log or trace the
body for those operations.
+* *Constrain the peer.* `SpiffeSSLContextParameters` requires either an
`acceptedSpiffeIds` allow-list or
+ `acceptAnySpiffeId=true`; it fails closed when neither is given. Prefer the
allow-list -
+ `acceptAnySpiffeId` accepts any SVID that chains to the trust bundle, which
authenticates the trust domain but not
+ the peer.
diff --git
a/components/camel-spiffe/src/main/java/org/apache/camel/component/spiffe/SpiffeConfiguration.java
b/components/camel-spiffe/src/main/java/org/apache/camel/component/spiffe/SpiffeConfiguration.java
index e19fbe9c5eb3..f34dad7f40e3 100644
---
a/components/camel-spiffe/src/main/java/org/apache/camel/component/spiffe/SpiffeConfiguration.java
+++
b/components/camel-spiffe/src/main/java/org/apache/camel/component/spiffe/SpiffeConfiguration.java
@@ -34,6 +34,9 @@ public class SpiffeConfiguration implements Cloneable {
@UriParam
private String audience;
+ @UriParam(label = "security", defaultValue = "false", security =
"insecure:dev")
+ private boolean allowOperationHeader;
+
@UriParam(label = "advanced",
description = "An existing WorkloadApiClient to use. When set,
the component does not"
+ " create or close its own client and
spiffeSocketPath is ignored.")
@@ -77,6 +80,21 @@ public class SpiffeConfiguration implements Cloneable {
this.audience = audience;
}
+ public boolean isAllowOperationHeader() {
+ return allowOperationHeader;
+ }
+
+ /**
+ * Whether the {@code CamelSpiffeOperation} header may override the
configured operation.
+ * <p/>
+ * Disabled by default: the operation decides whether this endpoint
<em>validates</em> a token or <em>mints</em>
+ * one, so a message that can set it can turn a validator into an endpoint
that hands out this workload's own
+ * JWT-SVID. Enable it only on routes whose input is trusted.
+ */
+ public void setAllowOperationHeader(boolean allowOperationHeader) {
+ this.allowOperationHeader = allowOperationHeader;
+ }
+
/**
* An already-configured {@link WorkloadApiClient} to use instead of
letting the endpoint create one.
*/
diff --git
a/components/camel-spiffe/src/main/java/org/apache/camel/component/spiffe/SpiffeConstants.java
b/components/camel-spiffe/src/main/java/org/apache/camel/component/spiffe/SpiffeConstants.java
index 9091a159efef..349e30523515 100644
---
a/components/camel-spiffe/src/main/java/org/apache/camel/component/spiffe/SpiffeConstants.java
+++
b/components/camel-spiffe/src/main/java/org/apache/camel/component/spiffe/SpiffeConstants.java
@@ -21,12 +21,17 @@ import org.apache.camel.spi.Metadata;
public final class SpiffeConstants {
private static final String HEADER_PREFIX = "CamelSpiffe";
- @Metadata(label = "producer", description = "Overrides the operation to be
used by the producer.",
+ @Metadata(label = "producer",
+ description = "Overrides the operation to be used by the
producer. Ignored unless the endpoint sets"
+ + " allowOperationHeader=true, because the
operation decides whether the endpoint"
+ + " validates a token or mints one.",
javaType = "org.apache.camel.component.spiffe.SpiffeOperation or
String")
public static final String OPERATION = HEADER_PREFIX + "Operation";
@Metadata(label = "producer",
- description = "The comma-separated audience(s) for the
fetchJwtSvid and validateJwtSvid operations.",
+ description = "The comma-separated audience(s) for the
fetchJwtSvid operation. Ignored by"
+ + " validateJwtSvid, which always validates
against the configured audience: there the"
+ + " audience is the check that binds the token to
this workload, not a parameter.",
javaType = "String")
public static final String AUDIENCE = HEADER_PREFIX + "Audience";
diff --git
a/components/camel-spiffe/src/main/java/org/apache/camel/component/spiffe/SpiffeProducer.java
b/components/camel-spiffe/src/main/java/org/apache/camel/component/spiffe/SpiffeProducer.java
index f66c2f16df06..ec38b420261f 100644
---
a/components/camel-spiffe/src/main/java/org/apache/camel/component/spiffe/SpiffeProducer.java
+++
b/components/camel-spiffe/src/main/java/org/apache/camel/component/spiffe/SpiffeProducer.java
@@ -75,7 +75,10 @@ public class SpiffeProducer extends DefaultProducer {
throw new IllegalArgumentException(
"A JWT-SVID token is required for validateJwtSvid (set the
CamelSpiffeToken header or the body)");
}
- String[] audiences = resolveAudiences(exchange);
+ // the audience is the check here, not a parameter: it is what binds
the token to THIS workload, so it
+ // comes from the configuration only. Honouring CamelSpiffeAudience
would let a caller validate a token
+ // minted for someone else against an audience of their choosing.
+ String[] audiences = resolveConfiguredAudiences();
JwtSvid svid = client.validateJwtSvid(token, audiences[0]);
Message message = getMessageForResponse(exchange);
message.setBody(svid);
@@ -83,27 +86,44 @@ public class SpiffeProducer extends DefaultProducer {
}
private SpiffeOperation determineOperation(Exchange exchange) {
+ SpiffeOperation configured =
getEndpoint().getConfiguration().getOperation();
+ if (!getEndpoint().getConfiguration().isAllowOperationHeader()) {
+ return configured;
+ }
SpiffeOperation operation
= exchange.getIn().getHeader(SpiffeConstants.OPERATION,
SpiffeOperation.class);
- return operation != null ? operation :
getEndpoint().getConfiguration().getOperation();
+ return operation != null ? operation : configured;
}
+ /**
+ * Audience for a fetch: a genuine per-message parameter, so the header
may override the configuration.
+ */
private String[] resolveAudiences(Exchange exchange) {
String audience = exchange.getIn().getHeader(SpiffeConstants.AUDIENCE,
String.class);
if (ObjectHelper.isEmpty(audience)) {
audience = getEndpoint().getConfiguration().getAudience();
}
+ return splitAudiences(audience, "set the audience option or the
CamelSpiffeAudience header");
+ }
+
+ /**
+ * Audience for a validation: taken from the configuration only, never
from the message.
+ */
+ private String[] resolveConfiguredAudiences() {
+ // deliberately does not mention the header: it is ignored for
validation
+ return splitAudiences(getEndpoint().getConfiguration().getAudience(),
"set the audience option");
+ }
+
+ private String[] splitAudiences(String audience, String how) {
if (ObjectHelper.isEmpty(audience)) {
- throw new IllegalArgumentException(
- "At least one audience is required (set the audience
option or the CamelSpiffeAudience header)");
+ throw new IllegalArgumentException("At least one audience is
required (" + how + ")");
}
String[] parts = Arrays.stream(audience.split(","))
.map(String::trim)
.filter(s -> !s.isEmpty())
.toArray(String[]::new);
if (parts.length == 0) {
- throw new IllegalArgumentException(
- "At least one non-blank audience is required (set the
audience option or the CamelSpiffeAudience header)");
+ throw new IllegalArgumentException("At least one non-blank
audience is required (" + how + ")");
}
return parts;
}
diff --git
a/components/camel-spiffe/src/test/java/org/apache/camel/component/spiffe/SpiffeHeaderOverrideTest.java
b/components/camel-spiffe/src/test/java/org/apache/camel/component/spiffe/SpiffeHeaderOverrideTest.java
new file mode 100644
index 000000000000..51727c805923
--- /dev/null
+++
b/components/camel-spiffe/src/test/java/org/apache/camel/component/spiffe/SpiffeHeaderOverrideTest.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.spiffe;
+
+import io.spiffe.spiffeid.SpiffeId;
+import io.spiffe.svid.jwtsvid.JwtSvid;
+import io.spiffe.workloadapi.WorkloadApiClient;
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.Exchange;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Covers which message headers may steer the producer.
+ * <p/>
+ * The operation decides whether the endpoint validates a token or mints one,
and for a validation the audience is the
+ * check that binds the token to this workload - neither may be chosen by the
message unless the route opts in.
+ */
+class SpiffeHeaderOverrideTest extends CamelTestSupport {
+
+ private static final String CONFIGURED_AUDIENCE =
"spiffe://example.org/my-service";
+ private static final String OTHER_AUDIENCE =
"spiffe://example.org/other-service";
+
+ @BindToRegistry("client")
+ private final WorkloadApiClient client = mock(WorkloadApiClient.class);
+
+ private static JwtSvid svid() {
+ JwtSvid svid = mock(JwtSvid.class);
+
when(svid.getSpiffeId()).thenReturn(SpiffeId.parse("spiffe://example.org/workload"));
+ when(svid.getToken()).thenReturn("minted-token");
+ return svid;
+ }
+
+ private String validator() {
+ return
"spiffe:v?workloadApiClient=#client&operation=validateJwtSvid&audience=" +
CONFIGURED_AUDIENCE;
+ }
+
+ @Test
+ void validationIgnoresTheAudienceHeader() throws Exception {
+ JwtSvid stub = svid();
+ when(client.validateJwtSvid(anyString(),
anyString())).thenReturn(stub);
+
+ Exchange out = template.request(validator(), e -> {
+ e.getIn().setHeader(SpiffeConstants.TOKEN, "a-token");
+ e.getIn().setHeader(SpiffeConstants.AUDIENCE, OTHER_AUDIENCE);
+ });
+
+ assertThat(out.getException()).isNull();
+ ArgumentCaptor<String> audience =
ArgumentCaptor.forClass(String.class);
+ verify(client).validateJwtSvid(anyString(), audience.capture());
+ assertThat(audience.getValue()).isEqualTo(CONFIGURED_AUDIENCE);
+ }
+
+ @Test
+ void aFetchStillHonoursTheAudienceHeader() throws Exception {
+ JwtSvid stub = svid();
+ when(client.fetchJwtSvid(anyString())).thenReturn(stub);
+
+
template.request("spiffe:v?workloadApiClient=#client&operation=fetchJwtSvid&audience="
+ CONFIGURED_AUDIENCE,
+ e -> e.getIn().setHeader(SpiffeConstants.AUDIENCE,
OTHER_AUDIENCE));
+
+ // minting a token for a named audience is a parameter, not a check
+ verify(client).fetchJwtSvid(OTHER_AUDIENCE);
+ }
+
+ @Test
+ void theOperationHeaderCannotTurnAValidatorIntoAMinter() throws Exception {
+ Exchange out = template.request(validator(),
+ e -> e.getIn().setHeader(SpiffeConstants.OPERATION,
"fetchJwtSvid"));
+
+ // the endpoint stays a validator: no token is minted, and the missing
token is what fails
+ verify(client, never()).fetchJwtSvid(anyString());
+
assertThat(out.getException()).isInstanceOf(IllegalArgumentException.class);
+ assertThat(out.getException().getMessage()).contains("JWT-SVID token
is required");
+ }
+
+ @Test
+ void theOperationHeaderWorksWhenTheRouteOptsIn() throws Exception {
+ JwtSvid stub = svid();
+ when(client.fetchJwtSvid(anyString())).thenReturn(stub);
+
+ Exchange out = template.request(validator() +
"&allowOperationHeader=true",
+ e -> e.getIn().setHeader(SpiffeConstants.OPERATION,
"fetchJwtSvid"));
+
+ assertThat(out.getException()).isNull();
+ assertThat(out.getMessage().getBody()).isEqualTo("minted-token");
+ verify(client).fetchJwtSvid(CONFIGURED_AUDIENCE);
+ }
+}
diff --git
a/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
b/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
index ea18612da6ec..0e7e42151dba 100644
--- a/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
+++ b/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
@@ -63,6 +63,7 @@ public final class SecurityUtils {
map.put("allowfilepathsource", new SecurityOption(INSECURE_DEV,
"true"));
map.put("allowjavaserializedobject", new
SecurityOption(INSECURE_SERIALIZATION, "true"));
map.put("allowlocalwebhookurls", new SecurityOption(INSECURE_DEV,
"true"));
+ map.put("allowoperationheader", new SecurityOption(INSECURE_DEV,
"true"));
map.put("allowpredicatefrommessage", new SecurityOption(INSECURE_DEV,
"true"));
map.put("allowserializedheaders", new
SecurityOption(INSECURE_SERIALIZATION, "true"));
map.put("allowurlbody", new SecurityOption(INSECURE_DEV, "true"));
diff --git
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SpiffeComponentBuilderFactory.java
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SpiffeComponentBuilderFactory.java
index f5a35a3bd920..adbba0194947 100644
---
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SpiffeComponentBuilderFactory.java
+++
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SpiffeComponentBuilderFactory.java
@@ -171,6 +171,27 @@ public interface SpiffeComponentBuilderFactory {
return this;
}
+
+ /**
+ * Whether the CamelSpiffeOperation header may override the configured
+ * operation. Disabled by default: the operation decides whether this
+ * endpoint validates a token or mints one, so a message that can set
it
+ * can turn a validator into an endpoint that hands out this workload's
+ * own JWT-SVID. Enable it only on routes whose input is trusted.
+ *
+ * The option is a: <code>boolean</code> type.
+ *
+ * Default: false
+ * Group: security
+ *
+ * @param allowOperationHeader the value to set
+ * @return the dsl builder
+ */
+ default SpiffeComponentBuilder allowOperationHeader(boolean
allowOperationHeader) {
+ doSetProperty("allowOperationHeader", allowOperationHeader);
+ return this;
+ }
+
/**
* The address of the SPIFFE Workload API endpoint (for example {code
* unix:///tmp/agent.sock} or {code tcp://127.0.0.1:8082}). When not
@@ -214,6 +235,7 @@ public interface SpiffeComponentBuilderFactory {
case "operation": getOrCreateConfiguration((SpiffeComponent)
component).setOperation((org.apache.camel.component.spiffe.SpiffeOperation)
value); return true;
case "autowiredEnabled": ((SpiffeComponent)
component).setAutowiredEnabled((boolean) value); return true;
case "workloadApiClient":
getOrCreateConfiguration((SpiffeComponent)
component).setWorkloadApiClient((io.spiffe.workloadapi.WorkloadApiClient)
value); return true;
+ case "allowOperationHeader":
getOrCreateConfiguration((SpiffeComponent)
component).setAllowOperationHeader((boolean) value); return true;
case "spiffeSocketPath":
getOrCreateConfiguration((SpiffeComponent)
component).setSpiffeSocketPath((java.lang.String) value); return true;
default: return false;
}
diff --git
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SpiffeEndpointBuilderFactory.java
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SpiffeEndpointBuilderFactory.java
index b24adceb3542..3e5c862c05e7 100644
---
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SpiffeEndpointBuilderFactory.java
+++
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SpiffeEndpointBuilderFactory.java
@@ -96,6 +96,44 @@ public interface SpiffeEndpointBuilderFactory {
doSetProperty("operation", operation);
return this;
}
+ /**
+ * Whether the CamelSpiffeOperation header may override the configured
+ * operation. Disabled by default: the operation decides whether this
+ * endpoint validates a token or mints one, so a message that can set
it
+ * can turn a validator into an endpoint that hands out this workload's
+ * own JWT-SVID. Enable it only on routes whose input is trusted.
+ *
+ * The option is a: <code>boolean</code> type.
+ *
+ * Default: false
+ * Group: security
+ *
+ * @param allowOperationHeader the value to set
+ * @return the dsl builder
+ */
+ default SpiffeEndpointBuilder allowOperationHeader(boolean
allowOperationHeader) {
+ doSetProperty("allowOperationHeader", allowOperationHeader);
+ return this;
+ }
+ /**
+ * Whether the CamelSpiffeOperation header may override the configured
+ * operation. Disabled by default: the operation decides whether this
+ * endpoint validates a token or mints one, so a message that can set
it
+ * can turn a validator into an endpoint that hands out this workload's
+ * own JWT-SVID. Enable it only on routes whose input is trusted.
+ *
+ * The option will be converted to a <code>boolean</code> type.
+ *
+ * Default: false
+ * Group: security
+ *
+ * @param allowOperationHeader the value to set
+ * @return the dsl builder
+ */
+ default SpiffeEndpointBuilder allowOperationHeader(String
allowOperationHeader) {
+ doSetProperty("allowOperationHeader", allowOperationHeader);
+ return this;
+ }
/**
* The address of the SPIFFE Workload API endpoint (for example {code
* unix:///tmp/agent.sock} or {code tcp://127.0.0.1:8082}). When not
@@ -274,7 +312,9 @@ public interface SpiffeEndpointBuilderFactory {
public static final SpiffeHeaderNameBuilder INSTANCE = new
SpiffeHeaderNameBuilder();
/**
- * Overrides the operation to be used by the producer.
+ * Overrides the operation to be used by the producer. Ignored unless
+ * the endpoint sets allowOperationHeader=true, because the operation
+ * decides whether the endpoint validates a token or mints one.
*
* The option is a: {@code
* org.apache.camel.component.spiffe.SpiffeOperation or String} type.
@@ -287,8 +327,10 @@ public interface SpiffeEndpointBuilderFactory {
return "CamelSpiffeOperation";
}
/**
- * The comma-separated audience(s) for the fetchJwtSvid and
- * validateJwtSvid operations.
+ * The comma-separated audience(s) for the fetchJwtSvid operation.
+ * Ignored by validateJwtSvid, which always validates against the
+ * configured audience: there the audience is the check that binds the
+ * token to this workload, not a parameter.
*
* The option is a: {@code String} type.
*