Kyverno Policy Patterns for SRE
Read this before creating or modifying anything in policies/.
Directory Structure
policies/
βββ baseline/ # Pod Security Standards baseline (applied cluster-wide)
β βββ disallow-privileged.yaml
β βββ disallow-host-namespaces.yaml
β βββ disallow-host-ports.yaml
β βββ restrict-sysctls.yaml
βββ restricted/ # Pod Security Standards restricted (applied to tenant namespaces)
β βββ require-run-as-nonroot.yaml
β βββ require-drop-all-capabilities.yaml
β βββ restrict-volume-types.yaml
β βββ disallow-privilege-escalation.yaml
βββ custom/ # SRE-specific policies
β βββ require-labels.yaml
β βββ require-resource-limits.yaml
β βββ restrict-image-registries.yaml
β βββ verify-image-signatures.yaml
β βββ disallow-default-namespace.yaml
β βββ disallow-latest-tag.yaml
β βββ require-network-policies.yaml
β βββ require-probes.yaml
βββ tests/ # Test cases for every policy
βββ require-labels/
β βββ policy.yaml
β βββ resource-pass.yaml
β βββ resource-fail.yaml
β βββ kyverno-test.yaml
βββ ...
Policy Template
Every policy follows this structure:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: <descriptive-kebab-case-name>
labels:
app.kubernetes.io/part-of: sre-platform
sre.io/policy-category: <baseline|restricted|custom>
annotations:
policies.kyverno.io/title: <Human Readable Title>
policies.kyverno.io/description: >-
Brief description of what this policy enforces and why.
policies.kyverno.io/category: <Pod Security Standards Baseline|Best Practices|Supply Chain>
policies.kyverno.io/severity: <critical|high|medium|low>
sre.io/nist-controls: "AC-6, CM-7" # Map to NIST 800-53 control IDs
spec:
validationFailureAction: Enforce # Use Audit in dev environments
background: true
rules:
- name: <rule-name>
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Clear message explaining why this was denied and how to fix it."
pattern:
spec:
# ... validation pattern
Key Design Rules
- ClusterPolicy for cluster-wide rules, Policy for namespace-scoped
validationFailureAction: Enforcein production,Auditin dev β use Flux value overlays for this- Always include the
sre.io/nist-controlsannotation linking to NIST 800-53 controls - Always include a clear, actionable
messageβ developers need to know HOW to fix it, not just that it failed - Set
background: trueso policies also report on existing non-compliant resources - Use
excludeblocks to exempt platform namespaces (kube-system, istio-system, flux-system) where needed
Image Verification with Cosign
This is a critical supply chain security policy:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-image-signatures
annotations:
sre.io/nist-controls: "SA-10, SI-7"
spec:
validationFailureAction: Enforce
webhookTimeoutSeconds: 30
rules:
- name: verify-cosign-signature
match:
any:
- resources:
kinds:
- Pod
verifyImages:
- imageReferences:
- "harbor.sre.internal/*"
attestors:
- entries:
- keys:
publicKeys: |-
-----BEGIN PUBLIC KEY-----
REPLACE_ME_WITH_COSIGN_PUBLIC_KEY
-----END PUBLIC KEY-----
Mutation Policies
Use mutation for injecting defaults, not for security enforcement:
spec:
rules:
- name: add-default-labels
match:
any:
- resources:
kinds:
- Pod
mutate:
patchStrategicMerge:
metadata:
labels:
sre.io/managed: "true"
Writing Tests
EVERY policy MUST have tests. No exceptions.
Test directory structure
policies/tests/<policy-name>/
βββ policy.yaml # Copy of the policy (or symlink)
βββ resource-pass.yaml # Resource that SHOULD be allowed
βββ resource-fail.yaml # Resource that SHOULD be denied
βββ kyverno-test.yaml # Test definition
kyverno-test.yaml template
apiVersion: cli.kyverno.io/v1alpha1
kind: Test
metadata:
name: <policy-name>-test
policies:
- policy.yaml
resources:
- resource-pass.yaml
- resource-fail.yaml
results:
- policy: <policy-name>
rule: <rule-name>
resource: <passing-resource-name>
kind: Pod
result: pass
- policy: <policy-name>
rule: <rule-name>
resource: <failing-resource-name>
kind: Pod
result: fail
Running tests
# Test a single policy
kyverno test policies/tests/<policy-name>/
# Test all policies
kyverno test policies/tests/
# Also run via task
task validate
Kyverno Reporter
Kyverno Reporter sends policy violation metrics to Prometheus. It is deployed alongside Kyverno and integrated with Grafana dashboards.
Policy reports are queryable:
kubectl get policyreport -A # Namespace-scoped reports
kubectl get clusterpolicyreport # Cluster-scoped reports
Common Mistakes
- Forgetting to exclude platform namespaces β kube-system pods will fail restricted policies
- Writing validation messages that say WHAT failed but not HOW to fix it
- Not setting
background: trueβ misses reporting on existing non-compliant resources - Writing a policy without tests β this is not optional
- Using
Enforcein dev β useAuditand check reports instead - Missing the NIST control annotation β needed for compliance mapping