Installing the Operator

The operator runs alongside the openZro control plane in the same or a different Kubernetes cluster. It needs:

  • Network reachability to the management API
  • A Personal Access Token (PAT) with permissions to manage groups / policies / setup keys / resources

This guide assumes you've already deployed the openZro control plane via the Helm Quickstart.

1. Issue a Personal Access Token

In the dashboard, go to Settings → Users → admin → Personal Access Tokens → Generate.

Copy the token immediately — it's shown only once. Treat it like a long-lived credential: store it in your secret manager of choice (Vault, AWS Secrets Manager, SOPS-encrypted file, etc.).

2. Store the credentials in a Kubernetes Secret

PAT="oz_pat_..."

kubectl -n openzro create secret generic openzro-operator-mgmt \
  --from-literal=managementApiUrl=https://openzro.example.com \
  --from-literal=managementApiToken="$PAT"

For GitOps workflows, encrypt this Secret with SealedSecrets, sops, or vault-csi rather than hard-coding. Operators with external secret managers point the operator at their existing Secret via existingSecret instead of creating one through kubectl create secret.

3. Install the operator chart

helm install openzro-operator openzro/openzro-operator \
  --namespace openzro \
  --set managementApiSecret=openzro-operator-mgmt

By default the chart pulls ghcr.io/openzro/openzro-operator:0.3.2-alpha.1 (multi-arch: amd64 + arm64). Pin a specific version with --set image.tag=0.3.2-alpha.1.

4. Verify

kubectl -n openzro get pods -l app.kubernetes.io/name=openzro-operator
# Expect: openzro-operator-... Running

kubectl -n openzro logs -l app.kubernetes.io/name=openzro-operator --tail=20
# Expect: "starting manager", no auth errors against the management API

A successful first reconcile log line looks like:

INFO	controllers.ozgroup	Reconciled
INFO	controllers.ozpolicy	Reconciled

If you see 401 Unauthorized against the management API, the PAT is wrong or expired. Re-issue from the dashboard.

Apply your first CR

# my-group.yaml
apiVersion: openzro.io/v1
kind: OZGroup
metadata:
  name: backend-team
  namespace: openzro
spec:
  name: "Backend Team"
kubectl apply -f my-group.yaml
kubectl get ozgroups
# NAME            STATUS
# backend-team    Reconciled

The same pattern applies to OZPolicy, OZSetupKey, OZResource, OZRoutingPeer — see the CRDs reference.

Upgrading

helm repo update
helm upgrade openzro-operator openzro/openzro-operator \
  --namespace openzro \
  --set managementApiSecret=openzro-operator-mgmt

CRDs aren't upgraded by helm upgrade. After every operator chart bump, re-apply them:

helm pull openzro/openzro-operator --untar --untardir /tmp/op
kubectl apply -f /tmp/op/openzro-operator/crds/

Uninstalling

# 1. Delete CRs first (operator releases the management-side
#    objects through finalizers)
kubectl delete ozgroups,ozpolicies,ozsetupkeys,ozresources,ozroutingpeers --all -n openzro

# 2. Uninstall the operator chart
helm uninstall openzro-operator -n openzro

# 3. CRDs survive helm uninstall — remove explicitly to fully clean up
kubectl delete crd ozgroups.openzro.io ozpolicies.openzro.io \
                   ozresources.openzro.io ozroutingpeers.openzro.io \
                   ozsetupkeys.openzro.io