[ 
https://issues.apache.org/jira/browse/CAMEL-24634?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Andrea Cosentino resolved CAMEL-24634.
--------------------------------------
    Fix Version/s: 4.23.0
       Resolution: Fixed

Fixed on main via https://github.com/apache/camel/pull/26165 (squash commit 
b2741f8f), targeting 4.23.0.

_Claude Code on behalf of Andrea Cosentino_

> 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
>             Fix For: 4.23.0
>
>
> 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)

Reply via email to