the-custodian/docs/changes/CUST-WP-0073/ATTENDED-CUTOVER.md

82 lines
5.2 KiB
Markdown
Raw Normal View History

# CUST-WP-0073 — attended cutover runbook (2026-10-20)
Founder interview 2026-10-20 (Bernd Worsch) fixed: one isolated workstation
account hosts **Codex, Claude Code and Grok Build**; attended execution with
per-step confirmation; owner workers commit and push to main; privileged
actions go through the new `gated-executor` repo; curated read RBAC;
short-lived, re-issued credentials; **open egress** (builder mode — re-arm an
egress allowlist at production close-down); Forgejo **bot user without write to
GitOps-sourced repos**, scoped per tenant (current work = tenant zero, the
platform building itself); transport mixed (Codex desktop via loopback SSH,
Claude Code/Grok Build via `wsl -d custodian-agents`).
Shared names: workstation distro `custodian-agents`, account `custodian-agt`
(workstation and railiance01), SSH principal `agt-custodian`, ServiceAccount
`custodian-agents/custodian-agent`, executor account `gexec`.
## Owner deliveries (source, pushed; nothing live)
| Owner | Workplan | Commit | Attended step |
|---|---|---|---|
| railiance-platform | RPF-WP-0062 | 567d2c6, ded5922 | T03 Argo sync |
| railiance-platform | (OpenBao agt-role) | e415da9 | apply ssh roles |
| railiance-cluster | RCLUSTER-WP-0019 | 1d8d11d | T03 mode-600 playbook |
| railiance-infra | RAIL-HO-WP-0014 | c62b187 | T02 account/principal |
| ops-warden | WARDEN-WP-0045 | e62763c | T03 inventory + first issuance |
| gated-executor | GEXEC-WP-0001 | 80b1973 | T05 register, T06 install |
| the-custodian | this dir | workstation-agents-r4/ | distro creation |
## Order (each step: check/diff first, then apply, then verify)
0. **Recovery access**: keep an open `ssh tegwick@railiance01` session through
steps 3–4. Migrate `railiance-platform/scripts/application_backup_credentials.py`
(reads admin kubeconfig as non-root) to `sudo` or gexec before step 3.
1. **OpenBao agt-role**: `railiance-platform/scripts/openbao-apply-ssh-engine.sh`
(dry-run first). Warden: copy the `agt-custodian` actor block from
`ops-warden/examples/inventory.seed.yaml` into `~/.config/warden/inventory.yaml`.
2. **RBAC**: in railiance-platform `make argocd-pin-drift`; then
`argocd app sync railiance-apps-root --revision ded5922 --resource argoproj.io:Application:custodian-agents`;
`argocd app sync custodian-agents`.
3. **k3s mode 600** (railiance-cluster):
`ansible-playbook ansible/k3s-kubeconfig-mode.yml -e target=<railiance01> --check --diff`, then without `--check`.
API pause ~30–90 s. Rollback in playbook header.
4. **Host account** (railiance-infra/ansible):
`ansible-playbook playbooks/bootstrap-ssh-ca.yaml --limit Railiance01 --tags restricted_agent_account --check --diff`, then apply.
Confirm a fresh `ssh tegwick@railiance01` still works before closing step 0's session.
5. **Workstation distro** (operator distro, this repo):
```
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "$(wslpath -w workstation-agents-r4/import.ps1)" -IAmAttended
tar -C workstation-agents-r4 -cf - . | wsl.exe -d custodian-agents -u root -- bash -c 'mkdir -p /root/r4 && tar -C /root/r4 -xf - && bash /root/r4/guest-setup.sh --i-am-attended'
wsl.exe --terminate custodian-agents
```
Never `wsl --shutdown`, never touch another distro.
6. **Harness install + login inside the distro** (as custodian-agt, interactive
by Bernd): Codex, Claude Code, Grok Build installers; each logs in with its
own account. Codex desktop: add the Windows-side public key to
`/etc/ssh/authorized_keys/custodian-agt` (root), connect to
`custodian-agt@127.0.0.1:22273`.
7. **Credentials into the distro** (from the operator account, daily):
- `kubectl -n custodian-agents create token custodian-agent --duration=24h` →
kubeconfig at `/home/custodian-agt/.kube/config` (server URL, CA, token only).
- agent keypair generated inside the distro; operator runs
`warden sign agt-custodian --pubkey <pub> > <cert>`; place cert beside key.
- Forgejo bot token (tenant-zero bot, no GitOps-repo write).
8. **gated-executor**: register project (`custodian register-project`), then
GEXEC-WP-0001-T06 attended install on railiance01.
9. **Proof (T02 acceptance)**, run inside `custodian-agents` as custodian-agt:
- `kubectl auth whoami` → `system:serviceaccount:custodian-agents:custodian-agent`.
- `credential-boundary-r1/verify_agent_denials.py` with supervisor namespace inventory.
- `ssh custodian-agt@railiance01`: `sudo -n true` fails; `cat /etc/rancher/k3s/k3s.yaml` fails.
- `ssh tegwick@railiance01` refused (no cert for that principal); no `~/.kube` admin
config, no `/mnt/c`, `wsl.exe`/`powershell.exe` absent, no `SSH_AUTH_SOCK`,
no OpenBao token.
- gexec: one approved no-op executes; tampered/replayed/expired refused; sanitized output only.
Record sanitized output under `docs/evidence/`.
## Re-arm list (builder-mode conveniences to tighten at production close-down)
- egress allowlist for `custodian-agents`; loopback forwards from the operator distro are reachable (shared WSL2 network namespace)
- retire `agt-task-bridge` / `agt-interhub-bootstrap` → tegwick (RAIL-HO-WP-0014-T03)
- gexec credential fetch via custody owner (GEXEC-WP-0001-T07) instead of a pre-placed file
- T05 rotation of the 2026-09-23 exposed Secrets stays founder-triggered