Connect Your OPA
Kamiwaza doesn't evaluate policy itself. It asks an Open Policy Agent (OPA) that you run. Connecting them takes two directions:
- Your OPA pulls from Kamiwaza. It downloads Kamiwaza's policy bundles, and reports which revision it has loaded.
- Kamiwaza calls your OPA. It asks for a decision on each connector result.
| Step | What |
|---|---|
| 1 | Create the tokens and Secrets |
| 2 | Add Kamiwaza's bundles to your OPA's configuration |
| 3 | Turn policy on in Kamiwaza |
| 4 | Check that the OPA has the bundle and Kamiwaza is enforcing |
Before you start
You need:
- An OPA, version 1.0 or later, that you run and that will stay up. If you don't run one yet, see OPA's deployment guide.
- Network routes both ways: the OPA reaches Kamiwaza's HTTPS address, and the
Kamiwaza cluster reaches the OPA's REST API (port
8181by default). - Your Kamiwaza values file, and
kubectlaccess to the namespace Kamiwaza is installed in. This page useskamiwaza. kapi, set up as in Run Your Own Connector: Before you start.
The OPA should serve HTTPS. Running it with TLS, and requiring a token on its API, are covered in OPA's security guide.
Step 1: Create the tokens and Secrets
There are two tokens, one for each direction. Generate them yourself; any long random string works.
BUNDLE_TOKEN=$(openssl rand -hex 32) # the OPA presents this to Kamiwaza
OPA_TOKEN=$(openssl rand -hex 32) # Kamiwaza presents this to the OPA
Store them, and the CA that signs the OPA's certificate, in Kamiwaza's namespace:
printf '%s' "$BUNDLE_TOKEN" | kubectl -n kamiwaza create secret generic \
kamiwaza-policy-bundle-token --from-file=token=/dev/stdin
printf '%s' "$OPA_TOKEN" | kubectl -n kamiwaza create secret generic \
kamiwaza-policy-opa-token --from-file=token=/dev/stdin
kubectl -n kamiwaza create secret generic kamiwaza-policy-opa-ca \
--from-file=ca.crt=<the CA file for your OPA's certificate>
Skip the CA Secret if the OPA's certificate is signed by a public CA. Skip the OPA token if your OPA doesn't require one.
Give BUNDLE_TOKEN to your OPA (step 2). If your OPA requires a token, add
OPA_TOKEN to the tokens its authorization policy accepts. That policy is
yours; see OPA's
authentication and authorization
guide.
Step 2: Configure your OPA
Add Kamiwaza as a service, its two bundles, and status reporting to your OPA's configuration file:
services:
kamiwaza:
url: https://<YOUR_KAMIWAZA_DOMAIN>/api/authz/policies
credentials:
bearer:
token: "${KAMIWAZA_POLICY_BUNDLE_TOKEN}"
# If Kamiwaza's certificate comes from your own CA:
# tls:
# ca_cert: /path/to/kamiwaza-ca.crt
bundles:
kamiwaza:
service: kamiwaza
resource: bundle
polling:
min_delay_seconds: 5
max_delay_seconds: 15
long_polling_timeout_seconds: 60
kamiwaza_drafts:
service: kamiwaza
resource: drafts/bundle
polling:
min_delay_seconds: 2
max_delay_seconds: 5
long_polling_timeout_seconds: 60
status:
service: kamiwaza
Set KAMIWAZA_POLICY_BUNDLE_TOKEN to BUNDLE_TOKEN in the OPA's environment,
for example from a Secret in the OPA's own namespace.
What each part does:
| Part | Why it's needed |
|---|---|
bundles.kamiwaza | The live templates and constraints. With long polling, Kamiwaza answers as soon as a change is published, so changes take effect in seconds. |
bundles.kamiwaza_drafts | Templates and constraints you are trying out. The OPA compiles them before they go live. Leave it out and drafts never compile, so you can't dry-run or add templates of your own. |
status | The OPA tells Kamiwaza which revision it has active. Kamiwaza needs this to know a change is in force, and to mark drafts as compiled. |
Both bundles only write under their own names (kamiwaza and
kamiwaza_drafts), so they sit alongside any policies the OPA already has.
The option names are OPA's: see Configuration and Bundles.
Restart or reload the OPA. Until you finish step 3, its log shows errors such
as Bundle load failed: server replied with Unauthorized or status update failed, because Kamiwaza doesn't have its token yet. That's expected.
A readiness probe on /health?bundles reports ready only once both bundles have
loaded. Until then, Kubernetes keeps the OPA out of its Service, so Kamiwaza
can't reach it either.
Step 3: Turn policy on in Kamiwaza
Add this under core: in your values file. If you skipped the CA Secret or the
OPA token Secret in step 1, set its caSecretName or tokenSecretName to "".
A name for a Secret that doesn't exist stops Kamiwaza's pods from starting.
core:
authz:
contentPolicy:
enabled: true
opa:
url: https://<YOUR_OPA_ADDRESS>:8181
caSecretName: kamiwaza-policy-opa-ca # "": the system CAs
tokenSecretName: kamiwaza-policy-opa-token # "": no token sent
bundle:
tokenSecretName: kamiwaza-policy-bundle-token
Then upgrade with the same command and values file you installed with, for example:
helm upgrade --install kamiwaza \
oci://ghcr.io/kamiwaza-ai/releases/kamiwaza/charts/kamiwaza \
--version <version> --namespace kamiwaza \
--values kamiwaza-values.yaml --timeout 70m
Optional values, which you rarely need to change:
| Value | Default | Notes |
|---|---|---|
core.authz.contentPolicy.opa.timeoutSeconds | 2 | The longest Kamiwaza waits for one decision. Past it, the result is withheld. |
core.authz.contentPolicy.maxBatchRecords | 200 | Records sent per decision. Larger results are split into several calls. |
Step 4: Check
Ask Kamiwaza whether it can reach the OPA and whether the OPA has its bundle:
kapi GET /authz/policies/health | jq '{enabled, reachable, bundle_loaded, enforcing, active_revision, latest_revision, error}'
Check: enabled, reachable, bundle_loaded and enforcing are all
true, and active_revision equals latest_revision.
Then see what each OPA instance reports:
kapi GET /authz/policies/status \
| jq '{latest_revision, instances: [.instances[] | {instance_id, opa_version, reported_at, bundles: (.bundles | map_values({active_revision, state, message}))}]}'
Check: your OPA is listed, and both its bundles are effective. The
kamiwaza bundle's active_revision is a number; the kamiwaza_drafts
bundle's is a long hash, which is normal.
If you run several OPA replicas, each one reports separately. Each OPA restart
gets a new instance_id, and an instance that stops reporting stays listed for
about 10 minutes before it drops off.
If a check fails, see Troubleshooting.