Managing OpenBao secrets for a tenant
This tutorial walks through writing, reading, listing, and removing secrets in OpenBao using the bao CLI, based on the tenant-demo reference setup. It can be fully validated on a local cluster started with task run-local; everything below assumes that, but works identically against any environment with the tenant-demo Flux Kustomizations reconciled.
Prerequisites
- The
baoCLI, installed via Mise as part of this repo's pinned tool versions (mise trust && mise install). kubectlaccess to the cluster.- The cluster's OpenBao and
tenant-demoFlux Kustomizations already reconciled, so thetenant-demorole/policy andSecretStoreexist.
Connecting to OpenBao
Port-forward the OpenBao service and point the CLI at it:
kubectl port-forward -n openbao svc/openbao 8200:8200
In another terminal:
export BAO_ADDR=http://127.0.0.1:8200
bao login
it's also possible to use the UI to insert secrets. Once you've setup the port forward, just go to http://127.0.0.1:8200 in your browser.
bao login needs a token:
-
On a local (dev-mode) cluster, the fixed dev root token is
root. -
On an HA-mode cluster (any non-local overlay), retrieve the generated root token:
kubectl get secret -n openbao openbao-init-credentials -o jsonpath='{.data.init\.json}' \
| base64 -d | jq -r '.root_token'
This is the root token, so don't leave it cached in your shell any longer than you need it for.
Writing a secret
tenant-demo's OpenBao role only grants access to the secret/tenant-demo/* path prefix, so any secret you want its SecretStore to read has to be written under that prefix. The tenant-demo overlays already ship an ExternalSecret (openbao-example) that expects a key at tenant-demo/example-secret with properties foo1 and foo2 (see tenants/tenant-demo/overlays/local/example-secret.yaml). Write it with bao kv put:
bao kv put -mount=secret tenant-demo/example-secret foo1=bar1 foo2=bar2
Verifying the sync
Once written, the ExternalSecret picks it up on its next refresh (refreshInterval: 15s):
kubectl get externalsecret -n tenant-demo openbao-example
NAME STORE REFRESH INTERVAL STATUS READY
openbao-example openbao-backend 15s SecretSynced True
And the materialized Kubernetes Secret (secret-from-bao-via-extsecrets) now holds that data:
kubectl get secret -n tenant-demo secret-from-bao-via-extsecrets -o jsonpath='{.data.foo1}' | base64 -d
bar1
Reading a secret
bao kv get -mount=secret tenant-demo/example-secret
Add -field=<key> to print a single value, e.g. bao kv get -mount=secret -field=foo1 tenant-demo/example-secret.
Listing secrets
bao kv list -mount=secret tenant-demo/
Removing a secret
bao kv delete -mount=secret tenant-demo/example-secret
This is a soft delete (KV v2 keeps prior versions). To permanently remove all versions and metadata:
bao kv metadata delete -mount=secret tenant-demo/example-secret
Deleting tenant-demo/example-secret will make openbao-example's next sync fail until the key exists again, since that ExternalSecret depends on it.