# Per-service security checklist The bar every service (a per-service role — ADR-004) must clear **before deploy**, especially anything reachable beyond its own host. Established by **ADR-002** (Security baseline and strategy); referenced from `docs/runbooks/new-role.md`. Enforced manually in review today; the planned `/security-review` skill (see `docs/TODO.md`) will automate the check. Treat each item as must-pass **unless** a deviation is recorded in `docs/security/accepted-risks.md` with a rationale and a revisit trigger. ## Secrets & credentials - [ ] All secrets live in an encrypted `vault.yml` (`vault..`); none in plaintext files, templates, or Compose env literals - [ ] No default or vendor-shipped credentials remain — admin passwords/tokens are generated and stored in vault - [ ] Nothing secret is baked into an image or committed to git (gitleaks must pass) ## Least privilege - [ ] Container runs as a non-root user where the image supports it - [ ] No `privileged: true` and no host network mode unless explicitly justified - [ ] Only the volumes/paths the service needs are mounted; read-only where possible - [ ] Linux capabilities dropped to what's required (no blanket grants) ## Network & exposure - [ ] Every listening port is declared in `group_vars` firewall definitions — never opened ad-hoc on a host - [ ] The service is not published directly to a LAN/WAN port if it can sit behind the reverse proxy instead - [ ] Anything reachable beyond the `srv` VLAN is behind the reverse proxy **with authentication** (and TLS) - [ ] Inter-service reach follows least privilege — no broad `srv`→`srv` access where a single declared dependency suffices ## Updates & provenance - [ ] Image/source version is pinned (tag or digest), not floating `latest` (ADR-011) - [ ] The update path is known — how this service gets patched ## Operability (security-adjacent) - [ ] Logs go somewhere reviewable (central aggregation when available) - [ ] Backup/restore is covered if the service holds state > Deviations are allowed but must be **conscious**: record them in > `docs/security/accepted-risks.md`, don't leave them implicit.