The operator creates a transient Job for each due or manually requested backup. The Job authenticates to OpenBao,
streams a Raft snapshot to object storage, and records the result on status.backup. Snapshot bytes do not pass
through the controller.
Before you begin
Prepare two independent identities:
- An OpenBao identity that can read
sys/storage/raft/snapshot. Prefer a JWT role bound to the generated<cluster>-backup-serviceaccount; usetokenSecretRefonly as a compatibility path. - An object-storage identity. Use
credentialsSecretRef, workload-identity metadata, or S3roleArn.
When self-init OIDC bootstrap is enabled, an empty jwtAuthRole resolves to openbao-operator-backup and the operator
creates the policy and role during initial bootstrap. Otherwise, configure jwtAuthRole or tokenSecretRef explicitly.
Hardened clusters also require explicit, port-scoped spec.network.egressRules and an explicit storage identity. See
Configure network policy.
Configure an S3 backup
This is the preferred minimal shape when self-init OIDC bootstrap is enabled:
Schedule an S3 snapshot
spec:
backup:
schedule: "0 3 * * *"
target:
provider: s3
endpoint: https://s3.amazonaws.com
bucket: openbao-backups
region: us-east-1
pathPrefix: clusters
credentialsSecretRef:
name: s3-backup-credentials
retention:
maxCount: 14
maxAge: 336hschedule is a five-field cron expression. The default provider is s3, but set it explicitly so intent remains
clear.
The operator persists the first scheduled run in status.backup.nextScheduledBackup before it waits for that run.
The deadline survives reconciliation and controller restarts. Check status.backup.lastBackupTime and
status.backup.lastBackupName to verify that a scheduled backup succeeds.
| Provider | Required target fields | Secret keys |
|---|---|---|
| S3 | endpoint, bucket; region defaults to us-east-1 | accessKeyId, secretAccessKey; optional sessionToken, region, caCert |
| GCS | bucket; optional gcs.project and endpoint | credentials.json |
| Azure | bucket, azure.storageAccount; optional azure.container and endpoint | accountKey or connectionString |
For platform workload identity, set target.workloadIdentity.serviceAccountAnnotations and, when required,
target.workloadIdentity.podLabels. For S3 web identity, target.roleArn also projects an STS token and configures the
Job explicitly.
Use a static OpenBao token only when needed
If JWT auth is unavailable, create a same-namespace Secret whose token value can read the Raft snapshot endpoint,
then reference it:
Reference a backup token
spec:
backup:
tokenSecretRef:
name: openbao-backup-tokenjwtAuthRole takes precedence when both fields are present. Rotate and revoke a static token as a high-sensitivity
credential.
Delegate configuration safely
The identity that changes the OpenBaoCluster needs:
geton each referenced Secretusecloudidentitieson the cluster when it setsroleArnor workload-identity metadatausecustomexecutableson the cluster when it overridesspec.backup.image(usehelperimagesremains a compatibility alias)
Admission rejects loopback and link-local storage endpoints. Hardened clusters also reject insecure TLS and ambient storage identity.
Trigger and verify a backup
The operator does not create a CronJob. Trigger an immediate backup by changing the one-shot annotation value:
Request a manual backup
kubectl -n <namespace> annotate openbaocluster <name> \
openbao.org/trigger-backup="$(date -u +%Y-%m-%dT%H:%M:%SZ)" --overwriteThe controller clears the annotation after accepting the request. It skips a duplicate request while another backup Job is active.
Inspect backup readiness and outcome
kubectl -n <namespace> get openbaocluster <name> \
-o jsonpath='{range .status.conditions[?(@.type=="BackupConfigurationReady")]}{.status}{" "}{.reason}{"\n"}{.message}{"\n"}{end}'
kubectl -n <namespace> get openbaocluster <name> -o jsonpath='{.status.backup}' | jq
kubectl -n <namespace> get jobs -l openbao.org/cluster=<name>A successful run advances lastBackupTime, lastBackupName, lastBackupSize, and lastBackupDuration. Failure
details are in lastFailureReason, lastFailureMessage, and lastFailureTime. Confirm the object independently in
storage before relying on it.
If the snapshot stream fails during upload, the executor aborts the write, so the failed snapshot creates no object. After upload, it checks that the stored object size matches the number of bytes streamed and deletes the object if they differ. That deletion can fail on object-lock or write-only buckets, so check for leftover objects after a failed run.
Set retention and pre-upgrade snapshots
maxCount: 0 and an empty maxAge mean unlimited retention. The operator applies retention after a successful
upload and never turns a retention error into a failed snapshot. Retention always keeps the newest snapshot and the
snapshot recorded in status.backup.lastBackupName, even when they are older than maxAge. Snapshot object keys use
the time the backup Job was created, so a backup delayed past its schedule is not treated as old.
Retention only manages scheduled and manual snapshots stored directly under the cluster prefix. It leaves pre-upgrade and blue-green phase snapshots, nested objects, and any other files in that prefix untouched. Remove those by hand or with storage lifecycle rules.
Enable spec.upgrade.preUpgradeSnapshot: true to require a snapshot before either upgrade strategy. Blue-green also
accepts spec.upgrade.blueGreen.preUpgradeSnapshot, but the top-level field keeps one policy across strategies. The
upgrade does not continue if its required snapshot fails.
A backup is complete only after you restore it into an isolated target and validate the recovered data.