Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
62 lines
2.8 KiB
YAML
62 lines
2.8 KiB
YAML
# 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: "?*"
|