Two isolated personal-credential backup options to evaluate, both excluded
from the admin policy (root-only break-glass):
- Scenario A: personal/ KV v2 (versioned) + personal-{put,get,list}.sh
- Scenario B: transit-personal/ key personal-backup + secret-{encrypt,decrypt}.sh
Plus an AppRole example of how a system should consume a secret:
- demo-app role/policy (read-only secret/demo-app/*), short-lived tokens
- scripts/app-get-secret.sh: login (role_id+secret_id) -> token -> read
All tokens/credentials live under ~/.config/openbao (outside the repo).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
24 lines
1.3 KiB
Bash
Executable File
24 lines
1.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# AppRole demo: how a *system* consumes a secret.
|
|
# It holds a RoleID (non-secret) + SecretID (secret), logs in to get a
|
|
# SHORT-LIVED token, then reads a secret with it. Contrast with the static-token
|
|
# helpers (git-credential-openbao.sh etc.) that keep a long-lived token on disk.
|
|
#
|
|
# app-get-secret.sh <kv-path-under-secret/> e.g. app-get-secret.sh demo-app/config
|
|
set -euo pipefail
|
|
ADDR="${BAO_ADDR:-http://127.0.0.1:8200}"
|
|
DIR="${OPENBAO_APPROLE_DIR:-$HOME/.config/openbao/approle}"
|
|
path="${1:?usage: app-get-secret.sh <kv-path under secret/>}"
|
|
RID="$(cat "$DIR/role_id")"; SID="$(cat "$DIR/secret_id")"
|
|
|
|
# 1) authenticate -> short-lived token
|
|
login="$(curl -sS --data "$(RID="$RID" SID="$SID" python3 -c \
|
|
'import json,os;print(json.dumps({"role_id":os.environ["RID"],"secret_id":os.environ["SID"]}))')" \
|
|
"$ADDR/v1/auth/approle/login")"
|
|
tok="$(printf '%s' "$login" | jq -r '.auth.client_token // empty')"
|
|
[ -n "$tok" ] || { echo "login failed: $(printf '%s' "$login" | jq -c '.errors // .')" >&2; exit 1; }
|
|
echo "authenticated: token ttl=$(printf '%s' "$login" | jq -r '.auth.lease_duration')s policies=$(printf '%s' "$login" | jq -c '.auth.token_policies')" >&2
|
|
|
|
# 2) read the secret with that token
|
|
curl -sS -H "X-Vault-Token: $tok" "$ADDR/v1/secret/data/$path" | jq '.data.data'
|