Andrea Cosentino created CAMEL-24634:
----------------------------------------
Summary: 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
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)