This is an automated email from the ASF dual-hosted git repository.

oscerd 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 0076168a5cd4 CAMEL-24784/CAMEL-24785: camel-opa - bound the REST 
decision call, reuse one HTTP client, and support sslContextParameters (#26524)
0076168a5cd4 is described below

commit 0076168a5cd42719dc4f1f873c9286cda12cd447
Author: Andrea Cosentino <[email protected]>
AuthorDate: Thu Sep 17 10:05:37 2026 +0200

    CAMEL-24784/CAMEL-24785: camel-opa - bound the REST decision call, reuse 
one HTTP client, and support sslContextParameters (#26524)
    
    camel-opa: bound the REST decision call with a request timeout 
(CAMEL-24784), reuse a single HTTP client
    across invocations instead of creating one per request, and support 
sslContextParameters for TLS to the OPA
    server (CAMEL-24785).
    
    Co-authored-by: Claude Opus 4.8 <[email protected]>
---
 .../org/apache/camel/catalog/components/opa.json   |  27 ++-
 .../apache/camel/catalog/docs/opa-component.adoc   |  37 ++++
 .../component/opa/OpaComponentConfigurer.java      |  24 +++
 .../camel/component/opa/OpaEndpointConfigurer.java |  18 ++
 .../camel/component/opa/OpaEndpointUriFactory.java |   5 +-
 .../org/apache/camel/component/opa/opa.json        |  27 ++-
 .../camel-opa/src/main/docs/opa-component.adoc     |  37 ++++
 .../apache/camel/component/opa/OpaComponent.java   |  19 +-
 .../camel/component/opa/OpaConfiguration.java      |  48 +++++
 .../apache/camel/component/opa/OpaEndpoint.java    |  48 ++++-
 .../apache/camel/component/opa/OpaHealthProbe.java |  28 ++-
 .../apache/camel/component/opa/OpaHttpClient.java  |  90 ++++++++
 .../apache/camel/component/opa/OpaProducer.java    |   2 +-
 .../component/opa/OpaProducerHealthCheck.java      |   9 +-
 .../camel/component/opa/OpaRestEvaluator.java      |  43 +++-
 .../component/opa/security/OpaSecurityPolicy.java  |  89 +++++++-
 .../opa/security/OpaSecurityPolicyHealthCheck.java |   9 +-
 .../component/opa/OpaProducerHealthCheckTest.java  |   8 +-
 .../camel/component/opa/OpaRestTransportTest.java  | 234 +++++++++++++++++++++
 .../security/OpaSecurityPolicyHealthCheckTest.java |   4 +-
 .../src/test/resources/README-tls-fixture.md       |  16 ++
 .../camel-opa/src/test/resources/opa-server.p12    | Bin 0 -> 2674 bytes
 .../component/dsl/OpaComponentBuilderFactory.java  |  82 ++++++++
 .../endpoint/dsl/OpaEndpointBuilderFactory.java    | 112 ++++++++++
 24 files changed, 963 insertions(+), 53 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/opa.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/opa.json
index 11cd8ccebcbc..27178ee61b22 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/opa.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/opa.json
@@ -36,12 +36,16 @@
     "serverUrl": { "index": 9, "kind": "property", "displayName": "Server 
Url", "group": "producer", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "http:\/\/localhost:8181", 
"configurationClass": "org.apache.camel.component.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "The base URL of the OPA 
server, without the {code \/v1\/data} suffix. The defaul [...]
     "autowiredEnabled": { "index": 10, "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  [...]
     "borrowTimeout": { "index": 11, "kind": "property", "displayName": "Borrow 
Timeout", "group": "advanced", "label": "advanced", "required": false, "type": 
"duration", "javaType": "long", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "30000", "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "How long an exchange waits for a free 
WebAssembly policy instance in wasm mode before the e [...]
-    "opaClient": { "index": 12, "kind": "property", "displayName": "Opa 
Client", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "com.styra.opa.OPAClient", "deprecated": false, 
"deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": "org.apache.camel.component.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "An existing OPAClient to 
use. When set, serverUrl and bearerToken are ignored." },
-    "poolSize": { "index": 13, "kind": "property", "displayName": "Pool Size", 
"group": "advanced", "label": "advanced", "required": false, "type": "integer", 
"javaType": "int", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 8, "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "How many WebAssembly policy instances to pool 
in wasm mode. An instance carries mutable state and is not thre [...]
-    "healthCheckConsumerEnabled": { "index": 14, "kind": "property", 
"displayName": "Health Check Consumer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all consumer based health checks 
from this component" },
-    "healthCheckProducerEnabled": { "index": 15, "kind": "property", 
"displayName": "Health Check Producer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all producer based health checks 
from this component. Notice: Camel has by default disabled all producer based 
health-checks. You can turn on produce [...]
-    "bearerToken": { "index": 16, "kind": "property", "displayName": "Bearer 
Token", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "Bearer token sent to the OPA server in the 
Authorization header, for an OPA instance that [...]
-    "failOpen": { "index": 17, "kind": "property", "displayName": "Fail Open", 
"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.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "Whether to allow the exchange to proceed when 
the policy cannot be evalua [...]
+    "connectionTimeout": { "index": 12, "kind": "property", "displayName": 
"Connection Timeout", "group": "advanced", "label": "advanced", "required": 
false, "type": "duration", "javaType": "long", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": "10000", 
"configurationClass": "org.apache.camel.component.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "How long to wait for the 
connection to the OPA server to be established, in rest mo [...]
+    "opaClient": { "index": 13, "kind": "property", "displayName": "Opa 
Client", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "com.styra.opa.OPAClient", "deprecated": false, 
"deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": "org.apache.camel.component.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "An existing OPAClient to 
use. When set, serverUrl and bearerToken are ignored." },
+    "poolSize": { "index": 14, "kind": "property", "displayName": "Pool Size", 
"group": "advanced", "label": "advanced", "required": false, "type": "integer", 
"javaType": "int", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 8, "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "How many WebAssembly policy instances to pool 
in wasm mode. An instance carries mutable state and is not thre [...]
+    "requestTimeout": { "index": 15, "kind": "property", "displayName": 
"Request Timeout", "group": "advanced", "label": "advanced", "required": false, 
"type": "duration", "javaType": "long", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": "30000", "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "How long to wait for the decision once 
connected, in rest mode. A request that times out  [...]
+    "healthCheckConsumerEnabled": { "index": 16, "kind": "property", 
"displayName": "Health Check Consumer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all consumer based health checks 
from this component" },
+    "healthCheckProducerEnabled": { "index": 17, "kind": "property", 
"displayName": "Health Check Producer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all producer based health checks 
from this component. Notice: Camel has by default disabled all producer based 
health-checks. You can turn on produce [...]
+    "bearerToken": { "index": 18, "kind": "property", "displayName": "Bearer 
Token", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "Bearer token sent to the OPA server in the 
Authorization header, for an OPA instance that [...]
+    "failOpen": { "index": 19, "kind": "property", "displayName": "Fail Open", 
"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.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "Whether to allow the exchange to proceed when 
the policy cannot be evalua [...]
+    "sslContextParameters": { "index": 20, "kind": "property", "displayName": 
"Ssl Context Parameters", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "TLS configuration for the connection to the 
OPA server in [...]
+    "useGlobalSslContextParameters": { "index": 21, "kind": "property", 
"displayName": "Use Global Ssl Context Parameters", "group": "security", 
"label": "security", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Enable usage of global SSL context 
parameters." }
   },
   "headers": {
     "CamelOpaDecisionAllow": { "index": 0, "kind": "header", "displayName": 
"", "group": "producer", "label": "producer", "required": false, "javaType": 
"Boolean", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The allow\/deny verdict of the policy 
evaluation. Always overwritten by the component, so a value set by an inbound 
message never survives into the route.", "constantName": 
"org.apache.camel.component.opa.OpaConstants#DECISION_ALLOW" },
@@ -60,9 +64,12 @@
     "serverUrl": { "index": 8, "kind": "parameter", "displayName": "Server 
Url", "group": "producer", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "http:\/\/localhost:8181", 
"configurationClass": "org.apache.camel.component.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "The base URL of the OPA 
server, without the {code \/v1\/data} suffix. The defau [...]
     "lazyStartProducer": { "index": 9, "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 [...]
     "borrowTimeout": { "index": 10, "kind": "parameter", "displayName": 
"Borrow Timeout", "group": "advanced", "label": "advanced", "required": false, 
"type": "duration", "javaType": "long", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": "30000", "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "How long an exchange waits for a free 
WebAssembly policy instance in wasm mode before the  [...]
-    "opaClient": { "index": 11, "kind": "parameter", "displayName": "Opa 
Client", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "com.styra.opa.OPAClient", "deprecated": false, 
"deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": "org.apache.camel.component.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "An existing OPAClient to 
use. When set, serverUrl and bearerToken are ignored." },
-    "poolSize": { "index": 12, "kind": "parameter", "displayName": "Pool 
Size", "group": "advanced", "label": "advanced", "required": false, "type": 
"integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": 8, "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "How many WebAssembly policy instances to pool 
in wasm mode. An instance carries mutable state and is not thr [...]
-    "bearerToken": { "index": 13, "kind": "parameter", "displayName": "Bearer 
Token", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "Bearer token sent to the OPA server in the 
Authorization header, for an OPA instance tha [...]
-    "failOpen": { "index": 14, "kind": "parameter", "displayName": "Fail 
Open", "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.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "Whether to allow the 
exchange to proceed when the policy cannot be evalu [...]
+    "connectionTimeout": { "index": 11, "kind": "parameter", "displayName": 
"Connection Timeout", "group": "advanced", "label": "advanced", "required": 
false, "type": "duration", "javaType": "long", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": "10000", 
"configurationClass": "org.apache.camel.component.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "How long to wait for the 
connection to the OPA server to be established, in rest m [...]
+    "opaClient": { "index": 12, "kind": "parameter", "displayName": "Opa 
Client", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "com.styra.opa.OPAClient", "deprecated": false, 
"deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": "org.apache.camel.component.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "An existing OPAClient to 
use. When set, serverUrl and bearerToken are ignored." },
+    "poolSize": { "index": 13, "kind": "parameter", "displayName": "Pool 
Size", "group": "advanced", "label": "advanced", "required": false, "type": 
"integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": 8, "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "How many WebAssembly policy instances to pool 
in wasm mode. An instance carries mutable state and is not thr [...]
+    "requestTimeout": { "index": 14, "kind": "parameter", "displayName": 
"Request Timeout", "group": "advanced", "label": "advanced", "required": false, 
"type": "duration", "javaType": "long", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": "30000", "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "How long to wait for the decision once 
connected, in rest mode. A request that times out [...]
+    "bearerToken": { "index": 15, "kind": "parameter", "displayName": "Bearer 
Token", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "Bearer token sent to the OPA server in the 
Authorization header, for an OPA instance tha [...]
+    "failOpen": { "index": 16, "kind": "parameter", "displayName": "Fail 
Open", "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.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "Whether to allow the 
exchange to proceed when the policy cannot be evalu [...]
+    "sslContextParameters": { "index": 17, "kind": "parameter", "displayName": 
"Ssl Context Parameters", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "TLS configuration for the connection to the 
OPA server i [...]
   }
 }
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 4df6be0ac77e..0a373925f776 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
@@ -278,6 +278,43 @@ exchanges evaluate at once, and `borrowTimeout` when a 
single evaluation is legi
 run long enough to matter is usually better served by `evaluationMode=rest`, 
where the decision point is a
 separate process that a timeout can abandon.
 
+== Connecting to the server
+
+In `rest` mode the component talks to OPA over HTTP, and both waits are 
bounded:
+
+* `connectionTimeout` (default 10s) — establishing the connection.
+* `requestTimeout` (default 30s) — waiting for the decision once connected.
+
+Neither is optional in practice. A refused connection fails immediately, but a 
server that *accepts* and then
+stops answering — wedged, mid-restart, or behind a load balancer holding the 
socket — would otherwise park the
+routing thread indefinitely. For a component that fails closed that is worse 
than a denial: it never reaches the
+point of deciding. A timeout is treated as a failure to reach a verdict, so it 
denies, or proceeds if `failOpen`
+is set, like any other such failure.
+
+TLS is configured with `sslContextParameters`, the usual 
xref:manual::camel-configuration-utilities.adoc[JSSE
+utility]:
+
+[source,java]
+------------------------------------------------------------
+from("platform-http:/orders")
+    
.to("opa:authz/orders/allow?serverUrl=https://opa:8181&sslContextParameters=#opaTls";)
+------------------------------------------------------------
+
+Set `useGlobalSslContextParameters=true` on the component to pick up the 
context-wide configuration instead.
+
+That is what lets a workload present a client certificate to an OPA server 
requiring mutual TLS — a SPIFFE
+X.509-SVID, for example, so the application authenticates to the policy 
decision point as itself rather than
+relying on network position:
+
+[source,java]
+------------------------------------------------------------
+SpiffeSSLContextParameters spiffe = new SpiffeSSLContextParameters();
+spiffe.setCamelContext(context);
+context.getRegistry().bind("opaTls", spiffe);
+------------------------------------------------------------
+
+None of this applies in `wasm` mode, where there is no server to reach.
+
 == Failure handling
 
 The component fails closed. If the policy cannot be evaluated at all — the OPA 
server is unreachable, times out,
diff --git 
a/components/camel-opa/src/generated/java/org/apache/camel/component/opa/OpaComponentConfigurer.java
 
b/components/camel-opa/src/generated/java/org/apache/camel/component/opa/OpaComponentConfigurer.java
index e726ff7dd3f2..abaee2681400 100644
--- 
a/components/camel-opa/src/generated/java/org/apache/camel/component/opa/OpaComponentConfigurer.java
+++ 
b/components/camel-opa/src/generated/java/org/apache/camel/component/opa/OpaComponentConfigurer.java
@@ -39,6 +39,8 @@ public class OpaComponentConfigurer extends 
PropertyConfigurerSupport implements
         case "borrowtimeout":
         case "borrowTimeout": 
getOrCreateConfiguration(target).setBorrowTimeout(property(camelContext, 
java.time.Duration.class, value).toMillis()); return true;
         case "configuration": target.setConfiguration(property(camelContext, 
org.apache.camel.component.opa.OpaConfiguration.class, value)); return true;
+        case "connectiontimeout":
+        case "connectionTimeout": 
getOrCreateConfiguration(target).setConnectionTimeout(property(camelContext, 
java.time.Duration.class, value).toMillis()); return true;
         case "entrypoint": 
getOrCreateConfiguration(target).setEntrypoint(property(camelContext, 
java.lang.String.class, value)); return true;
         case "evaluationmode":
         case "evaluationMode": 
getOrCreateConfiguration(target).setEvaluationMode(property(camelContext, 
java.lang.String.class, value)); return true;
@@ -62,8 +64,14 @@ public class OpaComponentConfigurer extends 
PropertyConfigurerSupport implements
         case "policyBundle": 
getOrCreateConfiguration(target).setPolicyBundle(property(camelContext, 
java.lang.String.class, value)); return true;
         case "poolsize":
         case "poolSize": 
getOrCreateConfiguration(target).setPoolSize(property(camelContext, int.class, 
value)); return true;
+        case "requesttimeout":
+        case "requestTimeout": 
getOrCreateConfiguration(target).setRequestTimeout(property(camelContext, 
java.time.Duration.class, value).toMillis()); return true;
         case "serverurl":
         case "serverUrl": 
getOrCreateConfiguration(target).setServerUrl(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "sslcontextparameters":
+        case "sslContextParameters": 
getOrCreateConfiguration(target).setSslContextParameters(property(camelContext, 
org.apache.camel.support.jsse.SSLContextParameters.class, value)); return true;
+        case "useglobalsslcontextparameters":
+        case "useGlobalSslContextParameters": 
target.setUseGlobalSslContextParameters(property(camelContext, boolean.class, 
value)); return true;
         default: return false;
         }
     }
@@ -85,6 +93,8 @@ public class OpaComponentConfigurer extends 
PropertyConfigurerSupport implements
         case "borrowtimeout":
         case "borrowTimeout": return long.class;
         case "configuration": return 
org.apache.camel.component.opa.OpaConfiguration.class;
+        case "connectiontimeout":
+        case "connectionTimeout": return long.class;
         case "entrypoint": return java.lang.String.class;
         case "evaluationmode":
         case "evaluationMode": return java.lang.String.class;
@@ -108,8 +118,14 @@ public class OpaComponentConfigurer extends 
PropertyConfigurerSupport implements
         case "policyBundle": return java.lang.String.class;
         case "poolsize":
         case "poolSize": return int.class;
+        case "requesttimeout":
+        case "requestTimeout": return long.class;
         case "serverurl":
         case "serverUrl": return java.lang.String.class;
+        case "sslcontextparameters":
+        case "sslContextParameters": return 
org.apache.camel.support.jsse.SSLContextParameters.class;
+        case "useglobalsslcontextparameters":
+        case "useGlobalSslContextParameters": return boolean.class;
         default: return null;
         }
     }
@@ -127,6 +143,8 @@ public class OpaComponentConfigurer extends 
PropertyConfigurerSupport implements
         case "borrowtimeout":
         case "borrowTimeout": return 
getOrCreateConfiguration(target).getBorrowTimeout();
         case "configuration": return target.getConfiguration();
+        case "connectiontimeout":
+        case "connectionTimeout": return 
getOrCreateConfiguration(target).getConnectionTimeout();
         case "entrypoint": return 
getOrCreateConfiguration(target).getEntrypoint();
         case "evaluationmode":
         case "evaluationMode": return 
getOrCreateConfiguration(target).getEvaluationMode();
@@ -150,8 +168,14 @@ public class OpaComponentConfigurer extends 
PropertyConfigurerSupport implements
         case "policyBundle": return 
getOrCreateConfiguration(target).getPolicyBundle();
         case "poolsize":
         case "poolSize": return getOrCreateConfiguration(target).getPoolSize();
+        case "requesttimeout":
+        case "requestTimeout": return 
getOrCreateConfiguration(target).getRequestTimeout();
         case "serverurl":
         case "serverUrl": return 
getOrCreateConfiguration(target).getServerUrl();
+        case "sslcontextparameters":
+        case "sslContextParameters": return 
getOrCreateConfiguration(target).getSslContextParameters();
+        case "useglobalsslcontextparameters":
+        case "useGlobalSslContextParameters": return 
target.isUseGlobalSslContextParameters();
         default: return null;
         }
     }
diff --git 
a/components/camel-opa/src/generated/java/org/apache/camel/component/opa/OpaEndpointConfigurer.java
 
b/components/camel-opa/src/generated/java/org/apache/camel/component/opa/OpaEndpointConfigurer.java
index 31c2e21a0ad7..469fa36c4faa 100644
--- 
a/components/camel-opa/src/generated/java/org/apache/camel/component/opa/OpaEndpointConfigurer.java
+++ 
b/components/camel-opa/src/generated/java/org/apache/camel/component/opa/OpaEndpointConfigurer.java
@@ -29,6 +29,8 @@ public class OpaEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "bearerToken": 
target.getConfiguration().setBearerToken(property(camelContext, 
java.lang.String.class, value)); return true;
         case "borrowtimeout":
         case "borrowTimeout": 
target.getConfiguration().setBorrowTimeout(property(camelContext, 
java.time.Duration.class, value).toMillis()); return true;
+        case "connectiontimeout":
+        case "connectionTimeout": 
target.getConfiguration().setConnectionTimeout(property(camelContext, 
java.time.Duration.class, value).toMillis()); return true;
         case "entrypoint": 
target.getConfiguration().setEntrypoint(property(camelContext, 
java.lang.String.class, value)); return true;
         case "evaluationmode":
         case "evaluationMode": 
target.getConfiguration().setEvaluationMode(property(camelContext, 
java.lang.String.class, value)); return true;
@@ -48,8 +50,12 @@ public class OpaEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "policyBundle": 
target.getConfiguration().setPolicyBundle(property(camelContext, 
java.lang.String.class, value)); return true;
         case "poolsize":
         case "poolSize": 
target.getConfiguration().setPoolSize(property(camelContext, int.class, 
value)); return true;
+        case "requesttimeout":
+        case "requestTimeout": 
target.getConfiguration().setRequestTimeout(property(camelContext, 
java.time.Duration.class, value).toMillis()); return true;
         case "serverurl":
         case "serverUrl": 
target.getConfiguration().setServerUrl(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "sslcontextparameters":
+        case "sslContextParameters": 
target.getConfiguration().setSslContextParameters(property(camelContext, 
org.apache.camel.support.jsse.SSLContextParameters.class, value)); return true;
         default: return false;
         }
     }
@@ -68,6 +74,8 @@ public class OpaEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "bearerToken": return java.lang.String.class;
         case "borrowtimeout":
         case "borrowTimeout": return long.class;
+        case "connectiontimeout":
+        case "connectionTimeout": return long.class;
         case "entrypoint": return java.lang.String.class;
         case "evaluationmode":
         case "evaluationMode": return java.lang.String.class;
@@ -87,8 +95,12 @@ public class OpaEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "policyBundle": return java.lang.String.class;
         case "poolsize":
         case "poolSize": return int.class;
+        case "requesttimeout":
+        case "requestTimeout": return long.class;
         case "serverurl":
         case "serverUrl": return java.lang.String.class;
+        case "sslcontextparameters":
+        case "sslContextParameters": return 
org.apache.camel.support.jsse.SSLContextParameters.class;
         default: return null;
         }
     }
@@ -103,6 +115,8 @@ public class OpaEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "bearerToken": return target.getConfiguration().getBearerToken();
         case "borrowtimeout":
         case "borrowTimeout": return 
target.getConfiguration().getBorrowTimeout();
+        case "connectiontimeout":
+        case "connectionTimeout": return 
target.getConfiguration().getConnectionTimeout();
         case "entrypoint": return target.getConfiguration().getEntrypoint();
         case "evaluationmode":
         case "evaluationMode": return 
target.getConfiguration().getEvaluationMode();
@@ -122,8 +136,12 @@ public class OpaEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "policyBundle": return 
target.getConfiguration().getPolicyBundle();
         case "poolsize":
         case "poolSize": return target.getConfiguration().getPoolSize();
+        case "requesttimeout":
+        case "requestTimeout": return 
target.getConfiguration().getRequestTimeout();
         case "serverurl":
         case "serverUrl": return target.getConfiguration().getServerUrl();
+        case "sslcontextparameters":
+        case "sslContextParameters": return 
target.getConfiguration().getSslContextParameters();
         default: return null;
         }
     }
diff --git 
a/components/camel-opa/src/generated/java/org/apache/camel/component/opa/OpaEndpointUriFactory.java
 
b/components/camel-opa/src/generated/java/org/apache/camel/component/opa/OpaEndpointUriFactory.java
index 5848d96093a9..b18d621d92b8 100644
--- 
a/components/camel-opa/src/generated/java/org/apache/camel/component/opa/OpaEndpointUriFactory.java
+++ 
b/components/camel-opa/src/generated/java/org/apache/camel/component/opa/OpaEndpointUriFactory.java
@@ -24,10 +24,11 @@ public class OpaEndpointUriFactory extends 
org.apache.camel.support.component.En
     private static final Set<String> ENDPOINT_IDENTITY_PROPERTY_NAMES;
     private static final Map<String, String> MULTI_VALUE_PREFIXES;
     static {
-        Set<String> props = new HashSet<>(15);
+        Set<String> props = new HashSet<>(18);
         props.add("allowKey");
         props.add("bearerToken");
         props.add("borrowTimeout");
+        props.add("connectionTimeout");
         props.add("entrypoint");
         props.add("evaluationMode");
         props.add("failOpen");
@@ -39,7 +40,9 @@ public class OpaEndpointUriFactory extends 
org.apache.camel.support.component.En
         props.add("policyBundle");
         props.add("policyPath");
         props.add("poolSize");
+        props.add("requestTimeout");
         props.add("serverUrl");
+        props.add("sslContextParameters");
         PROPERTY_NAMES = Collections.unmodifiableSet(props);
         Set<String> secretProps = new HashSet<>(1);
         secretProps.add("bearerToken");
diff --git 
a/components/camel-opa/src/generated/resources/META-INF/org/apache/camel/component/opa/opa.json
 
b/components/camel-opa/src/generated/resources/META-INF/org/apache/camel/component/opa/opa.json
index 11cd8ccebcbc..27178ee61b22 100644
--- 
a/components/camel-opa/src/generated/resources/META-INF/org/apache/camel/component/opa/opa.json
+++ 
b/components/camel-opa/src/generated/resources/META-INF/org/apache/camel/component/opa/opa.json
@@ -36,12 +36,16 @@
     "serverUrl": { "index": 9, "kind": "property", "displayName": "Server 
Url", "group": "producer", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "http:\/\/localhost:8181", 
"configurationClass": "org.apache.camel.component.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "The base URL of the OPA 
server, without the {code \/v1\/data} suffix. The defaul [...]
     "autowiredEnabled": { "index": 10, "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  [...]
     "borrowTimeout": { "index": 11, "kind": "property", "displayName": "Borrow 
Timeout", "group": "advanced", "label": "advanced", "required": false, "type": 
"duration", "javaType": "long", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "30000", "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "How long an exchange waits for a free 
WebAssembly policy instance in wasm mode before the e [...]
-    "opaClient": { "index": 12, "kind": "property", "displayName": "Opa 
Client", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "com.styra.opa.OPAClient", "deprecated": false, 
"deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": "org.apache.camel.component.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "An existing OPAClient to 
use. When set, serverUrl and bearerToken are ignored." },
-    "poolSize": { "index": 13, "kind": "property", "displayName": "Pool Size", 
"group": "advanced", "label": "advanced", "required": false, "type": "integer", 
"javaType": "int", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 8, "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "How many WebAssembly policy instances to pool 
in wasm mode. An instance carries mutable state and is not thre [...]
-    "healthCheckConsumerEnabled": { "index": 14, "kind": "property", 
"displayName": "Health Check Consumer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all consumer based health checks 
from this component" },
-    "healthCheckProducerEnabled": { "index": 15, "kind": "property", 
"displayName": "Health Check Producer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all producer based health checks 
from this component. Notice: Camel has by default disabled all producer based 
health-checks. You can turn on produce [...]
-    "bearerToken": { "index": 16, "kind": "property", "displayName": "Bearer 
Token", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "Bearer token sent to the OPA server in the 
Authorization header, for an OPA instance that [...]
-    "failOpen": { "index": 17, "kind": "property", "displayName": "Fail Open", 
"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.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "Whether to allow the exchange to proceed when 
the policy cannot be evalua [...]
+    "connectionTimeout": { "index": 12, "kind": "property", "displayName": 
"Connection Timeout", "group": "advanced", "label": "advanced", "required": 
false, "type": "duration", "javaType": "long", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": "10000", 
"configurationClass": "org.apache.camel.component.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "How long to wait for the 
connection to the OPA server to be established, in rest mo [...]
+    "opaClient": { "index": 13, "kind": "property", "displayName": "Opa 
Client", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "com.styra.opa.OPAClient", "deprecated": false, 
"deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": "org.apache.camel.component.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "An existing OPAClient to 
use. When set, serverUrl and bearerToken are ignored." },
+    "poolSize": { "index": 14, "kind": "property", "displayName": "Pool Size", 
"group": "advanced", "label": "advanced", "required": false, "type": "integer", 
"javaType": "int", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 8, "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "How many WebAssembly policy instances to pool 
in wasm mode. An instance carries mutable state and is not thre [...]
+    "requestTimeout": { "index": 15, "kind": "property", "displayName": 
"Request Timeout", "group": "advanced", "label": "advanced", "required": false, 
"type": "duration", "javaType": "long", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": "30000", "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "How long to wait for the decision once 
connected, in rest mode. A request that times out  [...]
+    "healthCheckConsumerEnabled": { "index": 16, "kind": "property", 
"displayName": "Health Check Consumer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all consumer based health checks 
from this component" },
+    "healthCheckProducerEnabled": { "index": 17, "kind": "property", 
"displayName": "Health Check Producer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all producer based health checks 
from this component. Notice: Camel has by default disabled all producer based 
health-checks. You can turn on produce [...]
+    "bearerToken": { "index": 18, "kind": "property", "displayName": "Bearer 
Token", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "Bearer token sent to the OPA server in the 
Authorization header, for an OPA instance that [...]
+    "failOpen": { "index": 19, "kind": "property", "displayName": "Fail Open", 
"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.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "Whether to allow the exchange to proceed when 
the policy cannot be evalua [...]
+    "sslContextParameters": { "index": 20, "kind": "property", "displayName": 
"Ssl Context Parameters", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "TLS configuration for the connection to the 
OPA server in [...]
+    "useGlobalSslContextParameters": { "index": 21, "kind": "property", 
"displayName": "Use Global Ssl Context Parameters", "group": "security", 
"label": "security", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Enable usage of global SSL context 
parameters." }
   },
   "headers": {
     "CamelOpaDecisionAllow": { "index": 0, "kind": "header", "displayName": 
"", "group": "producer", "label": "producer", "required": false, "javaType": 
"Boolean", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The allow\/deny verdict of the policy 
evaluation. Always overwritten by the component, so a value set by an inbound 
message never survives into the route.", "constantName": 
"org.apache.camel.component.opa.OpaConstants#DECISION_ALLOW" },
@@ -60,9 +64,12 @@
     "serverUrl": { "index": 8, "kind": "parameter", "displayName": "Server 
Url", "group": "producer", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "http:\/\/localhost:8181", 
"configurationClass": "org.apache.camel.component.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "The base URL of the OPA 
server, without the {code \/v1\/data} suffix. The defau [...]
     "lazyStartProducer": { "index": 9, "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 [...]
     "borrowTimeout": { "index": 10, "kind": "parameter", "displayName": 
"Borrow Timeout", "group": "advanced", "label": "advanced", "required": false, 
"type": "duration", "javaType": "long", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": "30000", "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "How long an exchange waits for a free 
WebAssembly policy instance in wasm mode before the  [...]
-    "opaClient": { "index": 11, "kind": "parameter", "displayName": "Opa 
Client", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "com.styra.opa.OPAClient", "deprecated": false, 
"deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": "org.apache.camel.component.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "An existing OPAClient to 
use. When set, serverUrl and bearerToken are ignored." },
-    "poolSize": { "index": 12, "kind": "parameter", "displayName": "Pool 
Size", "group": "advanced", "label": "advanced", "required": false, "type": 
"integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": 8, "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "How many WebAssembly policy instances to pool 
in wasm mode. An instance carries mutable state and is not thr [...]
-    "bearerToken": { "index": 13, "kind": "parameter", "displayName": "Bearer 
Token", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "Bearer token sent to the OPA server in the 
Authorization header, for an OPA instance tha [...]
-    "failOpen": { "index": 14, "kind": "parameter", "displayName": "Fail 
Open", "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.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "Whether to allow the 
exchange to proceed when the policy cannot be evalu [...]
+    "connectionTimeout": { "index": 11, "kind": "parameter", "displayName": 
"Connection Timeout", "group": "advanced", "label": "advanced", "required": 
false, "type": "duration", "javaType": "long", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": "10000", 
"configurationClass": "org.apache.camel.component.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "How long to wait for the 
connection to the OPA server to be established, in rest m [...]
+    "opaClient": { "index": 12, "kind": "parameter", "displayName": "Opa 
Client", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "com.styra.opa.OPAClient", "deprecated": false, 
"deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": "org.apache.camel.component.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "An existing OPAClient to 
use. When set, serverUrl and bearerToken are ignored." },
+    "poolSize": { "index": 13, "kind": "parameter", "displayName": "Pool 
Size", "group": "advanced", "label": "advanced", "required": false, "type": 
"integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": 8, "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "How many WebAssembly policy instances to pool 
in wasm mode. An instance carries mutable state and is not thr [...]
+    "requestTimeout": { "index": 14, "kind": "parameter", "displayName": 
"Request Timeout", "group": "advanced", "label": "advanced", "required": false, 
"type": "duration", "javaType": "long", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": "30000", "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "How long to wait for the decision once 
connected, in rest mode. A request that times out [...]
+    "bearerToken": { "index": 15, "kind": "parameter", "displayName": "Bearer 
Token", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "Bearer token sent to the OPA server in the 
Authorization header, for an OPA instance tha [...]
+    "failOpen": { "index": 16, "kind": "parameter", "displayName": "Fail 
Open", "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.opa.OpaConfiguration", 
"configurationField": "configuration", "description": "Whether to allow the 
exchange to proceed when the policy cannot be evalu [...]
+    "sslContextParameters": { "index": 17, "kind": "parameter", "displayName": 
"Ssl Context Parameters", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.opa.OpaConfiguration", "configurationField": 
"configuration", "description": "TLS configuration for the connection to the 
OPA server i [...]
   }
 }
diff --git a/components/camel-opa/src/main/docs/opa-component.adoc 
b/components/camel-opa/src/main/docs/opa-component.adoc
index 4df6be0ac77e..0a373925f776 100644
--- a/components/camel-opa/src/main/docs/opa-component.adoc
+++ b/components/camel-opa/src/main/docs/opa-component.adoc
@@ -278,6 +278,43 @@ exchanges evaluate at once, and `borrowTimeout` when a 
single evaluation is legi
 run long enough to matter is usually better served by `evaluationMode=rest`, 
where the decision point is a
 separate process that a timeout can abandon.
 
+== Connecting to the server
+
+In `rest` mode the component talks to OPA over HTTP, and both waits are 
bounded:
+
+* `connectionTimeout` (default 10s) — establishing the connection.
+* `requestTimeout` (default 30s) — waiting for the decision once connected.
+
+Neither is optional in practice. A refused connection fails immediately, but a 
server that *accepts* and then
+stops answering — wedged, mid-restart, or behind a load balancer holding the 
socket — would otherwise park the
+routing thread indefinitely. For a component that fails closed that is worse 
than a denial: it never reaches the
+point of deciding. A timeout is treated as a failure to reach a verdict, so it 
denies, or proceeds if `failOpen`
+is set, like any other such failure.
+
+TLS is configured with `sslContextParameters`, the usual 
xref:manual::camel-configuration-utilities.adoc[JSSE
+utility]:
+
+[source,java]
+------------------------------------------------------------
+from("platform-http:/orders")
+    
.to("opa:authz/orders/allow?serverUrl=https://opa:8181&sslContextParameters=#opaTls";)
+------------------------------------------------------------
+
+Set `useGlobalSslContextParameters=true` on the component to pick up the 
context-wide configuration instead.
+
+That is what lets a workload present a client certificate to an OPA server 
requiring mutual TLS — a SPIFFE
+X.509-SVID, for example, so the application authenticates to the policy 
decision point as itself rather than
+relying on network position:
+
+[source,java]
+------------------------------------------------------------
+SpiffeSSLContextParameters spiffe = new SpiffeSSLContextParameters();
+spiffe.setCamelContext(context);
+context.getRegistry().bind("opaTls", spiffe);
+------------------------------------------------------------
+
+None of this applies in `wasm` mode, where there is no server to reach.
+
 == Failure handling
 
 The component fails closed. If the policy cannot be evaluated at all — the OPA 
server is unreachable, times out,
diff --git 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaComponent.java
 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaComponent.java
index 96660e274da2..47fc55ffa75c 100644
--- 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaComponent.java
+++ 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaComponent.java
@@ -20,6 +20,7 @@ import java.util.Map;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.Endpoint;
+import org.apache.camel.SSLContextParametersAware;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.annotations.Component;
 import org.apache.camel.support.HealthCheckComponent;
@@ -30,11 +31,14 @@ import org.apache.camel.util.StringHelper;
  * Open Policy Agent component.
  */
 @Component("opa")
-public class OpaComponent extends HealthCheckComponent {
+public class OpaComponent extends HealthCheckComponent implements 
SSLContextParametersAware {
 
     @Metadata
     private OpaConfiguration configuration = new OpaConfiguration();
 
+    @Metadata(label = "security", defaultValue = "false")
+    private boolean useGlobalSslContextParameters;
+
     public OpaComponent() {
     }
 
@@ -42,6 +46,19 @@ public class OpaComponent extends HealthCheckComponent {
         super(context);
     }
 
+    @Override
+    public boolean isUseGlobalSslContextParameters() {
+        return useGlobalSslContextParameters;
+    }
+
+    /**
+     * Enable usage of global SSL context parameters.
+     */
+    @Override
+    public void setUseGlobalSslContextParameters(boolean 
useGlobalSslContextParameters) {
+        this.useGlobalSslContextParameters = useGlobalSslContextParameters;
+    }
+
     @Override
     protected Endpoint createEndpoint(String uri, String remaining, 
Map<String, Object> parameters) throws Exception {
         if (ObjectHelper.isEmpty(remaining)) {
diff --git 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaConfiguration.java
 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaConfiguration.java
index 98489b2659a8..9c3753d796c0 100644
--- 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaConfiguration.java
+++ 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaConfiguration.java
@@ -21,6 +21,7 @@ import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriParams;
+import org.apache.camel.support.jsse.SSLContextParameters;
 
 @UriParams
 public class OpaConfiguration implements Cloneable {
@@ -57,6 +58,14 @@ public class OpaConfiguration implements Cloneable {
     @UriParam(label = "advanced", defaultValue = "30000", javaType = 
"java.time.Duration")
     private long borrowTimeout = 30000;
 
+    @UriParam(label = "advanced", defaultValue = "10000", javaType = 
"java.time.Duration")
+    private long connectionTimeout = 10000;
+    @UriParam(label = "advanced", defaultValue = "30000", javaType = 
"java.time.Duration")
+    private long requestTimeout = 30000;
+
+    @UriParam(label = "security")
+    private SSLContextParameters sslContextParameters;
+
     @UriParam(label = "security", security = "insecure:dev")
     private boolean failOpen;
 
@@ -218,6 +227,45 @@ public class OpaConfiguration implements Cloneable {
         this.borrowTimeout = borrowTimeout;
     }
 
+    public long getConnectionTimeout() {
+        return connectionTimeout;
+    }
+
+    /**
+     * How long to wait for the connection to the OPA server to be 
established, in {@code rest} mode. The SDK's own
+     * transport applies no timeout at all, so a server that never answers 
would otherwise park the calling thread
+     * indefinitely rather than letting the component fail closed.
+     */
+    public void setConnectionTimeout(long connectionTimeout) {
+        this.connectionTimeout = connectionTimeout;
+    }
+
+    public long getRequestTimeout() {
+        return requestTimeout;
+    }
+
+    /**
+     * How long to wait for the decision once connected, in {@code rest} mode. 
A request that times out is an evaluation
+     * failure rather than a deny, so it fails closed - or proceeds when 
{@code failOpen} is set - like any other
+     * failure to reach a verdict.
+     */
+    public void setRequestTimeout(long requestTimeout) {
+        this.requestTimeout = requestTimeout;
+    }
+
+    public SSLContextParameters getSslContextParameters() {
+        return sslContextParameters;
+    }
+
+    /**
+     * TLS configuration for the connection to the OPA server in {@code rest} 
mode. Needed to trust a server whose
+     * certificate comes from a private CA, and to present a client 
certificate to a server that requires mutual TLS - a
+     * SPIFFE X.509-SVID, for instance, so the workload authenticates to the 
policy decision point as itself.
+     */
+    public void setSslContextParameters(SSLContextParameters 
sslContextParameters) {
+        this.sslContextParameters = sslContextParameters;
+    }
+
     /**
      * Whether to allow the exchange to proceed when the policy cannot be 
evaluated at all, for example because the OPA
      * server is unreachable. Disabled by default so that an unreachable 
policy decision point denies rather than grants
diff --git 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaEndpoint.java
 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaEndpoint.java
index 175bb7f85408..495f78f3184b 100644
--- 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaEndpoint.java
+++ 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaEndpoint.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.component.opa;
 
+import javax.net.ssl.SSLContext;
+
 import com.styra.opa.OPAClient;
 import org.apache.camel.Category;
 import org.apache.camel.Component;
@@ -27,6 +29,7 @@ import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriPath;
 import org.apache.camel.support.DefaultEndpoint;
+import org.apache.camel.support.jsse.SSLContextParameters;
 import org.apache.camel.util.ObjectHelper;
 
 /**
@@ -52,6 +55,7 @@ public class OpaEndpoint extends DefaultEndpoint {
 
     private OPAClient opaClient;
     private volatile OpaPolicyEvaluator evaluator;
+    private volatile SSLContext sslContext;
 
     public OpaEndpoint(final String uri, final Component component, final 
OpaConfiguration configuration) {
         super(uri, component);
@@ -70,13 +74,45 @@ public class OpaEndpoint extends DefaultEndpoint {
             throw new IllegalArgumentException(
                     "Unknown evaluationMode '" + mode + "'; expected one of " 
+ REST_MODE + ", " + WASM_MODE);
         } else {
-            opaClient = configuration.getOpaClient() != null
-                    ? configuration.getOpaClient()
-                    : 
OpaRestEvaluator.createClient(configuration.getServerUrl(), 
configuration.getBearerToken());
-            evaluator = new OpaRestEvaluator(
-                    opaClient, policyPath, configuration.getAllowKey(), 
configuration.getIncludeHeaders(),
-                    configuration.getIncludeProperties(), 
configuration.isIncludeBody(), configuration.isFailOpen());
+            if (configuration.getOpaClient() != null) {
+                opaClient = configuration.getOpaClient();
+                evaluator = new OpaRestEvaluator(
+                        opaClient, null, policyPath, 
configuration.getAllowKey(), configuration.getIncludeHeaders(),
+                        configuration.getIncludeProperties(), 
configuration.isIncludeBody(),
+                        configuration.isFailOpen());
+            } else {
+                sslContext = createSslContext();
+                OpaHttpClient transport = OpaRestEvaluator.createTransport(
+                        configuration.getBearerToken(),
+                        configuration.getConnectionTimeout(), 
configuration.getRequestTimeout(),
+                        sslContext);
+                opaClient = 
OpaRestEvaluator.createClient(configuration.getServerUrl(), transport);
+                evaluator = new OpaRestEvaluator(
+                        opaClient, transport, policyPath, 
configuration.getAllowKey(),
+                        configuration.getIncludeHeaders(),
+                        configuration.getIncludeProperties(), 
configuration.isIncludeBody(),
+                        configuration.isFailOpen());
+            }
+        }
+    }
+
+    /**
+     * Resolves the endpoint's TLS configuration, falling back to the 
context's global one when the component opts in.
+     */
+    private SSLContext createSslContext() throws Exception {
+        SSLContextParameters ssl = configuration.getSslContextParameters();
+        if (ssl == null) {
+            ssl = getComponent().retrieveGlobalSslContextParameters();
         }
+        return ssl != null ? ssl.createSSLContext(getCamelContext()) : null;
+    }
+
+    /**
+     * The TLS configuration the decision call resolved to, so the producer's 
readiness check probes the server the same
+     * way rather than failing a handshake the decision call passes.
+     */
+    SSLContext getSslContext() {
+        return sslContext;
     }
 
     private OpaPolicyEvaluator createWasmEvaluator() throws Exception {
diff --git 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaHealthProbe.java
 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaHealthProbe.java
index b354052c0154..1f9daf4ebc53 100644
--- 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaHealthProbe.java
+++ 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaHealthProbe.java
@@ -21,6 +21,10 @@ import java.net.http.HttpClient;
 import java.net.http.HttpRequest;
 import java.net.http.HttpResponse;
 import java.time.Duration;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.net.ssl.SSLContext;
 
 import org.apache.camel.health.HealthCheckResultBuilder;
 import org.apache.camel.util.FileUtil;
@@ -45,9 +49,27 @@ public final class OpaHealthProbe {
      */
     private static final HttpClient HTTP_CLIENT = 
HttpClient.newBuilder().connectTimeout(TIMEOUT).build();
 
+    /**
+     * One client per distinct TLS configuration, because an {@link 
SSLContext} can only be set when the client is
+     * built. A probe that ignored it would fail its handshake against the 
very server the decision call reaches happily
+     * - reporting DOWN, and with it an application that never becomes ready.
+     * <p/>
+     * Keyed on identity and never evicted, which is bounded in practice: the 
key is an {@code SSLContext} built from an
+     * endpoint's {@code sslContextParameters}, and a deployment has one or 
two of those, not one per exchange.
+     */
+    private static final Map<SSLContext, HttpClient> TLS_CLIENTS = new 
ConcurrentHashMap<>();
+
     private OpaHealthProbe() {
     }
 
+    private static HttpClient clientFor(SSLContext sslContext) {
+        if (sslContext == null) {
+            return HTTP_CLIENT;
+        }
+        return TLS_CLIENTS.computeIfAbsent(sslContext,
+                ctx -> 
HttpClient.newBuilder().connectTimeout(TIMEOUT).sslContext(ctx).build());
+    }
+
     /**
      * Probes the OPA server's health endpoint and records the outcome on the 
builder.
      * <p/>
@@ -58,9 +80,11 @@ public final class OpaHealthProbe {
      * @param serverUrl   base URL of the OPA server, without the /v1/data 
suffix
      * @param bearerToken token for OPA API authentication, or null when OPA 
does not require one
      * @param policyPath  the policy this check is reporting for, recorded as 
a detail
+     * @param sslContext  the TLS configuration the decision call uses, or 
null for the JVM default
      */
     public static void probe(
-            HealthCheckResultBuilder builder, String serverUrl, String 
bearerToken, String policyPath) {
+            HealthCheckResultBuilder builder, String serverUrl, String 
bearerToken, String policyPath,
+            SSLContext sslContext) {
         builder.detail("opa.serverUrl", URISupport.sanitizeUri(serverUrl));
         builder.detail("opa.policyPath", policyPath);
 
@@ -75,7 +99,7 @@ public final class OpaHealthProbe {
         }
 
         try {
-            HttpResponse<Void> response = HTTP_CLIENT.send(request.build(), 
HttpResponse.BodyHandlers.discarding());
+            HttpResponse<Void> response = 
clientFor(sslContext).send(request.build(), 
HttpResponse.BodyHandlers.discarding());
             if (response.statusCode() == 200) {
                 builder.up();
             } else {
diff --git 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaHttpClient.java
 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaHttpClient.java
new file mode 100644
index 000000000000..bd537e6173b9
--- /dev/null
+++ 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaHttpClient.java
@@ -0,0 +1,90 @@
+/*
+ * 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.opa;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.time.Duration;
+
+import javax.net.ssl.SSLContext;
+
+import com.styra.opa.openapi.utils.HTTPClient;
+import org.apache.camel.util.ObjectHelper;
+
+/**
+ * The HTTP transport the OPA SDK uses to reach the server.
+ * <p/>
+ * Supplied rather than left to the SDK, whose default {@code 
SpeakeasyHTTPClient} is a one-liner around
+ * {@code HttpClient.newHttpClient()} with two consequences a policy decision 
point cannot afford:
+ * <ul>
+ * <li><b>Nothing bounds the call.</b> That factory sets no connect timeout 
and the SDK sets no request timeout, so both
+ * are the JDK default of "wait indefinitely". A server that accepts the 
connection and then goes quiet parks the
+ * calling thread for ever - and a component that fails closed never reaches 
the point of denying, it simply stops.
+ * {@code failOpen} does not help, because it sits downstream of a call that 
never returns.</li>
+ * <li><b>It builds a client per request.</b> On the Java 17 baseline {@link 
HttpClient} is not {@link AutoCloseable},
+ * so each one holds its selector thread and executor until it is collected - 
once per message, on the path an
+ * {@code OpaSecurityPolicy} guards.</li>
+ * </ul>
+ * One client is built here per evaluator and reused, and every request is 
re-issued carrying a timeout.
+ */
+public class OpaHttpClient implements HTTPClient, AutoCloseable {
+
+    private static final String AUTHORIZATION = "Authorization";
+
+    private final HttpClient client;
+    private final Duration requestTimeout;
+    private final String bearerToken;
+
+    OpaHttpClient(long connectionTimeout, long requestTimeout, SSLContext 
sslContext, String bearerToken) {
+        HttpClient.Builder builder = HttpClient.newBuilder()
+                .connectTimeout(Duration.ofMillis(connectionTimeout));
+        if (sslContext != null) {
+            builder.sslContext(sslContext);
+        }
+        this.client = builder.build();
+        this.requestTimeout = Duration.ofMillis(requestTimeout);
+        // the SDK has no constructor taking a transport and headers together, 
so the token is applied here
+        // instead of through OPAClient(String, Map) - the request that goes 
out is the same either way
+        // isNotEmpty, not a null check: an unset placeholder resolves to "", 
and sending
+        // "Authorization: Bearer " is worse than sending nothing at all
+        this.bearerToken = ObjectHelper.isNotEmpty(bearerToken) ? bearerToken 
: null;
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (client instanceof AutoCloseable c) {
+            c.close();
+        }
+    }
+
+    @Override
+    public HttpResponse<InputStream> send(HttpRequest request) throws 
IOException, InterruptedException {
+        // the SDK hands us a finished request, and HttpRequest is immutable - 
rebuilding it is the only way to
+        // attach a timeout. The filter keeps every header the SDK set, 
dropping only an Authorization we are
+        // about to replace, because header() appends rather than overwrites
+        HttpRequest.Builder builder = HttpRequest
+                .newBuilder(request, (name, value) -> bearerToken == null || 
!AUTHORIZATION.equalsIgnoreCase(name))
+                .timeout(requestTimeout);
+        if (bearerToken != null) {
+            builder.header(AUTHORIZATION, "Bearer " + bearerToken);
+        }
+        return client.send(builder.build(), 
HttpResponse.BodyHandlers.ofInputStream());
+    }
+}
diff --git 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaProducer.java
 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaProducer.java
index 0e1e2c11f22d..3d6e2e4c25a2 100644
--- 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaProducer.java
+++ 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaProducer.java
@@ -58,7 +58,7 @@ public class OpaProducer extends DefaultProducer {
                     configuration.getServerUrl(), 
configuration.getBearerToken(),
                     // the endpoint URI is unique within the context, so two 
endpoints sharing a policy path but
                     // pointing at different servers get distinct health-check 
ids instead of colliding
-                    getEndpoint().getPolicyPath(), 
getEndpoint().getEndpointUri());
+                    getEndpoint().getPolicyPath(), 
getEndpoint().getEndpointUri(), getEndpoint().getSslContext());
             
producerHealthCheck.setEnabled(getEndpoint().getComponent().isHealthCheckProducerEnabled());
             healthCheckRepository.addHealthCheck(producerHealthCheck);
         }
diff --git 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaProducerHealthCheck.java
 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaProducerHealthCheck.java
index d91946850d99..6305a4de280c 100644
--- 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaProducerHealthCheck.java
+++ 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaProducerHealthCheck.java
@@ -18,6 +18,8 @@ package org.apache.camel.component.opa;
 
 import java.util.Map;
 
+import javax.net.ssl.SSLContext;
+
 import org.apache.camel.health.HealthCheckResultBuilder;
 import org.apache.camel.impl.health.AbstractHealthCheck;
 import org.apache.camel.util.URISupport;
@@ -34,18 +36,21 @@ public class OpaProducerHealthCheck extends 
AbstractHealthCheck {
     private final String serverUrl;
     private final String bearerToken;
     private final String policyPath;
+    private final SSLContext sslContext;
 
-    public OpaProducerHealthCheck(String serverUrl, String bearerToken, String 
policyPath, String id) {
+    public OpaProducerHealthCheck(String serverUrl, String bearerToken, String 
policyPath, String id,
+                                  SSLContext sslContext) {
         // the id is built from the endpoint URI so that two endpoints sharing 
a policy path stay distinct, but that
         // URI carries the bearerToken in the clear and the id is published in 
the health output, so sanitize it
         super("camel", "producer:opa-" + URISupport.sanitizeUri(id));
         this.serverUrl = serverUrl;
         this.bearerToken = bearerToken;
         this.policyPath = policyPath;
+        this.sslContext = sslContext;
     }
 
     @Override
     protected void doCall(HealthCheckResultBuilder builder, Map<String, 
Object> options) {
-        OpaHealthProbe.probe(builder, serverUrl, bearerToken, policyPath);
+        OpaHealthProbe.probe(builder, serverUrl, bearerToken, policyPath, 
sslContext);
     }
 }
diff --git 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaRestEvaluator.java
 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaRestEvaluator.java
index 4746ddc89500..10a67c19eecb 100644
--- 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaRestEvaluator.java
+++ 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaRestEvaluator.java
@@ -18,33 +18,58 @@ package org.apache.camel.component.opa;
 
 import java.util.Map;
 
+import javax.net.ssl.SSLContext;
+
 import com.styra.opa.OPAClient;
 import org.apache.camel.util.ObjectHelper;
 
 /**
  * Evaluates the policy by calling a running OPA server over its REST Data API.
  */
-public class OpaRestEvaluator extends OpaPolicyEvaluator {
+public class OpaRestEvaluator extends OpaPolicyEvaluator implements 
AutoCloseable {
 
     private final OPAClient client;
+    private final OpaHttpClient transport;
 
-    public OpaRestEvaluator(OPAClient client, String policyPath, String 
allowKey, String includeHeaders,
+    public OpaRestEvaluator(OPAClient client, OpaHttpClient transport, String 
policyPath, String allowKey,
+                            String includeHeaders,
                             String includeProperties, boolean includeBody, 
boolean failOpen) {
         super(policyPath, allowKey, includeHeaders, includeProperties, 
includeBody, failOpen);
         this.client = ObjectHelper.notNull(client, "client");
+        this.transport = transport;
     }
 
     /**
-     * Creates a client for an OPA server, optionally authenticating with a 
bearer token.
+     * Creates the HTTP transport for an OPA server connection.
      *
-     * @param serverUrl   base URL of the OPA server, without the /v1/data 
suffix
-     * @param bearerToken token for OPA API authentication, or null when OPA 
does not require one
+     * @param bearerToken       token for OPA API authentication, or null when 
OPA does not require one
+     * @param connectionTimeout how long to wait for the connection to be 
established, in milliseconds
+     * @param requestTimeout    how long to wait for the decision once 
connected, in milliseconds
+     * @param sslContext        TLS configuration for the connection, or null 
for the JVM default
      */
-    public static OPAClient createClient(String serverUrl, String bearerToken) 
{
-        if (ObjectHelper.isNotEmpty(bearerToken)) {
-            return new OPAClient(serverUrl, Map.of("Authorization", "Bearer " 
+ bearerToken));
+    public static OpaHttpClient createTransport(
+            String bearerToken, long connectionTimeout, long requestTimeout, 
SSLContext sslContext) {
+        return new OpaHttpClient(connectionTimeout, requestTimeout, 
sslContext, bearerToken);
+    }
+
+    /**
+     * Creates a client for an OPA server, over a transport this component 
controls.
+     * <p/>
+     * The SDK's own default transport builds a fresh {@code HttpClient} per 
request with no timeouts at all; see
+     * {@link OpaHttpClient} for why neither is acceptable on the path that 
decides authorization.
+     *
+     * @param serverUrl base URL of the OPA server, without the /v1/data suffix
+     * @param transport the HTTP transport to use for all requests
+     */
+    public static OPAClient createClient(String serverUrl, OpaHttpClient 
transport) {
+        return new OPAClient(serverUrl, transport);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (transport != null) {
+            transport.close();
         }
-        return new OPAClient(serverUrl);
     }
 
     @Override
diff --git 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/security/OpaSecurityPolicy.java
 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/security/OpaSecurityPolicy.java
index 3c3a60c907a1..a8dfc21cb742 100644
--- 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/security/OpaSecurityPolicy.java
+++ 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/security/OpaSecurityPolicy.java
@@ -16,14 +16,23 @@
  */
 package org.apache.camel.component.opa.security;
 
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+import javax.net.ssl.SSLContext;
+
 import com.styra.opa.OPAClient;
+import org.apache.camel.CamelContext;
 import org.apache.camel.NamedNode;
 import org.apache.camel.Processor;
 import org.apache.camel.Route;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.opa.OpaHttpClient;
 import org.apache.camel.component.opa.OpaPolicyEvaluator;
 import org.apache.camel.component.opa.OpaRestEvaluator;
 import org.apache.camel.health.HealthCheckRegistry;
 import org.apache.camel.spi.AuthorizationPolicy;
+import org.apache.camel.support.jsse.SSLContextParameters;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.StringHelper;
 import org.slf4j.Logger;
@@ -59,10 +68,14 @@ public class OpaSecurityPolicy implements 
AuthorizationPolicy {
     private OPAClient opaClient;
 
     private boolean healthCheckEnabled = true;
+    private long connectionTimeout = 10000;
+    private long requestTimeout = 30000;
+    private SSLContextParameters sslContextParameters;
 
     private volatile OpaPolicyEvaluator evaluator;
     private volatile OpaSecurityPolicyHealthCheck healthCheck;
     private volatile boolean ownsClient;
+    private volatile SSLContext sslContext;
 
     public OpaSecurityPolicy() {
     }
@@ -76,13 +89,25 @@ public class OpaSecurityPolicy implements 
AuthorizationPolicy {
     public void beforeWrap(Route route, NamedNode definition) {
         if (evaluator == null) {
             StringHelper.notEmpty(policyPath, "policyPath", this);
+            OpaHttpClient transport = null;
             if (opaClient == null) {
                 // createClient moved to OpaRestEvaluator when the evaluator 
became an abstract base
-                opaClient = OpaRestEvaluator.createClient(serverUrl, 
bearerToken);
+                sslContext = createSslContext(route.getCamelContext());
+                transport = OpaRestEvaluator.createTransport(
+                        bearerToken, connectionTimeout, requestTimeout, 
sslContext);
+                opaClient = OpaRestEvaluator.createClient(serverUrl, 
transport);
                 ownsClient = true;
             }
             evaluator = new OpaRestEvaluator(
-                    opaClient, policyPath, allowKey, includeHeaders, 
includeProperties, includeBody, failOpen);
+                    opaClient, transport, policyPath, allowKey, 
includeHeaders, includeProperties, includeBody,
+                    failOpen);
+            // a Policy has no stop hook of its own, so the transport would 
outlive the routes it was built for.
+            // Registering the evaluator as a service hands its close() to the 
context's shutdown
+            try {
+                route.getCamelContext().addService(evaluator);
+            } catch (Exception e) {
+                throw new RuntimeCamelException("Could not register the 
evaluator for policy " + policyPath, e);
+            }
         }
         // after validation, so a policy that is missing its policyPath fails 
without leaving a ".../null" check
         // behind in the registry
@@ -105,7 +130,7 @@ public class OpaSecurityPolicy implements 
AuthorizationPolicy {
         if (registry == null) {
             return;
         }
-        healthCheck = new OpaSecurityPolicyHealthCheck(serverUrl, bearerToken, 
policyPath);
+        healthCheck = new OpaSecurityPolicyHealthCheck(serverUrl, bearerToken, 
policyPath, sslContext);
         registry.register(healthCheck);
     }
 
@@ -211,6 +236,64 @@ public class OpaSecurityPolicy implements 
AuthorizationPolicy {
         this.failOpen = failOpen;
     }
 
+    /**
+     * The policy is a bean rather than a {@code CamelContextAware} service, 
so the context comes from the route it is
+     * wrapping - which is the only place one is available.
+     */
+    private SSLContext createSslContext(CamelContext camelContext) {
+        if (sslContextParameters == null) {
+            return null;
+        }
+        try {
+            return sslContextParameters.createSSLContext(camelContext);
+        } catch (GeneralSecurityException | IOException e) {
+            // beforeWrap cannot throw checked exceptions, and a policy whose 
TLS configuration is broken must not
+            // start a route that would then talk to OPA over the JVM default 
trust material instead
+            throw new RuntimeCamelException("Could not build the SSLContext 
for policy " + policyPath, e);
+        }
+    }
+
+    public long getConnectionTimeout() {
+        return connectionTimeout;
+    }
+
+    /**
+     * How long to wait for the connection to the OPA server to be 
established. The SDK's own transport applies no
+     * timeout, so a server that never answers would otherwise park the 
routing thread rather than letting the policy
+     * fail closed.
+     */
+    public void setConnectionTimeout(long connectionTimeout) {
+        this.connectionTimeout = connectionTimeout;
+    }
+
+    public long getRequestTimeout() {
+        return requestTimeout;
+    }
+
+    /**
+     * How long to wait for the decision once connected. A request that times 
out is an evaluation failure rather than a
+     * deny, so the policy denies the exchange unless {@code failOpen} is set.
+     */
+    public void setRequestTimeout(long requestTimeout) {
+        this.requestTimeout = requestTimeout;
+    }
+
+    public SSLContextParameters getSslContextParameters() {
+        return sslContextParameters;
+    }
+
+    /**
+     * TLS configuration for the connection to the OPA server. Needed to trust 
a server whose certificate comes from a
+     * private CA, and to present a client certificate to a server requiring 
mutual TLS.
+     * <p/>
+     * Note: {@code useGlobalSslContextParameters} on the {@link 
org.apache.camel.component.opa.OpaComponent} has no
+     * effect here. {@code OpaSecurityPolicy} is a standalone bean and is not 
bound to any component instance, so the
+     * global SSL context cannot be resolved automatically. Set this field 
explicitly when TLS is required.
+     */
+    public void setSslContextParameters(SSLContextParameters 
sslContextParameters) {
+        this.sslContextParameters = sslContextParameters;
+    }
+
     public boolean isHealthCheckEnabled() {
         return healthCheckEnabled;
     }
diff --git 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/security/OpaSecurityPolicyHealthCheck.java
 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/security/OpaSecurityPolicyHealthCheck.java
index 75e4aad3a7cf..2c53a3447005 100644
--- 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/security/OpaSecurityPolicyHealthCheck.java
+++ 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/security/OpaSecurityPolicyHealthCheck.java
@@ -18,6 +18,8 @@ package org.apache.camel.component.opa.security;
 
 import java.util.Map;
 
+import javax.net.ssl.SSLContext;
+
 import org.apache.camel.component.opa.OpaHealthProbe;
 import org.apache.camel.health.HealthCheckResultBuilder;
 import org.apache.camel.impl.health.AbstractHealthCheck;
@@ -36,18 +38,21 @@ public class OpaSecurityPolicyHealthCheck extends 
AbstractHealthCheck {
     private final String serverUrl;
     private final String bearerToken;
     private final String policyPath;
+    private final SSLContext sslContext;
 
-    public OpaSecurityPolicyHealthCheck(String serverUrl, String bearerToken, 
String policyPath) {
+    public OpaSecurityPolicyHealthCheck(String serverUrl, String bearerToken, 
String policyPath,
+                                        SSLContext sslContext) {
         // serverUrl and policyPath together identify the decision this policy 
enforces, so two policies pointing at
         // different servers stay distinct; sanitized because the id is 
published in the health output
         super("camel", "security-policy:opa-" + 
URISupport.sanitizeUri(serverUrl + "/" + policyPath));
         this.serverUrl = serverUrl;
         this.bearerToken = bearerToken;
         this.policyPath = policyPath;
+        this.sslContext = sslContext;
     }
 
     @Override
     protected void doCall(HealthCheckResultBuilder builder, Map<String, 
Object> options) {
-        OpaHealthProbe.probe(builder, serverUrl, bearerToken, policyPath);
+        OpaHealthProbe.probe(builder, serverUrl, bearerToken, policyPath, 
sslContext);
     }
 }
diff --git 
a/components/camel-opa/src/test/java/org/apache/camel/component/opa/OpaProducerHealthCheckTest.java
 
b/components/camel-opa/src/test/java/org/apache/camel/component/opa/OpaProducerHealthCheckTest.java
index 649c373ac548..7e0ee58d1cbb 100644
--- 
a/components/camel-opa/src/test/java/org/apache/camel/component/opa/OpaProducerHealthCheckTest.java
+++ 
b/components/camel-opa/src/test/java/org/apache/camel/component/opa/OpaProducerHealthCheckTest.java
@@ -52,7 +52,7 @@ class OpaProducerHealthCheckTest {
     }
 
     private static HealthCheck.Result call(String serverUrl) {
-        OpaProducerHealthCheck check = new OpaProducerHealthCheck(serverUrl, 
null, "authz/allow", "authz/allow");
+        OpaProducerHealthCheck check = new OpaProducerHealthCheck(serverUrl, 
null, "authz/allow", "authz/allow", null);
         check.setEnabled(true);
         return check.call(Map.of());
     }
@@ -63,7 +63,7 @@ class OpaProducerHealthCheckTest {
         // health output, so the token must not survive into it
         OpaProducerHealthCheck check = new OpaProducerHealthCheck(
                 "http://localhost:8181";, "s3cr3t-token", "authz/allow",
-                
"opa://authz/allow?bearerToken=s3cr3t-token&serverUrl=http://localhost:8181";);
+                
"opa://authz/allow?bearerToken=s3cr3t-token&serverUrl=http://localhost:8181";, 
null);
 
         assertThat(check.getId()).doesNotContain("s3cr3t-token");
         assertThat(check.getId()).contains("serverUrl=http://localhost:8181";);
@@ -73,10 +73,10 @@ class OpaProducerHealthCheckTest {
     void givesEndpointsOnDifferentServersDistinctIds() {
         OpaProducerHealthCheck primary = new OpaProducerHealthCheck(
                 "http://opa-primary:8181";, null, "authz/allow",
-                "opa://authz/allow?serverUrl=http://opa-primary:8181";);
+                "opa://authz/allow?serverUrl=http://opa-primary:8181";, null);
         OpaProducerHealthCheck secondary = new OpaProducerHealthCheck(
                 "http://opa-secondary:8181";, null, "authz/allow",
-                "opa://authz/allow?serverUrl=http://opa-secondary:8181";);
+                "opa://authz/allow?serverUrl=http://opa-secondary:8181";, null);
 
         assertThat(primary.getId()).isNotEqualTo(secondary.getId());
         assertThat(primary).isNotEqualTo(secondary);
diff --git 
a/components/camel-opa/src/test/java/org/apache/camel/component/opa/OpaRestTransportTest.java
 
b/components/camel-opa/src/test/java/org/apache/camel/component/opa/OpaRestTransportTest.java
new file mode 100644
index 000000000000..8bb3096a273f
--- /dev/null
+++ 
b/components/camel-opa/src/test/java/org/apache/camel/component/opa/OpaRestTransportTest.java
@@ -0,0 +1,234 @@
+/*
+ * 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.opa;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+
+import com.sun.net.httpserver.HttpServer;
+import com.sun.net.httpserver.HttpsConfigurator;
+import com.sun.net.httpserver.HttpsServer;
+import org.apache.camel.Exchange;
+import org.apache.camel.support.jsse.KeyStoreParameters;
+import org.apache.camel.support.jsse.SSLContextParameters;
+import org.apache.camel.support.jsse.TrustManagersParameters;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * The transport underneath {@code evaluationMode=rest}.
+ * <p/>
+ * A server that refuses a connection fails fast and is already covered; what 
is not, and what an operator actually
+ * meets, is a server that <em>accepts</em> and then says nothing. The SDK's 
own transport applies no timeout of any
+ * kind, so that case parked the routing thread for ever - and a component 
that fails closed never reached the point of
+ * denying, it simply stopped.
+ */
+public class OpaRestTransportTest extends CamelTestSupport {
+
+    private static final String KEYSTORE = "opa-server.p12";
+    private static final String PASSWORD = "changeit";
+
+    private final List<Closeable> open = new ArrayList<>();
+
+    private interface Closeable extends AutoCloseable {
+        @Override
+        void close() throws IOException;
+    }
+
+    @AfterEach
+    void closeSockets() throws Exception {
+        for (Closeable c : open) {
+            c.close();
+        }
+        open.clear();
+    }
+
+    /**
+     * A listener that completes the TCP handshake and then never answers. 
Deliberately not an HttpServer: the point is
+     * a peer that is reachable but mute, which is what a wedged OPA looks 
like from the client side.
+     */
+    private int mutePort() throws IOException {
+        ServerSocket listener = new ServerSocket(0);
+        open.add(listener::close);
+        Thread accepter = new Thread(() -> {
+            try {
+                listener.accept();
+                // hold it: no read, no write, no close. Ends when the test 
closes the listener.
+            } catch (IOException e) {
+                // the listener was closed as the test finished
+            }
+        }, "opa-mute-server");
+        accepter.setDaemon(true);
+        accepter.start();
+        return listener.getLocalPort();
+    }
+
+    /**
+     * An HTTPS listener presenting the throwaway self-signed certificate from 
{@code opa-server.p12}, answering the
+     * policy query the way a real OPA would.
+     */
+    private int tlsPort() throws Exception {
+        KeyStore keyStore = KeyStore.getInstance("PKCS12");
+        try (InputStream in = getClass().getResourceAsStream("/" + KEYSTORE)) {
+            keyStore.load(in, PASSWORD.toCharArray());
+        }
+        KeyManagerFactory kmf = 
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+        kmf.init(keyStore, PASSWORD.toCharArray());
+        SSLContext serverContext = SSLContext.getInstance("TLS");
+        serverContext.init(kmf.getKeyManagers(), null, null);
+
+        HttpsServer server = HttpsServer.create(new 
InetSocketAddress("localhost", 0), 0);
+        server.setHttpsConfigurator(new HttpsConfigurator(serverContext));
+        server.createContext("/v1/data/authz/allow", exchange -> {
+            byte[] body = "{\"result\":true}".getBytes(StandardCharsets.UTF_8);
+            exchange.getResponseHeaders().add("Content-Type", 
"application/json");
+            exchange.sendResponseHeaders(200, body.length);
+            try (OutputStream out = exchange.getResponseBody()) {
+                out.write(body);
+            }
+        });
+        server.start();
+        open.add(() -> server.stop(0));
+        return server.getAddress().getPort();
+    }
+
+    /** Trust material holding exactly the fixture certificate, and nothing 
else. */
+    private SSLContextParameters trustingTheFixture() {
+        KeyStoreParameters ks = new KeyStoreParameters();
+        ks.setCamelContext(context);
+        ks.setResource(KEYSTORE);
+        ks.setPassword(PASSWORD);
+        ks.setType("PKCS12");
+
+        TrustManagersParameters tm = new TrustManagersParameters();
+        tm.setCamelContext(context);
+        tm.setKeyStore(ks);
+
+        SSLContextParameters ssl = new SSLContextParameters();
+        ssl.setCamelContext(context);
+        ssl.setTrustManagers(tm);
+        return ssl;
+    }
+
+    @Test
+    @Timeout(60)
+    void reachesAnHttpsServerWhenSslContextParametersTrustIt() throws 
Exception {
+        context.getRegistry().bind("opaTls", trustingTheFixture());
+
+        Exchange out = template.request(
+                "opa:authz/allow?serverUrl=https://localhost:"; + tlsPort() + 
"&sslContextParameters=#opaTls", e -> {
+                });
+
+        assertThat(out.getException()).isNull();
+        
assertThat(out.getMessage().getHeader(OpaConstants.DECISION_ALLOW)).isEqualTo(true);
+    }
+
+    @Test
+    @Timeout(60)
+    void failsClosedAgainstTheSameServerWithoutTheTrustMaterial() throws 
Exception {
+        // same listener, same policy, same request - only 
sslContextParameters is missing. If this passed, the
+        // option would not be doing anything and the test above would prove 
nothing
+        Exchange out = template.request(
+                "opa:authz/allow?serverUrl=https://localhost:"; + tlsPort(), e 
-> {
+                });
+
+        
assertThat(out.getException()).isInstanceOf(OpaPolicyEvaluationException.class);
+        
assertThat(out.getMessage().getHeader(OpaConstants.DECISION_ALLOW)).isNull();
+    }
+
+    /** A plain listener that answers every policy query and records the 
Authorization it was sent. */
+    private int recordingPort(AtomicReference<String> seen) throws Exception {
+        HttpServer server = HttpServer.create(new 
InetSocketAddress("localhost", 0), 0);
+        server.createContext("/v1/data/authz/allow", exchange -> {
+            seen.set(exchange.getRequestHeaders().getFirst("Authorization"));
+            byte[] body = "{\"result\":true}".getBytes(StandardCharsets.UTF_8);
+            exchange.getResponseHeaders().add("Content-Type", 
"application/json");
+            exchange.sendResponseHeaders(200, body.length);
+            try (OutputStream out = exchange.getResponseBody()) {
+                out.write(body);
+            }
+        });
+        server.start();
+        open.add(() -> server.stop(0));
+        return server.getAddress().getPort();
+    }
+
+    @Test
+    @Timeout(60)
+    void sendsTheBearerTokenWhenOneIsConfigured() throws Exception {
+        AtomicReference<String> seen = new AtomicReference<>();
+
+        template.request("opa:authz/allow?serverUrl=http://localhost:"; + 
recordingPort(seen) + "&bearerToken=s3cr3t",
+                e -> {
+                });
+
+        assertThat(seen.get()).isEqualTo("Bearer s3cr3t");
+    }
+
+    @Test
+    @Timeout(60)
+    void sendsNoAuthorizationAtAllWhenTheTokenIsEmpty() throws Exception {
+        // an unset placeholder resolves to "", and "Authorization: Bearer " 
is not an absent header - it is a
+        // malformed credential, which a server enforcing tokens answers with 
a 401 rather than ignoring
+        AtomicReference<String> seen = new AtomicReference<>("not called");
+
+        template.request("opa:authz/allow?serverUrl=http://localhost:"; + 
recordingPort(seen) + "&bearerToken=",
+                e -> {
+                });
+
+        assertThat(seen.get()).isNull();
+    }
+
+    @Test
+    @Timeout(60)
+    void failsClosedWhenTheServerAcceptsAndThenSaysNothing() throws Exception {
+        Exchange out = template.request(
+                "opa:authz/allow?serverUrl=http://localhost:"; + mutePort() + 
"&requestTimeout=500", e -> {
+                });
+
+        
assertThat(out.getException()).isInstanceOf(OpaPolicyEvaluationException.class);
+        
assertThat(out.getMessage().getHeader(OpaConstants.DECISION_ALLOW)).isNull();
+    }
+
+    @Test
+    @Timeout(60)
+    void proceedsOnTheSameStallWhenFailOpenIsSet() throws Exception {
+        // a timeout is a failure to reach a verdict, not a deny, so it is 
handled like every other such failure
+        Exchange out = template.request(
+                "opa:authz/allow?serverUrl=http://localhost:"; + mutePort() + 
"&requestTimeout=500&failOpen=true",
+                e -> {
+                });
+
+        assertThat(out.getException()).isNull();
+        
assertThat(out.getMessage().getHeader(OpaConstants.DECISION_ALLOW)).isEqualTo(true);
+    }
+}
diff --git 
a/components/camel-opa/src/test/java/org/apache/camel/component/opa/security/OpaSecurityPolicyHealthCheckTest.java
 
b/components/camel-opa/src/test/java/org/apache/camel/component/opa/security/OpaSecurityPolicyHealthCheckTest.java
index 123f9fe90a0c..5042ea75839c 100644
--- 
a/components/camel-opa/src/test/java/org/apache/camel/component/opa/security/OpaSecurityPolicyHealthCheckTest.java
+++ 
b/components/camel-opa/src/test/java/org/apache/camel/component/opa/security/OpaSecurityPolicyHealthCheckTest.java
@@ -112,7 +112,7 @@ public class OpaSecurityPolicyHealthCheckTest extends 
CamelTestSupport {
         // non-canonical path with a redirect, and the probe's client does not 
follow redirects, so a healthy
         // server was reported DOWN. Every other test here uses a slash-free 
URL, which is how it went unnoticed.
         OpaSecurityPolicyHealthCheck check
-                = new OpaSecurityPolicyHealthCheck(serverUrl + "/", null, 
"authz/allow");
+                = new OpaSecurityPolicyHealthCheck(serverUrl + "/", null, 
"authz/allow", null);
         check.setEnabled(true);
 
         HealthCheck.Result result = check.call(Map.of());
@@ -123,7 +123,7 @@ public class OpaSecurityPolicyHealthCheckTest extends 
CamelTestSupport {
     @Test
     void reportsDownWhenTheServerCannotBeReached() {
         OpaSecurityPolicyHealthCheck check
-                = new OpaSecurityPolicyHealthCheck("http://localhost:1";, null, 
"authz/allow");
+                = new OpaSecurityPolicyHealthCheck("http://localhost:1";, null, 
"authz/allow", null);
         check.setEnabled(true);
 
         HealthCheck.Result result = check.call(Map.of());
diff --git a/components/camel-opa/src/test/resources/README-tls-fixture.md 
b/components/camel-opa/src/test/resources/README-tls-fixture.md
new file mode 100644
index 000000000000..7c027c7af306
--- /dev/null
+++ b/components/camel-opa/src/test/resources/README-tls-fixture.md
@@ -0,0 +1,16 @@
+# TLS test fixture
+
+`opa-server.p12` is a throwaway self-signed keypair for 
`OpaRestTransportTest`, used both as the HTTPS
+listener's key material and as the truststore the passing case is given. It is 
not used anywhere outside the
+tests and grants nothing: the private key is public in this repository.
+
+Regenerate with:
+
+```sh
+keytool -genkeypair -alias opa -keyalg RSA -keysize 2048 -validity 36500 \
+    -dname "CN=localhost, OU=camel-opa tests, O=Apache Camel" \
+    -ext "SAN=dns:localhost,ip:127.0.0.1" \
+    -keystore opa-server.p12 -storetype PKCS12 -storepass changeit -keypass 
changeit
+```
+
+The certificate is valid for 100 years, so the tests will not start failing on 
an expiry nobody is watching.
diff --git a/components/camel-opa/src/test/resources/opa-server.p12 
b/components/camel-opa/src/test/resources/opa-server.p12
new file mode 100644
index 000000000000..1a2db1d13df8
Binary files /dev/null and 
b/components/camel-opa/src/test/resources/opa-server.p12 differ
diff --git 
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/OpaComponentBuilderFactory.java
 
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/OpaComponentBuilderFactory.java
index 7613350eb30a..3b1c544f969a 100644
--- 
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/OpaComponentBuilderFactory.java
+++ 
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/OpaComponentBuilderFactory.java
@@ -309,6 +309,27 @@ public interface OpaComponentBuilderFactory {
             return this;
         }
     
+        
+        /**
+         * How long to wait for the connection to the OPA server to be
+         * established, in rest mode. The SDK's own transport applies no 
timeout
+         * at all, so a server that never answers would otherwise park the
+         * calling thread indefinitely rather than letting the component fail
+         * closed.
+         * 
+         * The option is a: &lt;code&gt;long&lt;/code&gt; type.
+         * 
+         * Default: 10000
+         * Group: advanced
+         * 
+         * @param connectionTimeout the value to set
+         * @return the dsl builder
+         */
+        default OpaComponentBuilder connectionTimeout(long connectionTimeout) {
+            doSetProperty("connectionTimeout", connectionTimeout);
+            return this;
+        }
+    
         /**
          * An existing OPAClient to use. When set, serverUrl and bearerToken 
are
          * ignored.
@@ -347,6 +368,26 @@ public interface OpaComponentBuilderFactory {
         }
     
         
+        /**
+         * How long to wait for the decision once connected, in rest mode. A
+         * request that times out is an evaluation failure rather than a deny,
+         * so it fails closed - or proceeds when failOpen is set - like any
+         * other failure to reach a verdict.
+         * 
+         * The option is a: &lt;code&gt;long&lt;/code&gt; type.
+         * 
+         * Default: 30000
+         * Group: advanced
+         * 
+         * @param requestTimeout the value to set
+         * @return the dsl builder
+         */
+        default OpaComponentBuilder requestTimeout(long requestTimeout) {
+            doSetProperty("requestTimeout", requestTimeout);
+            return this;
+        }
+    
+        
         /**
          * Used for enabling or disabling all consumer based health checks from
          * this component.
@@ -419,6 +460,43 @@ public interface OpaComponentBuilderFactory {
             doSetProperty("failOpen", failOpen);
             return this;
         }
+    
+        /**
+         * TLS configuration for the connection to the OPA server in rest mode.
+         * Needed to trust a server whose certificate comes from a private CA,
+         * and to present a client certificate to a server that requires mutual
+         * TLS - a SPIFFE X.509-SVID, for instance, so the workload
+         * authenticates to the policy decision point as itself.
+         * 
+         * The option is a:
+         * 
&lt;code&gt;org.apache.camel.support.jsse.SSLContextParameters&lt;/code&gt; 
type.
+         * 
+         * Group: security
+         * 
+         * @param sslContextParameters the value to set
+         * @return the dsl builder
+         */
+        default OpaComponentBuilder 
sslContextParameters(org.apache.camel.support.jsse.SSLContextParameters 
sslContextParameters) {
+            doSetProperty("sslContextParameters", sslContextParameters);
+            return this;
+        }
+    
+        
+        /**
+         * Enable usage of global SSL context parameters.
+         * 
+         * The option is a: &lt;code&gt;boolean&lt;/code&gt; type.
+         * 
+         * Default: false
+         * Group: security
+         * 
+         * @param useGlobalSslContextParameters the value to set
+         * @return the dsl builder
+         */
+        default OpaComponentBuilder useGlobalSslContextParameters(boolean 
useGlobalSslContextParameters) {
+            doSetProperty("useGlobalSslContextParameters", 
useGlobalSslContextParameters);
+            return this;
+        }
     }
 
     class OpaComponentBuilderImpl
@@ -452,12 +530,16 @@ public interface OpaComponentBuilderFactory {
             case "serverUrl": getOrCreateConfiguration((OpaComponent) 
component).setServerUrl((java.lang.String) value); return true;
             case "autowiredEnabled": ((OpaComponent) 
component).setAutowiredEnabled((boolean) value); return true;
             case "borrowTimeout": getOrCreateConfiguration((OpaComponent) 
component).setBorrowTimeout((long) value); return true;
+            case "connectionTimeout": getOrCreateConfiguration((OpaComponent) 
component).setConnectionTimeout((long) value); return true;
             case "opaClient": getOrCreateConfiguration((OpaComponent) 
component).setOpaClient((com.styra.opa.OPAClient) value); return true;
             case "poolSize": getOrCreateConfiguration((OpaComponent) 
component).setPoolSize((int) value); return true;
+            case "requestTimeout": getOrCreateConfiguration((OpaComponent) 
component).setRequestTimeout((long) value); return true;
             case "healthCheckConsumerEnabled": ((OpaComponent) 
component).setHealthCheckConsumerEnabled((boolean) value); return true;
             case "healthCheckProducerEnabled": ((OpaComponent) 
component).setHealthCheckProducerEnabled((boolean) value); return true;
             case "bearerToken": getOrCreateConfiguration((OpaComponent) 
component).setBearerToken((java.lang.String) value); return true;
             case "failOpen": getOrCreateConfiguration((OpaComponent) 
component).setFailOpen((boolean) value); return true;
+            case "sslContextParameters": 
getOrCreateConfiguration((OpaComponent) 
component).setSslContextParameters((org.apache.camel.support.jsse.SSLContextParameters)
 value); return true;
+            case "useGlobalSslContextParameters": ((OpaComponent) 
component).setUseGlobalSslContextParameters((boolean) value); return true;
             default: return false;
             }
         }
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpaEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpaEndpointBuilderFactory.java
index 12c227cff31e..789bb694faa4 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpaEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpaEndpointBuilderFactory.java
@@ -274,6 +274,44 @@ public interface OpaEndpointBuilderFactory {
             doSetProperty("failOpen", failOpen);
             return this;
         }
+        /**
+         * TLS configuration for the connection to the OPA server in rest mode.
+         * Needed to trust a server whose certificate comes from a private CA,
+         * and to present a client certificate to a server that requires mutual
+         * TLS - a SPIFFE X.509-SVID, for instance, so the workload
+         * authenticates to the policy decision point as itself.
+         * 
+         * The option is a:
+         * <code>org.apache.camel.support.jsse.SSLContextParameters</code> 
type.
+         * 
+         * Group: security
+         * 
+         * @param sslContextParameters the value to set
+         * @return the dsl builder
+         */
+        default OpaEndpointBuilder 
sslContextParameters(org.apache.camel.support.jsse.SSLContextParameters 
sslContextParameters) {
+            doSetProperty("sslContextParameters", sslContextParameters);
+            return this;
+        }
+        /**
+         * TLS configuration for the connection to the OPA server in rest mode.
+         * Needed to trust a server whose certificate comes from a private CA,
+         * and to present a client certificate to a server that requires mutual
+         * TLS - a SPIFFE X.509-SVID, for instance, so the workload
+         * authenticates to the policy decision point as itself.
+         * 
+         * The option will be converted to a
+         * <code>org.apache.camel.support.jsse.SSLContextParameters</code> 
type.
+         * 
+         * Group: security
+         * 
+         * @param sslContextParameters the value to set
+         * @return the dsl builder
+         */
+        default OpaEndpointBuilder sslContextParameters(String 
sslContextParameters) {
+            doSetProperty("sslContextParameters", sslContextParameters);
+            return this;
+        }
     }
 
     /**
@@ -372,6 +410,44 @@ public interface OpaEndpointBuilderFactory {
             doSetProperty("borrowTimeout", borrowTimeout);
             return this;
         }
+        /**
+         * How long to wait for the connection to the OPA server to be
+         * established, in rest mode. The SDK's own transport applies no 
timeout
+         * at all, so a server that never answers would otherwise park the
+         * calling thread indefinitely rather than letting the component fail
+         * closed.
+         * 
+         * The option is a: <code>long</code> type.
+         * 
+         * Default: 10000
+         * Group: advanced
+         * 
+         * @param connectionTimeout the value to set
+         * @return the dsl builder
+         */
+        default AdvancedOpaEndpointBuilder connectionTimeout(long 
connectionTimeout) {
+            doSetProperty("connectionTimeout", connectionTimeout);
+            return this;
+        }
+        /**
+         * How long to wait for the connection to the OPA server to be
+         * established, in rest mode. The SDK's own transport applies no 
timeout
+         * at all, so a server that never answers would otherwise park the
+         * calling thread indefinitely rather than letting the component fail
+         * closed.
+         * 
+         * The option will be converted to a <code>long</code> type.
+         * 
+         * Default: 10000
+         * Group: advanced
+         * 
+         * @param connectionTimeout the value to set
+         * @return the dsl builder
+         */
+        default AdvancedOpaEndpointBuilder connectionTimeout(String 
connectionTimeout) {
+            doSetProperty("connectionTimeout", connectionTimeout);
+            return this;
+        }
         /**
          * An existing OPAClient to use. When set, serverUrl and bearerToken 
are
          * ignored.
@@ -439,6 +515,42 @@ public interface OpaEndpointBuilderFactory {
             doSetProperty("poolSize", poolSize);
             return this;
         }
+        /**
+         * How long to wait for the decision once connected, in rest mode. A
+         * request that times out is an evaluation failure rather than a deny,
+         * so it fails closed - or proceeds when failOpen is set - like any
+         * other failure to reach a verdict.
+         * 
+         * The option is a: <code>long</code> type.
+         * 
+         * Default: 30000
+         * Group: advanced
+         * 
+         * @param requestTimeout the value to set
+         * @return the dsl builder
+         */
+        default AdvancedOpaEndpointBuilder requestTimeout(long requestTimeout) 
{
+            doSetProperty("requestTimeout", requestTimeout);
+            return this;
+        }
+        /**
+         * How long to wait for the decision once connected, in rest mode. A
+         * request that times out is an evaluation failure rather than a deny,
+         * so it fails closed - or proceeds when failOpen is set - like any
+         * other failure to reach a verdict.
+         * 
+         * The option will be converted to a <code>long</code> type.
+         * 
+         * Default: 30000
+         * Group: advanced
+         * 
+         * @param requestTimeout the value to set
+         * @return the dsl builder
+         */
+        default AdvancedOpaEndpointBuilder requestTimeout(String 
requestTimeout) {
+            doSetProperty("requestTimeout", requestTimeout);
+            return this;
+        }
     }
 
     public interface OpaBuilders {

Reply via email to