Files
OpenBAO/GOVERNANCE.md
Lutz Finsterle 5e5e7f779f Add governance blueprint: policy-as-code, operator/auditor, identity setup
Reviewable governance scaffolding — NOTHING applied to live OpenBAO yet:

- policies/: materialize all existing policies as code (faithfully fetched
  from live) + new `operator` (use engines, no admin) and `auditor`
  (read-only governance visibility, no secret material)
- scripts/apply-policies.sh: idempotent policy-as-code apply, with a
  read-only --dry-run that diffs files vs live (ignores comments)
- scripts/setup-identity.sh: identity-as-code — policy-bound groups
  (g-admins/operators/auditors/personal) + a human entity/alias; DEFAULT
  DRY-RUN, --apply to execute
- GOVERNANCE.md: the layered model, policy catalog, naming, apply order,
  and cross-cutting controls (audit device, root offline, AppRole migration)

Dry-runs verified read-only: apply-policies shows operator/auditor as NEW,
all others unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 21:05:38 +02:00

91 lines
3.8 KiB
Markdown

# 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: `<domain>-<resource>-<access>` (`kv-personal-rw`, `app-gitea-ro`)
- AppRoles: `app-<name>` (apps) / `svc-<name>` (infra jobs)
- Groups: `g-<persona>`
## 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