Keep controller auth short-lived, bound, and boring.
The operator authenticates to OpenBao with a projected Kubernetes ServiceAccount token by default. That path is safer than static root credentials, but it only stays safe when the rendered controller identity, JWT audience, and OpenBao-side role binding still match.
Diagram
Default operator auth path
Kubernetes issues a projected token for the controller. OpenBao validates that token against the configured JWT auth method and returns a scoped operator token for maintenance work.
Decision matrix
Why the JWT path is the default
| Property | What you get | Why it matters |
|---|---|---|
| No stored root token | The controller authenticates with a projected ServiceAccount token instead of a long-lived Secret. | You avoid carrying a static high-privilege credential in Kubernetes just to let the operator do day 2 work. |
| Automatic rotation | Kubernetes rotates the projected token on its own schedule. | Controller auth ages out naturally instead of depending on manual token rotation discipline. |
| Audience binding | The token is scoped to OPENBAO_JWT_AUDIENCE, which defaults to openbao-internal. | A token issued for OpenBao auth should not be replayable against unrelated services. |
| Scoped maintenance policy | The JWT role returns a token with the operator maintenance policy, not blanket admin privileges. | The controller gets the capabilities it needs for health checks, step-down, and autopilot without widening normal access. |
spec.selfInit.oidc.enabled: true bootstraps the controller auth path only.
It does not create a human login method by itself.
If people need access after first boot, add that through selfInit.requests or another explicit access path.
Self-init and manual bootstrap
Decision matrix
Choose the bootstrap path
| Path | Use it when | Operator behavior | Watch for |
|---|---|---|---|
| Self-init with OIDC | You want the supported production path and the cluster is allowed to bootstrap its own operator auth surface. | The operator configures JWT auth, discovery, the openbao-operator policy, and the bound role automatically. | Still add a human login path separately before you expose the cluster. |
| Manual JWT configuration | You are carrying a compatibility workflow, a custom install shape, or a controlled bootstrap sequence. | You create the JWT auth method, policy, and role binding yourself. | Rendered ServiceAccount name, namespace, and audience drift are the usual breakpoints. |
Configure
The operator policy is intentionally narrow
path "sys/health" {
capabilities = ["read"]
}
path "sys/step-down" {
capabilities = ["sudo", "update"]
}
path "sys/storage/raft/autopilot/configuration" {
capabilities = ["read", "update"]
}
Keep the controller policy focused on maintenance work. Backup, restore, and upgrade jobs should authenticate through their own roles instead of inheriting the controller scope.
Configure
Manual JWT role example for a custom controller identity
bao write auth/jwt-operator/role/openbao-operator \
role_type="jwt" \
bound_audiences="openbao-internal" \
user_claim="sub" \
bound_subject="system:serviceaccount:platform-security:demo-openbao-operator-controller" \
token_policies="openbao-operator" \
token_ttl="1h"
Replace the namespace, ServiceAccount name, and audience with the values produced by your rendered install, not the defaults from an example manifest.
What must stay aligned
Reference table
Custom-install checks
| Surface | Must match | What breaks when it drifts |
|---|---|---|
| Controller identity | Rendered controller ServiceAccount name and operator namespace | The OpenBao JWT role or admission-policy identity references the wrong controller subject. |
| Projected token mount | The controller Deployment still mounts the openbao-token projected volume | The controller loses its default path to authenticate to OpenBao at all. |
| JWT audience | OPENBAO_JWT_AUDIENCE, the projected token audience, and the OpenBao role bound_audiences | A valid ServiceAccount token is rejected because it was issued for a different audience contract. |
| Discovery access | The controller can reach /.well-known/openid-configuration and the JWKS endpoint | OpenBao cannot validate the projected token even though the controller identity itself is correct. |
Reference table
Typical auth failures
| Symptom | Most likely cause | Check first |
|---|---|---|
permission denied when the controller calls OpenBao | JWT audience mismatch or an incorrect bound subject | Rendered identity and OPENBAO_JWT_AUDIENCE alignment |
| Self-init completes but controller auth never settles | OIDC discovery is unreachable or incomplete | Kubernetes API discovery reachability and cluster condition output |
| Backup or restore auth fails even though controller auth works | Executor jobs use separate roles and ServiceAccounts | Operator authorization and the job-specific auth path |
Continue the support path
Official OpenBao background
This version tracks a prerelease build. Features and behavior may change before the next stable release.
Was this page helpful?
Use Needs work to open a structured GitHub issue for this page. The Yes button only acknowledges the signal locally.