# OpenBAO Governance Blueprint A layered access model for this instance. Everything here is **policy-as-code**: edit files, review in git, then apply with the scripts. Nothing is live until you run the apply scripts. ## Model ``` auth method → identity (entity / group) → policy → paths (how you log in) (who you are) (what's allowed) (where) ``` Rule of thumb: **bind policies to GROUPS (humans) and ROLES (machines)** — not to individuals or scattered standalone tokens. Access then = "which groups/roles am I in". ## Policy catalog (`policies/*.hcl`) | Policy | Kind | Grants | |--------|------|--------| | `admin` | human | platform administration (auth, mounts, policies, engines) — **not** root-only ops | | `operator` | human | day-to-day *use* of engines (KV, issue certs, sign SSH, transit) — no administration | | `auditor` | human | read-only governance visibility — config + policies, **no secret material** | | `personal-rw` | human | the isolated `personal/` KV vault | | `demo-app` | machine | read `secret/demo-app/*` (AppRole example) | | `gitea-push-ro` | machine | read `secret/gitea/push` (git credential helper) | | `cert-renew` | machine | `pki_int/issue/famfi-home` (cert renewal timer) | | `backup` | machine | `sys/storage/raft/snapshot` (snapshot timer) | | `ssh-sign-user` | machine | `ssh/sign/user` (ssh-login helper) | | `personal-transit` | machine | encrypt/decrypt with `transit-personal/personal-backup` | `default` and `root` are built-in and not managed here. ## Humans — via identity groups | Group | Policy | Who | |-------|--------|-----| | `g-admins` | `admin` | you (platform changes; not daily use) | | `g-operators` | `operator` | routine work | | `g-auditors` | `auditor` | the governance lens (read-only) | | `g-personal` | `personal-rw` | personal vault access | A person = an **entity**; each login (e.g. `admin@userpass`) is an **alias** to that entity; the entity's **group membership** confers policies. Compose access by adding an entity to more groups — no token edits. ## Machines — AppRole, one role + least-privilege policy per service Target: migrate the static-token helpers to AppRole roles `svc-backup`, `svc-cert-renew`, `svc-ssh-sign`, `app-gitea` (each bound to the matching policy above). `demo-app` already demonstrates the pattern. ## Naming conventions - Policies: `--` (`kv-personal-rw`, `app-gitea-ro`) - AppRoles: `app-` (apps) / `svc-` (infra jobs) - Groups: `g-` ## How to apply ```bash # 1. Review what would change (read-only): scripts/apply-policies.sh --dry-run # 2. Apply the policies (NEW/CHANGED only): scripts/apply-policies.sh # 3. Create groups + a human entity (dry-run first, then --apply): scripts/setup-identity.sh scripts/setup-identity.sh --apply # aliases to the 'admin' userpass user ``` ## Cross-cutting controls 1. **Audit device** (currently OFF — top gap). Enable a file audit log: ```bash docker compose exec openbao bao audit enable file file_path=/openbao/logs/audit.log ``` (logs to the container's `/openbao/logs`; mount/ship it for retention). 2. **Root sealed** — move `init-output.json` (recovery keys + root token) offline; root is break-glass only. 3. **Least privilege + short TTLs** — services use AppRole short tokens; humans get group-derived policies. 4. **Trust-domain isolation by mount** — `personal/` and `transit-personal/` are excluded from `admin`/`operator`; only `g-personal` reaches them. 5. **Policy-as-code** — all rules live in `policies/`, applied by `apply-policies.sh`, reviewed in git. ## Apply order (when you're ready) 1. `apply-policies.sh` (adds `operator`, `auditor`) 2. `setup-identity.sh --apply` (groups + entity) 3. Enable the audit device 4. (Optional) give `admin` `identity/*`; migrate services to AppRole; move root offline