# 07 — Security & Secrets Serves: **R-SEC-01/02/03**, supports all `R-NET-*` and `R-TLS-*`. Related: [ADR-0007 (SOPS+age)](../decisions/adr-0007-secrets-sops-age.md). ## Security posture Defense in depth with declarative, auditable controls: - **Network**: default-deny east-west, explicit port-level allow, egress-class routing, VPN kill- switch ([03](03-networking-isolation-and-egress.md)). This is the primary isolation control. - **Identity/least privilege**: each workload runs with a minimal ServiceAccount and only the RBAC it needs; no workload gets cluster-admin. VMs and containers alike get least network reach (R-SEC-02). - **Secrets**: encrypted at rest in git; decrypted only in-cluster (R-SEC-01). - **TLS**: trusted, auto-managed certificates end to end ([08](08-tls-and-certificates.md), R-TLS-*). - **Supply chain**: pin images by digest where automation allows; prefer known-good upstreams; updates flow through policy, not ad-hoc pulls ([11](11-automated-updates.md)). - **Policy enforcement (admission)**: **Kyverno** runs in-cluster as an admission controller and rejects non-conforming resources at reconcile time — e.g. a namespace missing its default-deny baseline, a plaintext Secret, a workload without a required egress-class label. The *same* policies gate CI ([14](14-testing-and-conformance.md), [ADR-0011](../decisions/adr-0011-test-tooling-kyverno-chainsaw.md)), so invariants are enforced both before merge and at admission (defense in depth). Enforcement complements — never replaces — the runtime behavior tests. - **Auditability**: isolation, egress path, cert validity, and backup integrity are all demonstrable (R-SEC-03) via Hubble, cert status, and DR drills. ## Secrets management (R-SEC-01) **SOPS + age**, native to Flux: - Secrets are committed to git **encrypted** with `age` recipients; Flux decrypts them at reconciliation using an in-cluster age key. Plaintext never enters git. - The age private key is bootstrapped into the cluster out-of-band (documented bootstrap step, one of the few sanctioned non-GitOps actions) and stored as a Kubernetes Secret Flux can read. - **Never** print decrypted secret material into logs, PR text, or agent output (see [AGENTS.md §5](../AGENTS.md)). ### Secret categories to manage - VPN credentials (WireGuard keys / OpenVPN creds) for the egress model. - DNS provider API token (Cloudflare) for ACME DNS-01 + ExternalDNS. - SMTP credentials for Alertmanager email. - Service credentials (Nextcloud, Gitea admin, UniFi, Semaphore, Kasm, DB passwords). - Off-cluster backup target credentials (S3/NFS) for Velero/Longhorn. - Grafana admin, and any API tokens the C2 UI needs. ### Rotation - Rotating a secret = re-encrypting with SOPS and committing; Flux rolls it out. Where a secret change requires a workload restart, that is triggered by the reconcile (e.g. checksum annotation). - VPN keys, DNS tokens, and SMTP creds SHOULD have a documented rotation procedure. ## Alternatives considered (see ADR-0007) - **Sealed Secrets** — viable; SOPS chosen for Flux-native decryption and multi-recipient/age simplicity and readable diffs. - **External Secrets Operator + external vault** — heavier; deferred until a real external secret store exists. May be revisited via ADR. ## RBAC & tenancy - Single operator + platform automation; no multi-tenant RBAC now (out of scope, [00](00-vision-and-scope.md)). - Platform controllers (Flux, cert-manager, ExternalDNS, Velero, KubeVirt) get scoped permissions; application workloads get near-zero cluster permissions. - The C2 UI's operational actions run through a constrained, audited path — not a shared admin kubeconfig handed to a browser. ## Node & host security - Nodes baselined via cloud-init/Ansible ([02](02-environments-and-provisioning.md)); SSH key-only, minimal packages, required sysctls only. - Host-level changes are IaC, not hand edits (drift + auditability). ## Auditability requirements (R-SEC-03) — what an operator must be able to prove - **Isolation**: "service X cannot reach service Y" — via Hubble flow logs + a denied-probe test. - **Egress path**: "service X's public IP is the VPN's" — via an egress IP check. - **Kill-switch**: "with VPN down, X leaks nothing" — via a fault-injection test. - **TLS**: "every endpoint serves a valid, non-self-signed, unexpired cert" — via cert status + external check. - **Backups**: "irreplaceable data is restorable" — via a DR drill. These proofs are part of the platform acceptance suite, not one-time checks. ## Acceptance gates - No plaintext secret exists anywhere in git history (scanned). - Flux decrypts SOPS secrets and workloads consume them without manual steps. - Least-privilege RBAC verified (no workload has broad cluster rights). - The five auditability proofs above can be produced on demand.