Operating the central OpenBao (CAPVCO)¶
A single, persistent OpenBao instance provides:
- the transit key-backend the CSI driver's encrypted StorageClass
(
be.cloudbuilders.csi-encrypted-vault) uses to wrap/unwrap LUKS volume keys, and - a transit auto-unseal KMS that other Vault/OpenBao instances can seal against.
It runs on a dedicated VM in its own cloudspace (capvco-openbao, customer geert_bv_2,
location qt-gen-dc01-003), not managed by Cluster API — so no cluster teardown affects it.
Current instance (deployed 2026-07-08): https://10.101.109.245:8200 — running,
uninitialized and sealed, awaiting bao operator init. The self-signed CA is at
/etc/openbao/tls/ca.pem on the VM; deploy the driver binary is at /usr/local/bin/bao
(v2.5.5). VM access is via the portal console (or add an ingress port-forward to :22).
OpenBao dropped mlock support, so the config has no disable_mlock line and swap is disabled
on the VM instead.
- Endpoint:
https://<public-ip>:8200(L4 LB → VM:8200, TLS terminated by OpenBao) - Storage:
filebackend at/opt/openbao/data, on a dedicated data disk (survives reboots) - TLS: self-signed CA + server cert (SAN = public IP). Distribute
openbao-ca.pemto clients, or setBAO_SKIP_VERIFY=true/tls_skip_verify = true.
Client setup¶
export BAO_ADDR=https://<public-ip>:8200
export BAO_CACERT=/path/to/openbao-ca.pem # or export BAO_SKIP_VERIFY=true
bao status # shows Sealed / Initialized
First-time initialization (once)¶
bao operator init -key-shares=5 -key-threshold=3
# --> SAVE the 5 unseal keys and the initial root token in a password manager / offline.
# Losing >3 unseal keys OR the data disk = permanent data loss. There is no recovery.
bao operator unseal <key1>
bao operator unseal <key2>
bao operator unseal <key3> # threshold reached -> unsealed
bao login <root-token>
Configure the transit engine¶
bao secrets enable transit
# Key used by the CSI encrypted StorageClass (keyBackendTransitKey: csi-volume-keys):
bao write -f transit/keys/csi-volume-keys
# Key used by downstream Vault/OpenBao instances for auto-unseal:
bao write -f transit/keys/autounseal
Grant a consumer access (policy + auth)¶
Transit least-privilege policy (per key):
# csi-transit.hcl
path "transit/encrypt/csi-volume-keys" { capabilities = ["update"] }
path "transit/decrypt/csi-volume-keys" { capabilities = ["update"] }
path "transit/rewrap/csi-volume-keys" { capabilities = ["update"] }
For the CSI driver (Kubernetes auth):
bao auth enable kubernetes
# TokenReview endpoint of the WORKLOAD cluster + its CA + a reviewer token:
bao write auth/kubernetes/config \
kubernetes_host="https://<workload-apiserver>:6443" \
kubernetes_ca_cert=@workload-ca.crt \
token_reviewer_jwt=@reviewer-token
bao write auth/kubernetes/role/csi-controller \
bound_service_account_names=csi-provisioner,csi-attacher,csi-driver-registrar \
bound_service_account_namespaces=csi-driver \
policies=csi-transit ttl=1h
KEY_BACKEND_* config points KEY_BACKEND_ADDR at this
endpoint, KEY_BACKEND_TRANSIT_MOUNT=transit, KEY_BACKEND_K8S_AUTH_PATH=kubernetes,
KEY_BACKEND_K8S_ROLE=csi-controller / csi-node.)
For auto-unseal consumers, in the downstream instance's config:
seal "transit" {
address = "https://<public-ip>:8200"
token = "<token-with-transit/autounseal-access>"
key_name = "autounseal"
mount_path = "transit/"
tls_ca_cert = "/etc/openbao/openbao-ca.pem"
}
Day-2 operations¶
Unseal after a reboot¶
OpenBao starts sealed after any restart. Re-run the unseal quorum:
This central instance is the trust root, so it is intentionally manually unsealed (no chicken -and-egg auto-unseal). Keep the unseal keys accessible to whoever restarts it.Service control (on the VM)¶
Backup / restore¶
The file backend is the data disk at /opt/openbao/data.
- Backup: stop or snapshot — either take a VCO disk snapshot of the data disk, or
systemctl stop openbao && tar czf openbao-data.tgz -C /opt/openbao data && systemctl start openbao.
- Restore: restore the disk/tarball to /opt/openbao/data, start, and unseal.
- Also back up the unseal keys + root token and the CA/cert separately — the data is
useless without the unseal keys.
Rotate / rekey¶
- Rotate a transit key (new version, old ciphertext still decryptable):
bao write -f transit/keys/csi-volume-keys/rotate - Rekey unseal shares:
bao operator rekey -init -key-shares=5 -key-threshold=3 - Rotate the root token:
bao token create -policy=rootthen revoke the old one.
Upgrade¶
bao is a single binary at /usr/local/bin/bao. To upgrade: replace the binary,
systemctl restart openbao, then unseal.
Health¶
bao status (sealed/initialized), GET /v1/sys/health (200 = unsealed+active,
503 = sealed). The LB/ingress can health-check the TCP port; app-level health needs the
/v1/sys/health path.
Security notes¶
- The unseal keys and root token are the crown jewels — store them offline / in a password manager, never in the cluster.
- The endpoint is public (behind the ingress) with a self-signed cert; restrict access at the
ingress/firewall to known consumers where possible, and always verify the CA (avoid
BAO_SKIP_VERIFYoutside first-time setup). - Give each consumer its own policy + auth role scoped to just the transit key it needs.