feat: close WP-0009/WP-0013 production integration stewardship strand

Ship flex-auth policy gate registry and smoke evidence, archive WP-0009
through WP-0013, and add integration docs: ops-bridge cert_command
migration playbook, operator OpenBao token hygiene, principals drift
check script, and 2026-06-24 INTENT/SCOPE gap analysis.
This commit is contained in:
2026-06-24 12:44:32 +02:00
parent 1778b169da
commit 90007c2cda
24 changed files with 2192 additions and 121 deletions

View File

@@ -0,0 +1,105 @@
# Operator OpenBao Token Hygiene
Date: 2026-06-24
Workplan: WARDEN-WP-0013 T4
Daily `warden sign` against production OpenBao requires a **scoped** API token in
`VAULT_TOKEN` — not the cluster root token.
---
## Rules
| Rule | Rationale |
| --- | --- |
| Never commit `VAULT_TOKEN` | Tokens are secrets |
| Never paste tokens in chat, State Hub, or workplans | Same |
| Do not use root token for daily `warden sign` | Break-glass only |
| Prefer short-lived tokens | Limit blast radius |
| Refresh on HTTP 403 | Token expired or policy mismatch |
---
## Scoped token for warden
Production signing needs permission to call the SSH engine sign endpoint for the
roles mapped in `warden.yaml` (`adm-role`, `agt-role`, `atm-role`).
Illustrative policy shape (create in OpenBao policy admin — adjust names to match
your cluster):
```hcl
# warden-sign — least privilege for ops-warden CLI
path "ssh/sign/agt-role" {
capabilities = ["create", "update"]
}
path "ssh/sign/adm-role" {
capabilities = ["create", "update"]
}
path "ssh/sign/atm-role" {
capabilities = ["create", "update"]
}
```
Issue a token bound to `warden-sign` (operator procedure in `railiance-platform` /
OpenBao admin runbooks).
---
## Session pattern
```bash
# Set for current shell only — do not add to ~/.bashrc with a literal token
export VAULT_TOKEN="<scoped-token>"
warden status agt-state-hub-bridge
warden sign agt-state-hub-bridge --pubkey ~/.ssh/agt-state-hub-bridge_ed25519.pub
```
`warden` reads the env var named in `vault.token_env` (default `VAULT_TOKEN`).
---
## OIDC / interactive login
For human operators, prefer platform OIDC login that yields a short-lived OpenBao
token instead of copying long-lived secrets.
| Need | Route to |
| --- | --- |
| Interactive login, OIDC, MFA | key-cape / Keycloak — `warden route show key-cape-oidc-login` |
ops-warden does not implement login; it documents the route only.
---
## Troubleshooting
| Symptom | Likely cause | Action |
| --- | --- | --- |
| `Vault token not found` | `VAULT_TOKEN` unset | Export scoped token |
| `HTTP 403` / `permission denied` | Expired token or insufficient policy | Re-issue `warden-sign` token |
| `Signing failed` + connection error | Wrong `vault.addr` or network | Check `warden.yaml`, tunnel/VPN |
| Suggest `--backend local` | OpenBao unreachable | Fix connectivity; local is lab-only |
After fixing token issues, re-run:
```bash
warden sign <actor> --pubkey <path>
```
---
## Root token (break-glass only)
Cluster root tokens bypass all policy. Use only for one-time engine setup
(`wiki/OpenBaoSshEngineChecklist.md` § One-time SSH engine setup), then revoke
from daily shell profile.
---
## See also
- `wiki/OpenBaoSshEngineChecklist.md`
- `wiki/OpsWardenConfig.md` — Authentication section
- `examples/warden.production.example.yaml`

View File

