Skip to main content

OpenBao Operations Runbook

Day-to-day operations and maintenance procedures for OpenBao.


Quick Reference

Essential Commands

# Set up root token
ROOT_TOKEN=$(op item get "OpenBao Root Keys" --vault ravenmask --fields "Root Token" --reveal)

# Check status
ssh ravenhelm@100.115.101.81 "docker exec openbao bao status"

# View logs
ssh ravenhelm@100.115.101.81 "docker logs -f openbao"

# Restart service
ssh ravenhelm@100.115.101.81 "cd ~/ravenhelm/services/openbao && docker compose restart"

Important URLs

ResourceURL
OpenBao UIhttps://vault.ravenhelm.dev
Health Checkhttps://vault.ravenhelm.dev/v1/sys/health

1Password Items

ItemContents
OpenBao Root KeysRoot token, recovery keys
OpenBao OIDC - ZitadelOIDC client credentials
OpenBao AppRole - *Service AppRole credentials
GCP Service Account - ravenmaskGCP KMS credentials

Daily Operations

Check OpenBao Health

# Quick health check
curl -s https://vault.ravenhelm.dev/v1/sys/health | jq .

# Full status
ssh ravenhelm@100.115.101.81 "docker exec openbao bao status"

Expected healthy response:

{
"initialized": true,
"sealed": false,
"standby": false,
"performance_standby": false,
"version": "2.4.4"
}

View Recent Activity

ssh ravenhelm@100.115.101.81 "docker logs openbao --since 1h 2>&1 | tail -50"

Secret Management

List All Secrets

ROOT_TOKEN=$(op item get "OpenBao Root Keys" --vault ravenmask --fields "Root Token" --reveal)

# List top-level paths
ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao kv list secret/"

# List specific path
ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao kv list secret/api-keys/"

Read a Secret

ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao kv get secret/api-keys/anthropic"

Create/Update a Secret

# Single field
ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao kv put secret/api-keys/newservice api_key=xxx"

# Multiple fields
ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao kv put secret/integrations/myservice \
client_id=xxx \
client_secret=yyy"

Delete a Secret

# Soft delete (can be recovered)
ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao kv delete secret/api-keys/oldservice"

# Permanent delete (all versions)
ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao kv metadata delete secret/api-keys/oldservice"

View Secret Versions

ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao kv metadata get secret/api-keys/anthropic"

Policy Management

List Policies

ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao policy list"

Read a Policy

ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao policy read norns"

Create/Update a Policy

# Create policy file
cat > /tmp/newpolicy.hcl << 'EOF'
path "secret/data/mypath/*" {
capabilities = ["read"]
}
EOF

# Upload and apply
scp /tmp/newpolicy.hcl ravenhelm@100.115.101.81:/tmp/
ssh ravenhelm@100.115.101.81 "docker cp /tmp/newpolicy.hcl openbao:/tmp/"
ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao policy write newpolicy /tmp/newpolicy.hcl"

Delete a Policy

ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao policy delete oldpolicy"

AppRole Management

List AppRoles

ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao list auth/approle/role"

View AppRole Details

ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao read auth/approle/role/norns"

Create New AppRole

# 1. Create policy first (see above)

# 2. Create role
ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao write auth/approle/role/newservice \
token_policies=newservice \
token_ttl=1h \
token_max_ttl=4h"

