Skip to main content

Connect Your OPA

Kamiwaza doesn't evaluate policy itself. It asks an Open Policy Agent (OPA). This page connects an OPA that you run, which 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

If you don't run an OPA, Kamiwaza can install one for you instead: see Use the OPA Kamiwaza installs.

Before you start​

You need:

For your own OPA, you also need:

  • An OPA, version 1.0 or later, 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).

The OPA should serve HTTPS. Running it with TLS, and requiring a token on its API, are covered in OPA's security guide. The OPA Kamiwaza installs needs none of this.

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.

Probe the OPA on plain /health, for readiness as well as liveness. Don't use /health?bundles for readiness: it keeps a starting OPA out of its Service until both bundles have loaded once. An OPA that restarts while the bundle token is wrong, or while Kamiwaza is down, stays out of its Service until both load. Meanwhile Kamiwaza can't reach it, so it withholds results from every data source and can't tell you why. The probe adds no safety: Kamiwaza already checks the bundle revision behind each decision, and withholds a result until the OPA has the change that applies to it.

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.

Use the OPA Kamiwaza installs​

Instead of connecting your own OPA, you can have the chart install one in Kamiwaza's namespace. It's a single replica of a FIPS OPA image that only Kamiwaza's own API and scheduler pods can reach, and the chart generates the tokens it shares with Kamiwaza. While that one pod restarts, Kamiwaza withholds results from every data source; run your own OPA if you need it highly available. Use it or your own OPA, not both. Skip steps 1 to 3 above.

Install it with policy still off, so the OPA can load the bundle before Kamiwaza depends on it. Add this under core: in your values file, and upgrade:

core:
authz:
contentPolicy:
enabled: false
localOpa:
enabled: true

Leave opa.url, opa.tokenSecretName, opa.caSecretName and bundle.tokenSecretName unset. The chart refuses to render any of them alongside localOpa.

Check that the OPA has loaded the bundle with the status command in step 4: the OPA is listed, and both its bundles are effective. Then set enabled: true, upgrade again, and run all of step 4.

Next​

Restrict a data source.