Skip to main content
Version: next

Decision matrix

Choose the bootstrap path deliberately

Choose the bootstrap path deliberately.
PathUse it whenWhat happens to the root tokenWatch for
Standard initYou need a temporary compatibility path for development or controlled manual setup.A root token can be created and stored in a Secret.This is easier to start with, but it leaves you with a stronger credential-management burden afterward.

Diagram

Self-init bootstrap flow

The cluster initializes, applies the declared requests, and then revokes the bootstrap credential instead of treating it as a permanent operating dependency.

Plan the access path before enabling self-init

If self-init is enabled and no usable auth method exists for operators or humans, the root token is revoked and the cluster can become effectively unreachable unless it is recreated.

Decision matrix

Bootstrap both access surfaces together

Bootstrap both access surfaces together.
Access surfaceWhere it livesWhat must be true before first reconcile
Human login pathspec.selfInit.requestsCreate at least one usable auth method and policy path for people before the root token is revoked.
Initial recovery keysspec.recoveryKeys.initialDeclare the OpenPGP recipients, share count, and threshold when auto-unseal clusters need recovery keys created during self-init.
Define operator and human access in the same bootstrap contract

If the cluster will self-initialize, define the human login path in selfInit.requests as part of the same manifest that enables operator auth.

Enable self-init

Configure

Start from the minimum self-init block

yaml

spec:
selfInit:
enabled: true
requests:
- name: enable-audit
operation: update
path: sys/audit/file
auditDevice:
type: file
fileOptions:
filePath: /tmp/audit.log

requests defines the bootstrap state. Include the minimum auth, policy, and audit configuration the cluster needs immediately after initialization.

Configure

Pair operator OIDC bootstrap with a human auth path

yaml

spec:
selfInit:
enabled: true
oidc:
enabled: true
requests:
- name: enable-userpass-auth
operation: update
path: sys/auth/userpass
authMethod:
type: userpass
- name: create-admin-policy
operation: update
path: sys/policies/acl/admin
policy:
policy: |
path "*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# Add your user, JWT role, or Kubernetes auth role here so a real human
# login path exists before the root token is revoked.

The exact human auth method is your choice, but it belongs inside the same selfInit contract. For a complete worked example, see the development self-init userpass recipe.

Create initial recovery keys

For auto-unseal clusters, self-init starts without recovery keys. Use spec.recoveryKeys.initial when you want the Operator to render the initial authenticated recovery-key creation request during self-init.

Configure

Declare initial recovery-key recipients

yaml

spec:
unseal:
type: awskms
selfInit:
enabled: true
recoveryKeys:
initial:
shares: 5
threshold: 3
recipients:
- name: provider-platform-lead
fingerprint: "0123456789ABCDEF0123456789ABCDEF01234567"
pgpPublicKey: "<base64-encoded-binary-openpgp-public-key>"
- name: provider-security-lead
pgpPublicKey: "<base64-encoded-binary-openpgp-public-key>"
# add exactly five recipients total

The Operator renders this as sys/rotate/recovery/init with backup=true so encrypted shares can be retrieved from OpenBao after bootstrap.

Custody remains outside the Operator

The Operator does not distribute encrypted shares, store decrypted shares, escrow key material, or run generate-root ceremonies. Verify fingerprints out of band, retrieve the encrypted backup through an approved access path, confirm custody with each recipient, and delete the temporary backup from OpenBao.

What belongs in requests

Reference table

Structured request surfaces

Structured request surfaces.
SurfaceUse it forTypical example
policyCreate ACL policies that your auth methods will bind to.Policies for apps, operators, or bootstrap-only roles.
secretEngineEnable mounts such as KV or transit.Initial application secret storage or cryptography services.
auditDeviceTurn on audit logging at bootstrap time.File or stdout audit devices required by your environment.
dataFallback for raw API payloads when no structured field exists.Specialized configuration that is not covered by the higher-level request fields yet.
headersAdd HTTP headers to a bootstrap request.Header-based auth or routing controls for a specific request.
whenGate a bootstrap request statically or through an OpenBao profile value.Skip optional setup unless a profile expression evaluates to true.
Do not embed raw secrets in requests

Avoid placing passwords, tokens, or key material directly in the manifest. Use Kubernetes Secrets where supported and treat bootstrap content like the rest of your GitOps security surface.

Use OpenBao profile request controls

OpenBao 2.6.0 and newer versions evaluate self-init through the profile engine. The operator exposes the request-level headers and when controls for that path. Use them only with OpenBao versions that support profile-engine self-init request fields; older OpenBao versions may reject or ignore these fields.

Configure

Gate a request and add request headers

yaml

- name: configure-optional-system
operation: update
path: sys/config/example
headers:
X-Bootstrap-Source:
- operator
when:
eval_source: cel
eval_type: bool
expression: "true"
data:
enabled: true

headers renders as OpenBao's map[string][]string request headers. when accepts either a boolean or an OpenBao profile value object that evaluates to a boolean.

Workflow ownership stays separate

OpenBao's profile engine is also used by the upstream workflows API. The operator does not currently reconcile OpenBao workflow definitions or expose workflow CRDs. Use self-init for one-time bootstrap state and manage day-2 OpenBao workflows through a deliberate external process until an operator ownership model exists.

Bootstrap operator OIDC roles

Configure

Enable operator OIDC bootstrap

yaml

spec:
selfInit:
enabled: true
oidc:
enabled: true
# Optional:
# issuer: "https://..."
# audience: "openbao-internal"

This bootstraps operator-only JWT auth roles for lifecycle work such as backup, upgrade, and restore. It does not create human login paths by itself.

Reference table

What must stay aligned

What must stay aligned.
SurfaceWhy it mattersWhat to align
JWT audienceThe role binding inside OpenBao and the projected token audience must match.Keep spec.selfInit.oidc.audience aligned with the installation-scoped OPENBAO_JWT_AUDIENCE value.
Rendered controller identityCustom namespace or name-prefix changes affect the ServiceAccount subject the JWT role expects.If you manage roles manually, bind them to the rendered controller ServiceAccount identity rather than to a guessed default.

Common bootstrap patterns

Configure

Enable a JWT auth method

yaml

- name: enable-jwt
operation: update
path: sys/auth/jwt-operator
authMethod:
type: jwt
description: "Kubernetes JWT auth"
config:
default_lease_ttl: "1h"
max_lease_ttl: "24h"

Verify the cluster finished bootstrap

Verify

Check the self-init status bit

bash

kubectl get openbaocluster <name> -o jsonpath='{.status.selfInitialized}'

A healthy bootstrap should report true. If it does not, inspect the cluster status conditions and controller logs before retrying with additional requests.

Continue cluster baseline

Next release documentation

You are reading the unreleased main docs. Use the version menu for the newest published release, or check the release notes for what is already out.

Was this page helpful?

Use Needs work to open a structured GitHub issue for this page. The Yes button only acknowledges the signal locally.