# Serves: R-SEC-01 (no plaintext secrets in git; SOPS-encrypted only) # Spec: docs/07-security-and-secrets.md "Secrets management (R-SEC-01)"; docs/05 # "Secrets in GitOps"; ADR-0007 (SOPS + age). # # SCOPE / IMPORTANT NUANCE (see platform/kyverno/README.md and admission/README.md): # This policy is the CI / L0 gate over the SECRET MANIFESTS COMMITTED TO GIT. # A SOPS-encrypted Secret file carries a top-level `sops:` block (with `sops.mac`); # a plaintext Secret does not. We reject any committed Secret lacking that block. # # This policy is CI-ONLY. It MUST NOT be applied unchanged in-cluster: Flux # decrypts SOPS before the object reaches the API server, so an admitted Secret # never has a `sops:` block -- applying this at admission would reject EVERY real # Secret. The in-cluster admission variant enforces PROVENANCE instead # (admission/secret-provenance.yaml). This CI/admission divergence is an # escalation item (see report) because docs/07's phrase "reject a plaintext # Secret at admission" is not literally achievable post-decrypt. # # "As far as policy can express" (per task): value-level ciphertext and git-history # leakage are additionally covered by a secret scanner (gitleaks) per docs/07 # acceptance gate "No plaintext secret exists anywhere in git history (scanned)". apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: disallow-plaintext-secrets annotations: policies.kyverno.io/title: Disallow plaintext Secrets (require SOPS) policies.kyverno.io/category: Secrets policies.kyverno.io/severity: critical homelab.keithjackson.dev/requirements: R-SEC-01 homelab.keithjackson.dev/scope: ci-only policies.kyverno.io/description: >- Secret manifests committed to git must be SOPS-encrypted (top-level `sops` block present). Plaintext Secrets are rejected. CI/L0 gate only -- see the provenance-based admission variant for in-cluster enforcement. spec: validationFailureAction: Enforce background: false rules: - name: secrets-must-be-sops-encrypted match: any: - resources: kinds: - Secret # Controller-generated Secrets (cert-manager, SA tokens, Helm) are never # committed to git, so the CI gate never sees them; the label keeps the rule # safe if ever reused where such Secrets exist. exclude: any: - resources: selector: matchLabels: homelab.keithjackson.dev/secret-managed-by: controller validate: message: >- Secrets committed to git must be SOPS-encrypted: the manifest must carry a top-level `sops` block (with a `mac`). No plaintext secrets (R-SEC-01, docs/07, ADR-0007). pattern: sops: mac: "?*"