[
https://issues.apache.org/jira/browse/CAMEL-24634?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18112314#comment-18112314
]
Andrea Cosentino commented on CAMEL-24634:
------------------------------------------
Pull request opened: https://github.com/apache/camel/pull/26165
Adds the {{camel-opa}} module (producer + {{OpaSecurityPolicy}}), 25 unit tests
and component documentation. main only — new component, nothing to backport.
_Claude Code on behalf of oscerd_
> camel-opa - new component to evaluate Open Policy Agent (Rego) policies
> against an Exchange
> -------------------------------------------------------------------------------------------
>
> Key: CAMEL-24634
> URL: https://issues.apache.org/jira/browse/CAMEL-24634
> Project: Camel
> Issue Type: New Feature
> Reporter: Andrea Cosentino
> Assignee: Andrea Cosentino
> Priority: Major
>
> h2. Background
> {{camel-spiffe}} (CAMEL-23305 / CAMEL-24571) gave Camel a way to *obtain and
> verify workload identity* - X.509-SVIDs, JWT-SVIDs and SPIFFE-backed mTLS. It
> answers "who is this caller?".
> What Camel still lacks is the next step: "is this caller allowed to do
> this?". There is no policy decision component, so authorization logic ends up
> hand-coded in {{.process()}} / {{.bean()}} blocks - scattered across routes,
> hard to test in isolation, and impossible to change without redeploying the
> integration.
> Camel does ship two authorization integrations - {{camel-shiro}}
> ({{ShiroSecurityPolicy}}) and {{camel-keycloak}} ({{KeycloakSecurityPolicy}})
> - but both are tied to a specific identity provider and to coarse
> role/permission checks. Neither supports externalised, declarative,
> attribute-based policy.
> h2. Proposal
> Add a {{camel-opa}} component that acts as a Policy Enforcement Point (PEP)
> delegating decisions to [Open Policy Agent|https://www.openpolicyagent.org/],
> the CNCF-graduated policy engine whose policies are written in Rego. Camel
> supplies the {{input}} document built from the Exchange; OPA evaluates the
> Rego policy and returns the decision.
> Two complementary usage modes:
> *1. Producer endpoint* - {{opa:<decisionPath>}}
> Builds an OPA {{input}} document from the Exchange (headers, and optionally
> the body), POSTs it to the OPA Data API, and sets the decision back on the
> Exchange as headers:
> * {{CamelOpaDecisionAllow}} (Boolean) - the allow/deny verdict
> * {{CamelOpaDecision}} - the full raw decision document, for policies
> returning more than a boolean (obligations, row filters, deny reasons)
> That makes it directly usable in a {{filter}} or {{choice}} predicate:
> {code:java}
> from("platform-http:/orders")
> .to("opa:authz/orders/allow")
> .filter(header(OpaConstants.DECISION_ALLOW).isEqualTo(true))
> .to("direct:handleOrder");
> {code}
> *2. {{OpaSecurityPolicy implements
> org.apache.camel.spi.AuthorizationPolicy}}* - the interceptor style,
> mirroring {{ShiroSecurityPolicy}} / {{KeycloakSecurityPolicy}}:
> {code:java}
> from("platform-http:/orders")
> .policy(opaPolicy)
> .to("direct:handleOrder");
> {code}
> A deny throws {{CamelAuthorizationException}}, so it composes with the
> existing {{onException}} machinery and never silently continues down the
> route.
> h2. Design notes
> * *Library*: {{com.styra:opa}} (the official OPA Java SDK,
> {{styrainc/opa-java}}) - Apache-2.0 and published on Maven Central, so it
> clears the new-component dependency gate. It wraps OPA's REST Data API, which
> is the standard OPA deployment model (OPA running as a sidecar/daemon next to
> the application).
> * *Input shaping must be opt-in and bounded.* Sending the whole message body
> to the PDP is wrong as a default - bodies can be large, streaming, or carry
> data the PDP has no business seeing. Default to headers plus a configurable
> header allow-list; body inclusion behind an explicit {{includeBody}} option,
> with the stream-caching implications documented.
> * *Fail-closed by default.* If OPA is unreachable, times out, or returns a
> malformed or absent decision, the default must be *deny*. A {{failOpen}}
> option may exist but must default to {{false}}. See CAMEL-24281 and the
> keycloak fail-open finding, where an authorization component that failed open
> was treated as a security defect.
> * *Header hygiene.* The decision headers are Camel-internal. The component
> must not let an external sender pre-set {{CamelOpaDecisionAllow}} and have it
> survive into the route - overwrite unconditionally, and document
> {{removeHeaders("CamelOpa*")}} for untrusted ingress.
> * *In-process evaluation* ({{com.styra.opa:opa-java-wasm}}, Rego compiled to
> WASM) is deliberately out of scope for this first increment - that artifact
> is still at 0.0.6, and the REST/sidecar model covers the mainstream
> deployment. It can follow later.
> h2. Scope of this issue
> First increment, {{main}} only (new component, so no backport):
> * new module {{components/camel-opa}} - component, endpoint, producer,
> configuration, constants
> * {{OpaSecurityPolicy}} + {{OpaSecurityProcessor}} implementing
> {{AuthorizationPolicy}}
> * unit tests covering allow, deny, unreachable PDP (fail-closed), non-boolean
> decision documents, and the security-policy path
> * component documentation ({{src/main/docs/opa-component.adoc}})
--
This message was sent by Atlassian Jira
(v8.20.10#820010)