Revise ADR-004 to a service-role standard: every service is its own self-contained role with a required file set including SECURITY.md, uniform deploy mechanics, and a deferred shared-engine option (with revisit trigger) recorded in the ADR. Add the per-service security record: - docs/security/service-security-template.md — canonical SECURITY.md template (exposure, checklist status, service-specific hardening, residual risks) - roles/<service>/SECURITY.md is where each service records how it meets the bar; /security-review aggregates roles/*/SECURITY.md and cross-checks against config - service-checklist.md noted as the generic bar the record answers Wire-up: new-role runbook step writes SECURITY.md from the template; ADR-002 governance bullet points at it; CLAUDE.md role conventions require it and mandate one-role-per-service; STATUS records the convention as defined-not-yet-applied. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
53 lines
2.4 KiB
Markdown
53 lines
2.4 KiB
Markdown
# 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.
|
|
|
|
This checklist is the generic **bar**. Each service answers it in its own
|
|
`roles/<service>/SECURITY.md` (the "Checklist status" section), created from
|
|
`docs/security/service-security-template.md` — see ADR-004.
|
|
|
|
## Secrets & credentials
|
|
|
|
- [ ] All secrets live in an encrypted `vault.yml` (`vault.<service>.<key>`); 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.
|