Files
infra-plugins/plugins/openbao-session
Adnan Zahir 6877bc7202 feat(openbao-session): tie session token to the user entity
Mint the session token with -entity-alias from OPENBAO_SESSION_ENTITY so
{{identity.entity.id}} resolves and the session can read humans/self (read-only)
in addition to shared/*. Document the claude-session policy with humans/self.
Bump 0.1.1.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-01 11:19:00 +07:00
..

openbao-session

Hook SessionStart untuk Claude Code dan Codex yang menyuntikkan token OpenBao berumur pendek ke lingkungan sesi agent. Dengan ini agent tidak perlu memegang credential statis — setiap sesi mendapat token baru yang scoped dan kadaluarsa sendiri.

Cara kerja

Saat sesi mulai, hooks/bao-session.sh:

  1. Memastikan SSH tunnel loopback ke listener VPC privat OpenBao hidup (127.0.0.1:8200 → 10.104.0.12:8200 lewat jumphost mbu-backup-jumphost).
  2. Mengambil CA cert OpenBao (/opt/openbao/tls/tls.crt) dan menyimpannya lokal.
  3. Membaca bootstrap credential dari secrets store lokal (manage.py get openbao bootstrap_token).
  4. Mint token sesi claude-session (TTL 4h, renewable) memakai bootstrap credential sebagai caller; bila OPENBAO_SESSION_ENTITY diset, token dikaitkan ke entity pemakai (-entity-alias) sehingga {{identity.entity.id}} resolve dan sesi dapat membaca humans/self.
  5. Menyuntikkan OPENBAO_TOKEN, BAO_ADDR, BAO_CACERT, BAO_TLS_SERVER_NAME ke sesi:
Host Mekanisme injeksi
Claude Code Menulis export OPENBAO_TOKEN=... ke $CLAUDE_ENV_FILE — file yang di-source Claude Code ke setiap command Bash sesi itu.
Codex / host lain Hook Codex tidak bisa persist env (proses hook terpisah). Skrip menulis session env file (mode 600) dan memberitahu agent lewat additionalContext untuk source file itu — nilai token tidak pernah masuk konteks model.

Token sesi cuma bisa membaca secret yang diizinkan policy claude-session (bukan semua). Semua akses tercatat di audit OpenBao.

Prasyarat sekali-jalan (platform admin)

Dengan token admin di jumphost (lihat OpenBao Production Operations and Recovery):

export BAO_ADDR=https://10.104.0.12:8200
export BAO_CACERT=/opt/openbao/tls/tls.crt
export BAO_TOKEN=<token admin Anda>   # jangan di-paste ke chat

# 1. Policy bootstrap: bisa membuat token, TIDAK bisa membaca secret
cat > /tmp/openbao-session-creator.hcl <<'EOF'
path "auth/token/create" {
  capabilities = ["create", "update", "sudo"]
}
path "auth/token/renew-self"  { capabilities = ["update"] }
path "auth/token/revoke-self" { capabilities = ["update"] }
path "auth/token/lookup-self" { capabilities = ["read"] }
EOF
bao policy write openbao-session-creator /tmp/openbao-session-creator.hcl

# 2. Policy sesi: baca-only untuk secret yang memang di-assign ke agent.
#    humans/self otomatis ter-scope ke entity pemakai via {{identity.entity.id}}
cat > /tmp/claude-session.hcl <<'EOF'
# Refine daftar path di sini sesuai owner/consumer assignment.
path "shared/data/*"        { capabilities = ["read", "list"] }
path "shared/metadata/*"    { capabilities = ["read", "list"] }
path "humans/data/{{identity.entity.id}}/*"     { capabilities = ["read", "list"] }
path "humans/metadata/{{identity.entity.id}}/*" { capabilities = ["read", "list"] }
EOF
bao policy write claude-session /tmp/claude-session.hcl

# 3. Issue bootstrap token (TTL panjang, renewable) dan simpan NILAINYA ke secrets store LOKAL:
bao token create -policy=openbao-session-creator -ttl=720h -renewable \
  -display-name=openbao-session-bootstrap -format=json
#   → ambil auth.client_token, lalu di Mac Anda:
python3 ~/.config/devops-secrets/manage.py set openbao bootstrap_token --description "OpenBao session bootstrap (creator)"

Bootstrap credential ini kuat (bisa mint token policy apa pun) tapi tidak bisa membaca nilai secret. Karena itu simpan hanya di secrets store lokal (~/.config/devops-secrets, mode 700/600), jangan di vault/repo/chat. Upgrade ke AppRole atau OIDC saat identity provider disetujui.

Instalasi

Claude Code

  • Daftarkan marketplace (jika belum): claude plugin marketplace add infra-plugins https://git.senkensha.space/senkensha/infra-plugins.git
  • Pasang: claude plugin install openbao-session@infra-plugins
  • Konfirmasi hook aktif: buka sesi baru, lihat status message "Provisioning OpenBao session token...", lalu echo ${OPENBAO_TOKEN:+SET}.

Codex

  • codex plugin install openbao-session@infra-plugins (marketplace sudah terdaftar sebagai infra-plugins).

Konfigurasi (opsional, via env)

Variable Default Keterangan
OPENBAO_SESSION_CONF_DIR ~/.config/openbao dir cache CA cert + binary bao
OPENBAO_SESSION_LOCAL_PORT 8200 port tunnel lokal
OPENBAO_SESSION_VPC_ADDR 10.104.0.12 alamat VPC listener OpenBao
OPENBAO_SESSION_DROPLET mbu-backup-jumphost droplet jumphost
OPENBAO_SESSION_HOST (kosong) public IP jumphost eksplisit (default: resolve via doctl)
OPENBAO_SESSION_SSH_KEY ~/.ssh/id_ed25519 key SSH ke jumphost
OPENBAO_SESSION_POLICY claude-session policy token sesi
OPENBAO_SESSION_TTL 4h umur token sesi
OPENBAO_SESSION_ENTITY (kosong) nama entity OpenBao pemakai (mis. adnan, rizal) → token sesi diikat ke entity (aktifkan humans/self)
OPENBAO_SESSION_BAO_VER 2.6.2 versi binary bao (auto-download jika belum ada)
OPENBAO_SESSION_SECRETS_HELPER ~/.config/devops-secrets/manage.py helper baca bootstrap
OPENBAO_SESSION_BOOTSTRAP_TOOL / _KEY openbao / bootstrap_token lokasi bootstrap di secrets store

Keamanan

  • Nilai secret tidak pernah ditulis ke repo, chat, atau log; token sesi mengalir lewat $CLAUDE_ENV_FILE (Claude) atau session env file mode 600 (Codex), bukan argv dan bukan ke konteks model.
  • Token sesi short-lived (4h, renewable) dan scoped ke policy claude-session saja.
  • humans/self hanya terbaca lewat token yang terikat entity pemakai ({{identity.entity.id}}) — sesi orang lain tidak bisa membaca ruang pribadi Anda.
  • Bootstrap credential tidak bisa membaca secret, tapi bisa mint token → rotasi bila dicurigai bocor: buat bootstrap baru, manage.py set, revoke yang lama (bao token revoke <accessor>).
  • Tunnel hanya bind 127.0.0.1; jangan pernah expose port publik atau pakai TLS skip-verify.