Skip to main content

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.
StepWhat
1Create the tokens and Secrets
2Add Kamiwaza's bundles to your OPA's configuration
3Turn policy on in Kamiwaza
4Check 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 8181 by default).
  • Your Kamiwaza values file, and kubectl access to the namespace Kamiwaza is installed in. This page uses kamiwaza.
  • 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:

PartWhy it's needed
bundles.kamiwazaThe live templates and constraints. With long polling, Kamiwaza answers as soon as a change is published, so changes take effect in seconds.
bundles.kamiwaza_draftsTemplates 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.
statusThe 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:

ValueDefaultNotes
core.authz.contentPolicy.opa.timeoutSeconds2The longest Kamiwaza waits for one decision. Past it, the result is withheld.
core.authz.contentPolicy.maxBatchRecords200Records 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.

Next​

Restrict a data source.