Skip to main content
Version: next

This recipe should leave you with

  • an infra cluster that hosts shared trust services and the shared Transit key
  • a healthy source cluster and target cluster with distinct namespaces and external endpoints
  • shared RustFS storage available to both clusters for snapshot transfer
  • known pre-restore state on both sides so the restore event can be verified later
Validated lane

This bootstrap path matches the local DR lane that was proven end to end on March 16, 2026, including source backup, restore into the target cluster, target unseal, and credential plus data verification after restore.

Decision matrix

What this lane assumes

What this lane assumes.
AssumptionWhy it existsWhat breaks if it is wrong
You have bootstrap automation or manifests for the three-cluster labThe validated lane was assembled from repeatable infra, gateway, and operator setup rather than ad hoc kubectl edits.Without repeatable bootstrap artifacts, the restore result is hard to trust or reproduce.
Shared Transit and shared storage are available before cluster applySource and target clusters both depend on them from the start.The restore will fail later if these dependencies are improvised after the source cluster is already in use.
Cutover remains manualThe bootstrap only prepares the recovery pair; it does not automate failover.Treating the lane as automatic DR creates false confidence in behavior it does not validate.

Reference table

Validated lane defaults

Validated lane defaults.
ValueDefaultPurpose
Infra contextk3d-openbao-dr-infraShared trust-services cluster.
Source contextk3d-openbao-dr-sourcePrimary cluster that creates the snapshot.
Target contextk3d-openbao-dr-targetRecovery target cluster.
Source hostnamebao-dr-source.example.comSource passthrough endpoint.
Target hostnamebao-dr-target.example.comTarget passthrough endpoint.
Transit endpointhttps://host.k3d.internalShared trust-services endpoint.
Snapshot bucketopenbao-dr-backupsShared RustFS bucket.
Transit keyopenbao-dr-shared-unsealShared seal root used by both clusters.

Step 1: Bootstrap the three-cluster lab

Configure

Run the bootstrap automation or manifests you keep for the validated lane

text

The validated bootstrap needs to create and wire:
- one infra cluster for shared trust services
- one source cluster
- one target cluster
- the Gateway API experimental bundle in each cluster
- a dedicated passthrough edge in each cluster
- a shared RustFS instance and bucket
- a shared external OpenBao trust-services endpoint in the infra cluster
- one operator install in the source cluster
- one operator install in the target cluster

The exact command is specific to your k3d automation. The lane contract is the resulting topology, not the name of one local helper script.

Validated defaults

The validated local proof used the public signed edge images by default:

  • ghcr.io/dc-tec/openbao-operator:edge
  • ghcr.io/dc-tec/openbao-backup:edge

Step 2: Apply the source and target clusters

Apply

Apply the source and target OpenBaoCluster manifests

bash

kubectl --context <source-context> apply -f source-openbaocluster.yaml
kubectl --context <target-context> apply -f target-openbaocluster.yaml

The source and target manifests must both reference the same Transit endpoint, CA bundle, SNI, and key name. That shared seal root is the invariant the restore event depends on.

Verify the bootstrap

Verify

Check source and target readiness

bash

kubectl --context k3d-openbao-dr-source -n openbaocluster-dr-source \
get openbaocluster openbaocluster-dr-source \
-o jsonpath='{.status.phase}{"\n"}{.status.readyReplicas}{"\n"}{range .status.conditions[*]}{.type}={.status}{" reason="}{.reason}{"\n"}{end}'

kubectl --context k3d-openbao-dr-target -n openbaocluster-dr-target \
get openbaocluster openbaocluster-dr-target \
-o jsonpath='{.status.phase}{"\n"}{.status.readyReplicas}{"\n"}{range .status.conditions[*]}{.type}={.status}{" reason="}{.reason}{"\n"}{end}'

The important steady-state expectation on both sides is phase=Running, readyReplicas=1, Available=True, OpenBaoInitialized=True, and OpenBaoSealed=False.

Verify

Check the source and target health endpoints

bash

curl -ksS --resolve bao-dr-source.example.com:10443:127.0.0.1 \
https://bao-dr-source.example.com:10443/v1/sys/health

curl -ksS --resolve bao-dr-target.example.com:11443:127.0.0.1 \
https://bao-dr-target.example.com:11443/v1/sys/health

Verify

Verify the pre-restore source and target state

bash

SOURCE_TOKEN="$(
curl -ksS --resolve bao-dr-source.example.com:10443:127.0.0.1 \
-H 'Content-Type: application/json' \
-d '{"password":"source-demo-password"}' \
https://bao-dr-source.example.com:10443/v1/auth/userpass/login/demo-admin \
| jq -r '.auth.client_token'
)"

TARGET_TOKEN="$(
curl -ksS --resolve bao-dr-target.example.com:11443:127.0.0.1 \
-H 'Content-Type: application/json' \
-d '{"password":"target-demo-password"}' \
https://bao-dr-target.example.com:11443/v1/auth/userpass/login/demo-admin \
| jq -r '.auth.client_token'
)"

curl -ksS --resolve bao-dr-source.example.com:10443:127.0.0.1 \
-H "X-Vault-Token: ${SOURCE_TOKEN}" \
https://bao-dr-source.example.com:10443/v1/secret/data/dr-control

curl -ksS --resolve bao-dr-target.example.com:11443:127.0.0.1 \
-H "X-Vault-Token: ${TARGET_TOKEN}" \
https://bao-dr-target.example.com:11443/v1/secret/data/dr-control

The validated lane starts with phase1-source on the source side and phase1-target on the target side so the restore event can prove that target state was really replaced.

Continue the DR rehearsal

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.