# 3. Get role_id
ROLE_ID=$(ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao read -field=role_id auth/approle/role/newservice/role-id")

# 4. Generate secret_id
SECRET_ID=$(ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao write -field=secret_id -f auth/approle/role/newservice/secret-id")

# 5. Store in 1Password
op item create --vault ravenmask --category "API Credential" --title "OpenBao AppRole - NewService" \
"role_id=$ROLE_ID" \
"secret_id[password]=$SECRET_ID" \
"vault_addr=https://vault.ravenhelm.dev"

Rotate Secret ID

# Generate new secret
NEW_SECRET=$(ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao write -field=secret_id -f auth/approle/role/norns/secret-id")

# Update 1Password
op item edit "OpenBao AppRole - Norns" --vault ravenmask "secret_id=$NEW_SECRET"

# Update service .env and restart

Backup & Restore

Create Backup

ROOT_TOKEN=$(op item get "OpenBao Root Keys" --vault ravenmask --fields "Root Token" --reveal)

# Create snapshot
ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao operator raft snapshot save /openbao/data/backup.snap"

# Copy to backup location
ssh ravenhelm@100.115.101.81 "docker cp openbao:/openbao/data/backup.snap ~/ravenhelm/backups/openbao-$(date +%Y%m%d).snap"

# Verify backup
ssh ravenhelm@100.115.101.81 "ls -la ~/ravenhelm/backups/openbao-*.snap"

Restore from Backup

# Copy snapshot to container
ssh ravenhelm@100.115.101.81 "docker cp ~/ravenhelm/backups/openbao-YYYYMMDD.snap openbao:/openbao/data/restore.snap"

# Restore (WARNING: overwrites current state)
ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao operator raft snapshot restore /openbao/data/restore.snap"

Troubleshooting

OpenBao is Sealed

With auto-unseal, this should not happen. If it does:

  1. Check GCP KMS connectivity
  2. Check GCP credentials file
  3. Review logs for errors
  4. If GCP KMS unavailable, use recovery keys
# Check seal status
ssh ravenhelm@100.115.101.81 "docker exec openbao bao status"

# If sealed and GCP KMS unavailable, use recovery keys
KEY1=$(op item get "OpenBao Root Keys" --vault ravenmask --fields "Unseal Key 1" --reveal)
KEY2=$(op item get "OpenBao Root Keys" --vault ravenmask --fields "Unseal Key 2" --reveal)
KEY3=$(op item get "OpenBao Root Keys" --vault ravenmask --fields "Unseal Key 3" --reveal)

ssh ravenhelm@100.115.101.81 "docker exec openbao bao operator unseal -recovery $KEY1"
ssh ravenhelm@100.115.101.81 "docker exec openbao bao operator unseal -recovery $KEY2"
ssh ravenhelm@100.115.101.81 "docker exec openbao bao operator unseal -recovery $KEY3"

Container Not Starting

# Check container status
ssh ravenhelm@100.115.101.81 "docker ps -a | grep openbao"

# View logs
ssh ravenhelm@100.115.101.81 "docker logs openbao 2>&1 | tail -50"

# Common issues:
# - GCP credentials missing/invalid
# - Config syntax error
# - Port conflict

Lost Root Token

Generate a new root token using recovery keys:

# Start generation
ssh ravenhelm@100.115.101.81 "docker exec openbao bao operator generate-root -init"

# Get OTP from output, then provide recovery keys
KEY1=$(op item get "OpenBao Root Keys" --vault ravenmask --fields "Unseal Key 1" --reveal)
ssh ravenhelm@100.115.101.81 "docker exec openbao bao operator generate-root -nonce=<NONCE> $KEY1"
# Repeat for KEY2, KEY3

# Decode the encoded token with the OTP

Service Can't Authenticate

# Test AppRole login manually
ROLE_ID=$(op item get "OpenBao AppRole - Norns" --vault ravenmask --fields role_id --reveal)
SECRET_ID=$(op item get "OpenBao AppRole - Norns" --vault ravenmask --fields secret_id --reveal)

curl -X POST https://vault.ravenhelm.dev/v1/auth/approle/login \
-d "{\"role_id\":\"$ROLE_ID\",\"secret_id\":\"$SECRET_ID\"}"

Permission Denied

# Check token's policies
curl -s -H "X-Vault-Token: $TOKEN" \
https://vault.ravenhelm.dev/v1/auth/token/lookup-self | jq '.data.policies'

# Check if path is covered by policy
ssh ravenhelm@100.115.101.81 "docker exec -e BAO_TOKEN=$ROOT_TOKEN openbao bao policy read <policy-name>"

Maintenance Tasks

Weekly

  • Verify backup exists and is recent
  • Check logs for errors
  • Verify services are authenticating successfully

Monthly

  • Review access policies
  • Rotate AppRole secret IDs
  • Update any expiring credentials
  • Test backup restore procedure (in staging)

Quarterly

  • Audit who has root token access
  • Review and clean up unused secrets
  • Update OpenBao version if available

Emergency Contacts

RoleContact
Primary AdminNate Walker
1Password Vaultravenmask