feat: add openbao-session plugin for interactive agents
SessionStart hook that provisions a short-lived, policy-scoped OpenBao token for each agent session. For Claude Code it writes export lines into $CLAUDE_ENV_FILE; for hosts that cannot persist env from hooks (Codex) it writes a mode-600 session env file and points the agent to it via context. Failure degrades to a benign JSON so sessions still start. Registered in both Claude and Codex marketplace manifests. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
97
plugins/openbao-session/README.md
Normal file
97
plugins/openbao-session/README.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# 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.
|
||||
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](../../../Areas/DevOps/Notes/Runbooks/OpenBao%20Production%20Operations%20and%20Recovery.md)):
|
||||
|
||||
```bash
|
||||
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
|
||||
# (sempitkan/sesuaikan daftar path mengikuti penugasan Phase 2 migrasi)
|
||||
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"] }
|
||||
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_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.
|
||||
- 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.
|
||||
|
||||
## Related
|
||||
|
||||
- [OpenBao Secret Taxonomy and Migration](../../../Areas/DevOps/Credentials/OpenBao%20Secret%20Taxonomy%20and%20Migration.md)
|
||||
- [OpenBao Production Operations and Recovery](../../../Areas/DevOps/Notes/Runbooks/OpenBao%20Production%20Operations%20and%20Recovery.md)
|
||||
Reference in New Issue
Block a user