@@ -0,0 +1,121 @@
# ops-bridge Tunnel — cert_command Migration
Date: 2026-06-24
Workplan: WARDEN-WP-0013 T3
Catalog: `ops-bridge-tunnel`
Migrate an ops-bridge tunnel from **static SSH keys** to **short-lived warden-signed
certificates** via the `cert_command` contract (`wiki/CertCommandInterface.md`).
ops-warden documents the migration; **ops-bridge** owns tunnel config changes.
---
## Prerequisites
- [ ] Actor registered in `~/.config/warden/inventory.yaml` (see `wiki/ActorInventoryPatterns.md`)
- [ ] Actor keypair on disk (`ssh_key` private, `.pub` for signing)
- [ ] Production `warden.yaml` with `backend: vault` and valid scoped `VAULT_TOKEN`
- [ ] Host trusts warden/OpenBao CA (`railiance-infra` `bootstrap-ssh-ca`)
- [ ] Host principal allows the actor's principals (`railiance-infra` `ssh_principals.yaml`)
---
## Pilot tunnel: `agt-state-hub-bridge`
| Field | Value |
| --- | --- |
| Actor | `agt-state-hub-bridge` |
| Type | `agt` |
| Principals | `agt-task-bridge` |
| TTL | 24 h |
| Private key | `~/.ssh/agt-state-hub-bridge_ed25519` |
| Public key | `~/.ssh/agt-state-hub-bridge_ed25519.pub` |
| cert_command | `warden sign agt-state-hub-bridge --pubkey ~/.ssh/agt-state-hub-bridge_ed25519.pub` |
### Pre-migration smoke (operator workstation)
```bash
export VAULT_TOKEN="<scoped-warden-sign-token>" # never commit or paste in chat
warden status agt-state-hub-bridge
warden sign agt-state-hub-bridge --pubkey ~/.ssh/agt-state-hub-bridge_ed25519.pub | head -1
```
Confirm exit 0 and cert line starts with `ssh-ed25519-cert-v01@openssh.com`.
---
## Migration checklist
### 1. Inventory and signing path
- [ ] Actor exists: `warden inventory list` shows `agt-state-hub-bridge`
- [ ] `warden sign` succeeds with production OpenBao backend
- [ ] `signatures.log` records the sign (`~/.local/state/warden/signatures.log`)
### 2. ops-bridge tunnel config
Edit `~/.config/bridge/tunnels.yaml` (ops-bridge repo owns schema; example below):
```yaml
tunnels:
state-hub-coulombcore:
host: coulombcore
remote_port: 8001
local_port: 8000
ssh_user: agt-state-hub-bridge
ssh_key: ~/.ssh/agt-state-hub-bridge_ed25519
actor: agt-state-hub-bridge
cert_command: "warden sign agt-state-hub-bridge --pubkey ~/.ssh/agt-state-hub-bridge_ed25519.pub"
```
- [ ] `cert_command` uses the **public** key path (warden reads pubkey, writes cert to stdout)
- [ ] `ssh_user` matches the certificate identity / host expectation
- [ ] Remove or disable static-key-only fallback once cert path is verified
### 3. Host-side verification
- [ ] Principal `agt-task-bridge` present in `railiance-infra` `ssh_principals.yaml` for target host
- [ ] Run `scripts/check_principals_drift.py` if inventory `hosts` section documents allowed principals
### 4. Tunnel smoke
```bash
# ops-bridge (from ops-bridge repo)
bridge status state-hub-coulombcore
bridge up state-hub-coulombcore
```
- [ ] Tunnel establishes without static cert file on disk
- [ ] Re-run `bridge up` after cert TTL expires — `cert_command` re-issues automatically
### 5. Policy gate (optional, after FLEX-WP-0007)
When `policy.enabled: true`, confirm `signatures.log` includes `policy_decision_id`
on tunnel-driven signs. See `wiki/PolicyGatedSigning.md`.
---
## Rollback
Keep the static key path until cert_command smoke passes. To roll back:
1. Remove `cert_command` from tunnel config
2. Restore prior static-key or `CertificateFile` workflow
3. Document rollback in ops-bridge session notes (not in git secrets)
---
## Static-key tunnels (legacy)
Tunnels using `agt-claude-*` or other long-lived keys are **out of scope** for this
pilot. Migrate per-tunnel when ops-bridge owner prioritizes them.
---
## See also
- `wiki/CertCommandInterface.md`
- `wiki/OpsWardenConfig.md` — cert_command example
- `wiki/playbooks/operator-openbao-token-hygiene.md`
- `warden route show ops-bridge-tunnel --json`