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.
| 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 |
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:
- 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.
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
8181by 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:
| 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.
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:
| 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.
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.