Initialize the cluster

Define self-init requests, usable human access, operator JWT authentication, and recovery-key custody.

Updated 9 August 2026 · 5 min read

On this page

Use self-init to apply one-time bootstrap requests and revoke the bootstrap root token. Before enabling it, define a complete human login path and the recovery procedure for that path.

Choose the initialization path

PathUse it whenRoot-token behavior
Self-initRequired for Hardened; preferred when bootstrap state is declarativeOpenBao revokes the bootstrap root token after the requests complete; the operator does not create a root-token Secret
Standard initDisposable Development clusters and controlled compatibility workThe operator can store the root token in an immutable Kubernetes Secret

Self-init is a one-time bootstrap mechanism. It does not continuously reconcile OpenBao auth methods, policies, secret engines, audit devices, or upstream workflow definitions.

Define access before self-init

Bootstrap these surfaces together:

  1. Choose the human authentication method and external identity owner.
  2. Add requests that enable the auth method, configure it, create the policy, and bind a role or user to that policy.
  3. Add any secret engines and audit devices required at first login.
  4. Enable selfInit.oidc if the operator and lifecycle Jobs will authenticate with projected Kubernetes JWTs.
  5. Configure initial recovery keys when a non-static auto-unseal cluster needs a generate-root recovery path.

selfInit.oidc is only for operator lifecycle access. It does not create a human login path.

This fragment shows the structured request forms. It is not a complete access configuration because every identity provider has different issuer, claim, redirect, group, and role requirements.

configure

Build the self-init request list

spec:
  selfInit:
    enabled: true
    oidc:
      enabled: true
    requests:
      - name: enable-human-auth
        operation: update
        path: sys/auth/<human-auth-mount>
        authMethod:
          type: <jwt-or-kubernetes-or-other-supported-type>

      - name: create-platform-policy
        operation: update
        path: sys/policies/acl/platform-operator
        policy:
          policy: |
            <least-privilege-policy>

      - name: configure-human-auth
        operation: update
        path: auth/<human-auth-mount>/config
        data:
          <provider-specific-non-secret-configuration>

      - name: bind-human-role
        operation: update
        path: auth/<human-auth-mount>/role/<role-name>
        data:
          <provider-specific-role-and-policy-binding>

Replace every placeholder. Test the same issuer, claims, group mapping, redirect URIs, and policy binding in a disposable cluster before using the manifest for production.

Use the structured request fields

Each request has a unique name, an operation, and an OpenBao API path. Use at most 64 requests; request names must be unique and paths can contain at most 256 characters.

FieldUse it for
authMethodEnable an auth mount through sys/auth/*
policyCreate or update an ACL policy through sys/policies/*
secretEngineEnable a mount through sys/mounts/*
auditDeviceEnable an audit device through sys/audit/*
dataSend an object payload when no structured field exists
allowFailureContinue initialization after an optional request fails

Supported operations are create, read, update, patch, delete, and list.

Use allowFailure only for genuinely optional state. An authentication, policy, audit, or recovery request that is part of the access contract must fail the bootstrap when it cannot be applied.

Configure operator JWT authentication

Enable operator OIDC bootstrap inside the complete self-init block:

configure

Add operator OIDC bootstrap

spec:
  selfInit:
    enabled: true
    oidc:
      enabled: true
      # Optional compatibility overrides:
      # issuer: "https://<kubernetes-issuer>"
      # audience: "openbao-internal"
    requests:
      - <complete-human-access-request-set>

The operator creates lifecycle roles for controller, backup, upgrade, and restore work as needed. Keep these values aligned:

  • The operator ServiceAccount must be allowed to read the Kubernetes OIDC discovery and JWKS non-resource URLs.
  • selfInit.oidc.audience, when set, must match the installation-scoped OPENBAO_JWT_AUDIENCE. It cannot define a per-cluster audience.
  • Manually managed roles must bind the rendered controller and Job ServiceAccount identities, not guessed defaults.

Review operator authentication and operator authorization before replacing any generated role.

Create initial recovery keys

Use spec.recoveryKeys.initial only with self-init and a non-static unseal provider. Set threshold no higher than shares, and provide exactly one recipient for every share.

configure

Declare initial recovery-key custody

spec:
  recoveryKeys:
    initial:
      shares: 3
      threshold: 2
      recipients:
        - name: platform-custodian
          fingerprint: "0123456789ABCDEF0123456789ABCDEF01234567"
          pgpPublicKey: "<base64-encoded-binary-openpgp-public-key>"
        - name: security-custodian
          fingerprint: "89ABCDEF0123456789ABCDEF0123456789ABCDEF"
          pgpPublicKey: "<base64-encoded-binary-openpgp-public-key>"
        - name: recovery-custodian
          fingerprint: "FEDCBA9876543210FEDCBA9876543210FEDCBA98"
          pgpPublicKey: "<base64-encoded-binary-openpgp-public-key>"

The operator renders an authenticated sys/rotate/recovery/init request with backup=true. It does not distribute encrypted shares, store decrypted shares, escrow key material, or run generate-root ceremonies.

Verify every fingerprint out of band. Retrieve the encrypted backup through an approved access path, confirm each custodian can decrypt their share, record custody evidence, and remove the temporary backup from OpenBao.

Verify bootstrap and access

  1. Wait for the operator to observe self-initialization.

    verify

    Check self-init status

    kubectl -n <namespace> get openbaocluster <name> \
         -o jsonpath='{.status.selfInitialized}{"\n"}'
  2. Inspect UserAccessBootstrap, ProductionReady, and the other status conditions.

    inspect

    Inspect bootstrap conditions

    kubectl -n <namespace> get openbaocluster <name> \
         -o jsonpath='{range .status.conditions[*]}{.type}={.status}{"\t"}{.reason}{"\t"}{.message}{"\n"}{end}'
  3. Sign in through the human authentication method with a non-bootstrap identity.

  4. Read one allowed path and confirm one disallowed path is denied.

  5. If operator OIDC is enabled, run a lifecycle authentication check before depending on backup or upgrade Jobs.

  6. Complete and record the recovery-share custody test.

status.selfInitialized: true means the operator observed an initialized and unsealed cluster. The user-access condition is a best-effort recognition signal. Neither one performs a real human login or authorization test.

Continue with unseal.

Search the handbook

Try “install”, “threat model”, or “compatibility”.