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 d76673581bbc CAMEL-26561: camel-opa, camel-spiffe - fix the SPIFFE TLS
doc example, and add YAML for the SPIFFE beans (#29137)
d76673581bbc is described below
commit d76673581bbc94d2641aace39afa3d6f0f13a1fb
Author: Andrea Cosentino <[email protected]>
AuthorDate: Wed Nov 4 10:34:40 2026 +0100
CAMEL-26561: camel-opa, camel-spiffe - fix the SPIFFE TLS doc example, and
add YAML for the SPIFFE beans (#29137)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
.../apache/camel/catalog/docs/opa-component.adoc | 26 ++++++-
.../camel/catalog/docs/spiffe-component.adoc | 91 ++++++++++++++++++++++
.../camel-opa/src/main/docs/opa-component.adoc | 26 ++++++-
.../src/main/docs/spiffe-component.adoc | 91 ++++++++++++++++++++++
4 files changed, 232 insertions(+), 2 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/opa-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/opa-component.adoc
index f87d0b185987..70c72ed5b535 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/opa-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/opa-component.adoc
@@ -532,13 +532,37 @@ That is what lets a workload present a client certificate
to an OPA server requi
X.509-SVID, for example, so the application authenticates to the policy
decision point as itself rather than
relying on network position:
+[tabs]
+====
+Java::
++
[source,java]
------------------------------------------------------------
SpiffeSSLContextParameters spiffe = new SpiffeSSLContextParameters();
-spiffe.setCamelContext(context);
+// the SPIFFE ID the OPA server presents: the handshake fails for any other
+spiffe.setAcceptedSpiffeIds("spiffe://example.org/opa");
context.getRegistry().bind("opaTls", spiffe);
------------------------------------------------------------
+YAML::
++
+[source,yaml]
+----
+- beans:
+ - name: opaTls
+ type: org.apache.camel.component.spiffe.SpiffeSSLContextParameters
+ properties:
+ # the SPIFFE ID the OPA server presents: the handshake fails for any
other
+ acceptedSpiffeIds: spiffe://example.org/opa
+----
+====
+
+`SpiffeSSLContextParameters` must be told which peers to accept: it refuses to
build a context with neither
+`acceptedSpiffeIds` nor `acceptAnySpiffeId`, so a route referencing it would
not start. Prefer naming the OPA server's
+ID, as above, over `acceptAnySpiffeId`, which accepts any server the trust
bundle vouches for. The Workload API is
+found through `spiffeSocketPath`, or the `SPIFFE_ENDPOINT_SOCKET` environment
variable when that is not set; the
+xref:spiffe-component.adoc[SPIFFE] component page describes the rest of its
options.
+
None of this applies in `wasm` mode, where there is no server to reach.
[[failure-handling]]
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 61e453af99e0..52027bb966b7 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
@@ -138,6 +138,10 @@ Because it extends `SSLContextParameters`, the inherited
configuration is still
`CamelContext` shutdown, and the cached context is invalidated at the same
time so a restarted context rebuilds a
fresh source.
+[tabs]
+====
+Java::
++
[source,java]
------------------------------------------------------------
SpiffeSSLContextParameters ssl = new SpiffeSSLContextParameters();
@@ -149,6 +153,27 @@ from("direct:start")
.to("https://backend.example.org/api?sslContextParameters=#spiffeSsl");
------------------------------------------------------------
+YAML::
++
+[source,yaml]
+----
+- beans:
+ - name: spiffeSsl
+ type: org.apache.camel.component.spiffe.SpiffeSSLContextParameters
+ properties:
+ # spiffeSocketPath: unix:///tmp/spire-agent/public/api.sock # or
SPIFFE_ENDPOINT_SOCKET
+ acceptedSpiffeIds: spiffe://example.org/backend
+- route:
+ from:
+ uri: direct:start
+ steps:
+ - to:
+ uri: https://backend.example.org/api
+ parameters:
+ sslContextParameters: "#spiffeSsl"
+----
+====
+
== Authorizing a route on the peer SPIFFE ID (SpiffeSecurityPolicy)
`SpiffeSSLContextParameters` decides *which peers may connect*;
`org.apache.camel.component.spiffe.SpiffeSecurityPolicy`
@@ -156,6 +181,10 @@ decides *what a given peer may reach*. It is an
`AuthorizationPolicy` - the SPIF
`KeycloakSecurityPolicy` and `OpaSecurityPolicy` - that wraps a route segment
and authorizes it on the caller's
verified SPIFFE ID:
+[tabs]
+====
+Java::
++
[source,java]
------------------------------------------------------------
// the server must REQUIRE a client certificate, or the policy has no verified
peer to authorize
@@ -174,6 +203,36 @@
from("netty-http:https://0.0.0.0:8443?sslContextParameters=#spiffeSsl")
.to("direct:handleOrder");
------------------------------------------------------------
+YAML::
++
+[source,yaml]
+----
+- beans:
+ - name: spiffeSsl
+ type: org.apache.camel.component.spiffe.SpiffeSSLContextParameters
+ properties:
+ acceptedSpiffeIds: spiffe://example.org/frontend
+ # the server must REQUIRE a client certificate, or the policy has no
verified peer to authorize
+ serverParameters:
+ clientAuthentication: REQUIRE
+ - name: spiffePolicy
+ type: org.apache.camel.component.spiffe.SpiffeSecurityPolicy
+ properties:
+ acceptedSpiffeIds: spiffe://example.org/frontend
+- route:
+ from:
+ uri: netty-http:https://0.0.0.0:8443
+ parameters:
+ sslContextParameters: "#spiffeSsl"
+ steps:
+ - policy:
+ ref: spiffePolicy
+ steps:
+ - to:
+ uri: direct:handleOrder
+----
+====
+
[IMPORTANT]
====
A few things about the server side decide whether, and for which peers, this
policy can work.
@@ -213,6 +272,10 @@ this") rather than duplicate it. On a successful
authorization the verified SPIF
`CamelSpiffePeerId` exchange property, so an OPA policy downstream can forward
it to a Rego rule through its
`includeProperties` option:
+[tabs]
+====
+Java::
++
[source,java]
------------------------------------------------------------
from("netty-http:https://0.0.0.0:8443?sslContextParameters=#spiffeSsl")
@@ -221,6 +284,34 @@
from("netty-http:https://0.0.0.0:8443?sslContextParameters=#spiffeSsl")
.to("direct:handleOrder");
------------------------------------------------------------
+YAML::
++
+[source,yaml]
+----
+- beans:
+ - name: opaPolicy
+ type: org.apache.camel.component.opa.security.OpaSecurityPolicy
+ properties:
+ policyPath: authz/orders/allow
+ includeProperties: CamelSpiffePeerId
+- route:
+ from:
+ uri: netty-http:https://0.0.0.0:8443
+ parameters:
+ sslContextParameters: "#spiffeSsl"
+ steps:
+ # authenticates the peer, and sets the CamelSpiffePeerId exchange
property
+ - policy:
+ ref: spiffePolicy
+ steps:
+ - policy:
+ ref: opaPolicy
+ steps:
+ - to:
+ uri: direct:handleOrder
+----
+====
+
For a TLS consumer that exposes the `SSLSession` under a different header
name, set `sslSessionHeader` accordingly. The
identity is always read from the verified `SSLSession`, never from a
certificate object placed on a message header -
nothing would prove the TLS layer had verified such a certificate.
diff --git a/components/camel-opa/src/main/docs/opa-component.adoc
b/components/camel-opa/src/main/docs/opa-component.adoc
index f87d0b185987..70c72ed5b535 100644
--- a/components/camel-opa/src/main/docs/opa-component.adoc
+++ b/components/camel-opa/src/main/docs/opa-component.adoc
@@ -532,13 +532,37 @@ That is what lets a workload present a client certificate
to an OPA server requi
X.509-SVID, for example, so the application authenticates to the policy
decision point as itself rather than
relying on network position:
+[tabs]
+====
+Java::
++
[source,java]
------------------------------------------------------------
SpiffeSSLContextParameters spiffe = new SpiffeSSLContextParameters();
-spiffe.setCamelContext(context);
+// the SPIFFE ID the OPA server presents: the handshake fails for any other
+spiffe.setAcceptedSpiffeIds("spiffe://example.org/opa");
context.getRegistry().bind("opaTls", spiffe);
------------------------------------------------------------
+YAML::
++
+[source,yaml]
+----
+- beans:
+ - name: opaTls
+ type: org.apache.camel.component.spiffe.SpiffeSSLContextParameters
+ properties:
+ # the SPIFFE ID the OPA server presents: the handshake fails for any
other
+ acceptedSpiffeIds: spiffe://example.org/opa
+----
+====
+
+`SpiffeSSLContextParameters` must be told which peers to accept: it refuses to
build a context with neither
+`acceptedSpiffeIds` nor `acceptAnySpiffeId`, so a route referencing it would
not start. Prefer naming the OPA server's
+ID, as above, over `acceptAnySpiffeId`, which accepts any server the trust
bundle vouches for. The Workload API is
+found through `spiffeSocketPath`, or the `SPIFFE_ENDPOINT_SOCKET` environment
variable when that is not set; the
+xref:spiffe-component.adoc[SPIFFE] component page describes the rest of its
options.
+
None of this applies in `wasm` mode, where there is no server to reach.
[[failure-handling]]
diff --git a/components/camel-spiffe/src/main/docs/spiffe-component.adoc
b/components/camel-spiffe/src/main/docs/spiffe-component.adoc
index 61e453af99e0..52027bb966b7 100644
--- a/components/camel-spiffe/src/main/docs/spiffe-component.adoc
+++ b/components/camel-spiffe/src/main/docs/spiffe-component.adoc
@@ -138,6 +138,10 @@ Because it extends `SSLContextParameters`, the inherited
configuration is still
`CamelContext` shutdown, and the cached context is invalidated at the same
time so a restarted context rebuilds a
fresh source.
+[tabs]
+====
+Java::
++
[source,java]
------------------------------------------------------------
SpiffeSSLContextParameters ssl = new SpiffeSSLContextParameters();
@@ -149,6 +153,27 @@ from("direct:start")
.to("https://backend.example.org/api?sslContextParameters=#spiffeSsl");
------------------------------------------------------------
+YAML::
++
+[source,yaml]
+----
+- beans:
+ - name: spiffeSsl
+ type: org.apache.camel.component.spiffe.SpiffeSSLContextParameters
+ properties:
+ # spiffeSocketPath: unix:///tmp/spire-agent/public/api.sock # or
SPIFFE_ENDPOINT_SOCKET
+ acceptedSpiffeIds: spiffe://example.org/backend
+- route:
+ from:
+ uri: direct:start
+ steps:
+ - to:
+ uri: https://backend.example.org/api
+ parameters:
+ sslContextParameters: "#spiffeSsl"
+----
+====
+
== Authorizing a route on the peer SPIFFE ID (SpiffeSecurityPolicy)
`SpiffeSSLContextParameters` decides *which peers may connect*;
`org.apache.camel.component.spiffe.SpiffeSecurityPolicy`
@@ -156,6 +181,10 @@ decides *what a given peer may reach*. It is an
`AuthorizationPolicy` - the SPIF
`KeycloakSecurityPolicy` and `OpaSecurityPolicy` - that wraps a route segment
and authorizes it on the caller's
verified SPIFFE ID:
+[tabs]
+====
+Java::
++
[source,java]
------------------------------------------------------------
// the server must REQUIRE a client certificate, or the policy has no verified
peer to authorize
@@ -174,6 +203,36 @@
from("netty-http:https://0.0.0.0:8443?sslContextParameters=#spiffeSsl")
.to("direct:handleOrder");
------------------------------------------------------------
+YAML::
++
+[source,yaml]
+----
+- beans:
+ - name: spiffeSsl
+ type: org.apache.camel.component.spiffe.SpiffeSSLContextParameters
+ properties:
+ acceptedSpiffeIds: spiffe://example.org/frontend
+ # the server must REQUIRE a client certificate, or the policy has no
verified peer to authorize
+ serverParameters:
+ clientAuthentication: REQUIRE
+ - name: spiffePolicy
+ type: org.apache.camel.component.spiffe.SpiffeSecurityPolicy
+ properties:
+ acceptedSpiffeIds: spiffe://example.org/frontend
+- route:
+ from:
+ uri: netty-http:https://0.0.0.0:8443
+ parameters:
+ sslContextParameters: "#spiffeSsl"
+ steps:
+ - policy:
+ ref: spiffePolicy
+ steps:
+ - to:
+ uri: direct:handleOrder
+----
+====
+
[IMPORTANT]
====
A few things about the server side decide whether, and for which peers, this
policy can work.
@@ -213,6 +272,10 @@ this") rather than duplicate it. On a successful
authorization the verified SPIF
`CamelSpiffePeerId` exchange property, so an OPA policy downstream can forward
it to a Rego rule through its
`includeProperties` option:
+[tabs]
+====
+Java::
++
[source,java]
------------------------------------------------------------
from("netty-http:https://0.0.0.0:8443?sslContextParameters=#spiffeSsl")
@@ -221,6 +284,34 @@
from("netty-http:https://0.0.0.0:8443?sslContextParameters=#spiffeSsl")
.to("direct:handleOrder");
------------------------------------------------------------
+YAML::
++
+[source,yaml]
+----
+- beans:
+ - name: opaPolicy
+ type: org.apache.camel.component.opa.security.OpaSecurityPolicy
+ properties:
+ policyPath: authz/orders/allow
+ includeProperties: CamelSpiffePeerId
+- route:
+ from:
+ uri: netty-http:https://0.0.0.0:8443
+ parameters:
+ sslContextParameters: "#spiffeSsl"
+ steps:
+ # authenticates the peer, and sets the CamelSpiffePeerId exchange
property
+ - policy:
+ ref: spiffePolicy
+ steps:
+ - policy:
+ ref: opaPolicy
+ steps:
+ - to:
+ uri: direct:handleOrder
+----
+====
+
For a TLS consumer that exposes the `SSLSession` under a different header
name, set `sslSessionHeader` accordingly. The
identity is always read from the verified `SSLSession`, never from a
certificate object placed on a message header -
nothing would prove the TLS layer had verified such a certificate.