Skip to main content
CleanStart

Knowledge Hub

Kyverno Policies for CleanStart Image Enforcement

Why Admission Control Matters

You've signed your images with Cosign, generated SBOMs, built from verified source, and deployed to a hardened cluster. But without admission control, anyone with kubectl access can deploy an unsigned, unverified image and bypass everything. Admission controllers are the enforcement point. They intercept every pod creation request and reject pods that don't meet your security policies. Without them, your entire supply chain security posture is advisory, not enforced.

Ready-to-use Kyverno policies specifically designed for CleanStart deployments are provided below.

The following diagram illustrates the Kubernetes admission webhook flow for policy enforcement:

graph TD    A["Pod Creation<br/>Request<br/>kubectl apply"] -->|Send| B["Kyverno<br/>Admission<br/>Webhook"]     B -->|Intercept| C["Validate<br/>Against<br/>Policies"]     C -->|Check 1| D["Registry<br/>Policy"]    D -->|Verify| D1["Image from<br/>registry.cleanstart.com?"]     C -->|Check 2| E["Signature<br/>Policy"]    E -->|Verify| E1["Image<br/>Cosign Signed?"]     C -->|Check 3| F["SBOM<br/>Policy"]    F -->|Verify| F1["SBOM<br/>Attestation<br/>Present?"]     C -->|Check 4| G["CVE<br/>Policy"]    G -->|Verify| G1["No Critical<br/>CVEs?"]     D1 -->|Result| H{All<br/>Policies<br/>Pass?}     E1 --> H    F1 --> H    G1 --> H     H -->|Reject| I["Request<br/>Denied<br/>Error Message"]    I -->|User| J["Fix Non-Compliant<br/>Image"]    J -->|Retry| A     H -->|Approve| K["Mutate<br/>Request"]    K -->|Add Labels| L["Inject Security<br/>Labels"]    K -->|Add Sidecar| M["Add Security<br/>Sidecar<br/>Optional"]     L -->|Allow| N["Pod<br/>Created"]    M -->|Allow| N     N -->|Deploy| O["Secure Pod<br/>Running"]     style B fill:#99ccff    style C fill:#99ccff    style H fill:#ffff99    style I fill:#ffcccc    style K fill:#ccffcc    style N fill:#99ff99

Why Kyverno

Kyverno is a Kubernetes-native policy engine that operates fundamentally differently from OPA/Gatekeeper. Instead of using Rego, a specialized policy language that requires separate training and maintains a learning curve, Kyverno policies are written as Kubernetes resources in YAML. This means your team uses the exact same language already familiar from managing manifests, configuring Helm values, and setting up CI/CD pipelines. The cognitive load of adopting a new policy language is eliminated entirely, and policies can be managed with the same GitOps workflows and version control practices your infrastructure team already employs.

For teams that prefer OPA and already use it extensively elsewhere in their infrastructure, a detailed comparison is available at OPA Gatekeeper Policies. The choice between these two engines depends on your organizational context. Kyverno is the natural choice when your team prefers YAML and wants minimal friction in policy adoption. It also includes native support for image verification with Cosign built directly into the policy language, eliminating the need for custom webhook code. Kyverno excels at mutation policies, allowing you to automatically inject labels, security defaults, and sidecar containers without rejecting deployments. Finally, policy violations are reported as Kubernetes resources themselves, making them queryable and auditable just like any other cluster object.

OPA/Gatekeeper becomes preferable when you already maintain OPA policies elsewhere in your infrastructure—perhaps for Terraform validation, API gateway rules, or microservice policies. You might also choose OPA if your policy requirements involve complex conditional logic, external data lookups from policy-as-code repositories, or deeply interconnected rules that benefit from a full-featured policy language. A shared policy language across your entire stack, from infrastructure to application to API layers, creates consistency and reduces operational overhead when policies need updates.

In practice, both engines can coexist in a cluster. You might use Kyverno for straightforward image enforcement and OPA for complex cross-system policies. The decision often comes down to team preference and existing investments.

Installing Kyverno

# Add Kyverno Helm repohelm repo add kyverno https://kyverno.github.io/kyverno/helm repo update # Install Kyverno with high availability (production)helm install kyverno kyverno/kyverno \  --namespace kyverno \  --create-namespace \  --set replicaCount=3 \  --set resources.requests.cpu=100m \  --set resources.requests.memory=256Mi # Verify installationkubectl get pods -n kyverno# Expected: 3 kyverno pods running # Check webhook is registeredkubectl get validatingwebhookconfigurations | grep kyvernokubectl get mutatingwebhookconfigurations | grep kyverno

Policy 1: Require CleanStart Images Only

This policy enforces that all container images must come from registry.cleanstart.com. No Docker Hub, no quay.io, no gcr.io — only verified CleanStart images.

# policy-require-cleanstart-registry.yamlapiVersion: kyverno.io/v1kind: ClusterPolicymetadata:  name: require-cleanstart-registry  annotations:    policies.kyverno.io/title: Require CleanStart Registry    policies.kyverno.io/category: Supply Chain Security    policies.kyverno.io/severity: high    policies.kyverno.io/description: >-      All container images must be pulled from the CleanStart registry      (registry.cleanstart.com). Images from other registries are rejected.spec:  validationFailureAction: Enforce    # Reject non-compliant pods  background: true                     # Scan existing resources too  rules:    - name: validate-image-registry      match:        any:          - resources:              kinds:                - Pod      validate:        message: >-          Image '{{request.object.spec.containers[].image}}' is not from          the CleanStart registry. All images must be pulled from          registry.cleanstart.com. Contact your platform team if you need          an image added to the approved registry.        pattern:          spec:            containers:              - image: "registry.cleanstart.com/*"            # Also enforce init containers            =(initContainers):              - image: "registry.cleanstart.com/*"            # And ephemeral containers            =(ephemeralContainers):              - image: "registry.cleanstart.com/*"

Apply and test:

# Apply the policykubectl apply -f policy-require-cleanstart-registry.yaml # Test: this should SUCCEEDkubectl run test-pass --image=registry.cleanstart.com/python3:3.12-prod --dry-run=server# Output: pod/test-pass created (server dry run) # Test: this should FAILkubectl run test-fail --image=python:3.12-slim --dry-run=server# Output: Error: admission webhook denied the request:#   Image 'python:3.12-slim' is not from the CleanStart registry. # Test: Docker Hub should also FAILkubectl run test-fail2 --image=nginx:latest --dry-run=server# Output: Error: admission webhook denied the request

Allowing additional registries (for sidecars like Istio, Datadog, etc.):

# If you need to allow specific additional registriesspec:  rules:    - name: validate-image-registry      match:        any:          - resources:              kinds:                - Pod      validate:        message: "Image must be from an approved registry."        deny:          conditions:            all:              - key: "{{request.object.spec.containers[].image}}"                operator: AnyNotIn                value:                  - "registry.cleanstart.com/*"                  - "docker.io/istio/*"        # Istio sidecars                  - "gcr.io/datadoghq/*"       # Datadog agent

Policy 2: Verify Image Signatures (Cosign)

This policy requires that every image is signed with Cosign and the signature is verified before the pod is admitted. Instead of simply assuming images are safe because they come from a particular registry, Kyverno interacts with the Cosign tooling to cryptographically verify that a signature matching approved signing identities is present in the container image registry. This transforms image trust from a registry-level control into a cryptographic identity control, ensuring that only images explicitly signed by your build system can run.

# policy-verify-image-signatures.yamlapiVersion: kyverno.io/v1kind: ClusterPolicymetadata:  name: verify-image-signatures  annotations:    policies.kyverno.io/title: Verify Cosign Image Signatures    policies.kyverno.io/category: Supply Chain Security    policies.kyverno.io/severity: high    policies.kyverno.io/description: >-      All container images must have a valid Cosign signature.      Images without verified signatures are rejected.spec:  validationFailureAction: Enforce  webhookTimeoutSeconds: 30  rules:    - name: verify-cosign-signature      match:        any:          - resources:              kinds:                - Pod      verifyImages:        - imageReferences:            - "registry.cleanstart.com/*"          attestors:            - entries:                # Option A: Keyless verification (Sigstore/Fulcio)                - keyless:                    subject: "build@clnstrt.dev"                    issuer: "https://accounts.google.com"                    rekor:                      url: https://rekor.sigstore.dev                # Option B: Static public key verification                # - keys:                #     publicKeys: |-                #       -----BEGIN PUBLIC KEY-----                #       MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...                #       -----END PUBLIC KEY-----

Apply and test:

# Apply the policykubectl apply -f policy-verify-image-signatures.yaml # Test with a signed CleanStart image (should SUCCEED)kubectl run signed-app \  --image=registry.cleanstart.com/python3:3.12.5-prod \  --dry-run=server# Output: pod/signed-app created (server dry run) # Manually verify an image signature (outside the cluster)cosign verify \  --certificate-identity build@clnstrt.dev \  --certificate-oidc-issuer https://accounts.google.com \  registry.cleanstart.com/python3:3.12.5-prod

Policy 3: Require SBOM Attestation

This policy ensures every image has an SBOM attestation attached (CycloneDX or SPDX). Images without SBOMs are rejected. By requiring attestations at admission time, you guarantee that every pod running in your cluster has a complete inventory of its software dependencies, enabling vulnerability scanning, license compliance audits, and incident response investigations.

# policy-require-sbom-attestation.yamlapiVersion: kyverno.io/v1kind: ClusterPolicymetadata:  name: require-sbom-attestation  annotations:    policies.kyverno.io/title: Require SBOM Attestation    policies.kyverno.io/category: Supply Chain Security    policies.kyverno.io/severity: medium    policies.kyverno.io/description: >-      All container images must have a Software Bill of Materials (SBOM)      attestation attached, giving every deployed image a      complete inventory of its dependencies.spec:  validationFailureAction: Enforce  webhookTimeoutSeconds: 30  rules:    - name: require-sbom      match:        any:          - resources:              kinds:                - Pod      verifyImages:        - imageReferences:            - "registry.cleanstart.com/*"          attestations:            - type: https://cyclonedx.org/bom              attestors:                - entries:                    - keyless:                        subject: "build@clnstrt.dev"                        issuer: "https://accounts.google.com"                        rekor:                          url: https://rekor.sigstore.dev              conditions:                - all:                    # Verify the SBOM has components (not empty)                    - key: "{{ components[].name | length(@) }}"                      operator: GreaterThan                      value: 0

Verify SBOM attestation manually:

# Check SBOM attestation on a CleanStart imagecosign verify-attestation \  --type cyclonedx \  --certificate-identity build@clnstrt.dev \  --certificate-oidc-issuer https://accounts.google.com \  registry.cleanstart.com/python3:3.12.5-prod # Download the SBOM for inspectioncosign verify-attestation \  --type cyclonedx \  --certificate-identity build@clnstrt.dev \  --certificate-oidc-issuer https://accounts.google.com \  registry.cleanstart.com/python3:3.12.5-prod \  | jq -r '.payload' | base64 -d | jq '.predicate'

Policy 4: Enforce Pod Security Standards

This policy enforces the security posture that CleanStart images are designed for: non-root, read-only filesystem, dropped capabilities, no privilege escalation. By validating these controls at admission time, you ensure that developers cannot accidentally create pods that circumvent the security boundaries the images themselves were designed to operate within.

# policy-enforce-pod-security.yamlapiVersion: kyverno.io/v1kind: ClusterPolicymetadata:  name: enforce-cleanstart-pod-security  annotations:    policies.kyverno.io/title: Enforce CleanStart Pod Security Standards    policies.kyverno.io/category: Pod Security    policies.kyverno.io/severity: high    policies.kyverno.io/description: >-      Enforces security best practices for CleanStart containers:      non-root execution, read-only root filesystem, dropped capabilities,      no privilege escalation.spec:  validationFailureAction: Enforce  background: true  rules:    # Rule 1: Must run as non-root (UID 65532)    - name: require-non-root      match:        any:          - resources:              kinds:                - Pod      validate:        message: >-          Containers must run as non-root. Set          securityContext.runAsNonRoot: true and          securityContext.runAsUser: 65532 (CleanStart standard UID).        pattern:          spec:            securityContext:              runAsNonRoot: true            containers:              - securityContext:                  runAsNonRoot: true     # Rule 2: Read-only root filesystem    - name: require-read-only-rootfs      match:        any:          - resources:              kinds:                - Pod      validate:        message: >-          Container root filesystem must be read-only. Set          securityContext.readOnlyRootFilesystem: true. Use emptyDir          or tmpfs volumes for writable paths.        pattern:          spec:            containers:              - securityContext:                  readOnlyRootFilesystem: true     # Rule 3: No privilege escalation    - name: deny-privilege-escalation      match:        any:          - resources:              kinds:                - Pod      validate:        message: "Privilege escalation is not allowed."        pattern:          spec:            containers:              - securityContext:                  allowPrivilegeEscalation: false     # Rule 4: Drop ALL capabilities    - name: drop-all-capabilities      match:        any:          - resources:              kinds:                - Pod      validate:        message: >-          All capabilities must be dropped. Set          securityContext.capabilities.drop: ["ALL"]. Add back only          specific capabilities if absolutely required.        pattern:          spec:            containers:              - securityContext:                  capabilities:                    drop:                      - ALL     # Rule 5: No privileged containers    - name: deny-privileged-containers      match:        any:          - resources:              kinds:                - Pod      validate:        message: "Privileged containers are not allowed."        pattern:          spec:            containers:              - securityContext:                  privileged: false     # Rule 6: No hostPath volumes    - name: deny-host-path      match:        any:          - resources:              kinds:                - Pod      validate:        message: "hostPath volumes are not allowed."        deny:          conditions:            any:              - key: "{{ request.object.spec.volumes[?hostPath] | length(@) }}"                operator: GreaterThan                value: 0     # Rule 7: No host networking    - name: deny-host-network      match:        any:          - resources:              kinds:                - Pod      validate:        message: "Host networking is not allowed."        pattern:          spec:            =(hostNetwork): false            =(hostPID): false            =(hostIPC): false

Apply and test:

# Apply the policykubectl apply -f policy-enforce-pod-security.yaml # Test: compliant CleanStart pod (should SUCCEED)cat <<'EOF' | kubectl apply --dry-run=server -f -apiVersion: v1kind: Podmetadata:  name: compliant-podspec:  securityContext:    runAsNonRoot: true    runAsUser: 65532    fsGroup: 65532  containers:    - name: app      image: registry.cleanstart.com/python3:3.12.5-prod      securityContext:        runAsNonRoot: true        readOnlyRootFilesystem: true        allowPrivilegeEscalation: false        privileged: false        capabilities:          drop: ["ALL"]      volumeMounts:        - name: tmp          mountPath: /tmp  volumes:    - name: tmp      emptyDir:        sizeLimit: 100MiEOF# Output: pod/compliant-pod created (server dry run) # Test: non-compliant pod (should FAIL)cat <<'EOF' | kubectl apply --dry-run=server -f -apiVersion: v1kind: Podmetadata:  name: non-compliant-podspec:  containers:    - name: app      image: registry.cleanstart.com/python3:3.12.5-prod      securityContext:        runAsRoot: true        privileged: trueEOF# Output: Error: admission webhook denied the request

Policy 5: Enforce Resource Limits

CleanStart minimal images use significantly less resources than traditional images. This policy ensures every pod declares resource requests and limits, enabling the Kubernetes scheduler to make informed placement decisions and preventing resource starvation scenarios where a single badly-configured pod consumes all available CPU or memory.

# policy-require-resource-limits.yamlapiVersion: kyverno.io/v1kind: ClusterPolicymetadata:  name: require-resource-limits  annotations:    policies.kyverno.io/title: Require Resource Requests and Limits    policies.kyverno.io/category: Resource Management    policies.kyverno.io/severity: mediumspec:  validationFailureAction: Enforce  background: true  rules:    - name: require-requests-and-limits      match:        any:          - resources:              kinds:                - Pod      validate:        message: >-          All containers must declare CPU and memory requests and limits.          CleanStart images are minimal — start with cpu: 100m/500m          and memory: 128Mi/512Mi and adjust based on metrics.        pattern:          spec:            containers:              - resources:                  requests:                    memory: "?*"                    cpu: "?*"                  limits:                    memory: "?*"                    cpu: "?*"     - name: limit-memory-ceiling      match:        any:          - resources:              kinds:                - Pod      validate:        message: >-          Memory limit cannot exceed 4Gi. CleanStart images are          minimal — if you need more than 4Gi, review your application.        deny:          conditions:            any:              - key: "{{ request.object.spec.containers[].resources.limits.memory }}"                operator: GreaterThan                value: "4Gi"

Policy 6: Block Latest Tags

The :latest tag is mutable—it can point to different images at different times. This breaks reproducibility and auditing. By enforcing versioned tags, you guarantee that deployments remain stable even when new images are pushed to the registry, and you create an immutable record of exactly which image version was deployed at which time.

# policy-block-latest-tag.yamlapiVersion: kyverno.io/v1kind: ClusterPolicymetadata:  name: block-latest-tag  annotations:    policies.kyverno.io/title: Block Latest Image Tag    policies.kyverno.io/category: Supply Chain Security    policies.kyverno.io/severity: medium    policies.kyverno.io/description: >-      Images must use a specific version tag or digest, not :latest.      Mutable tags break reproducibility and supply chain verification.spec:  validationFailureAction: Enforce  background: true  rules:    - name: deny-latest-tag      match:        any:          - resources:              kinds:                - Pod      validate:        message: >-          Image tag ':latest' is not allowed. Use a specific version tag          (e.g., registry.cleanstart.com/python3:3.12.5-prod) or a digest          (e.g., registry.cleanstart.com/python3@sha256:abc...).        pattern:          spec:            containers:              - image: "!*:latest"            =(initContainers):              - image: "!*:latest"

Policy 7: Auto-Inject Security Defaults (Mutation)

Instead of rejecting pods that miss security settings, this mutation policy automatically adds CleanStart security defaults. Use this in development and staging environments; use validation (enforce) in production. This approach dramatically improves developer experience by eliminating rejection loops while still maintaining security baselines through automatic injection.

# policy-mutate-security-defaults.yamlapiVersion: kyverno.io/v1kind: ClusterPolicymetadata:  name: inject-cleanstart-security-defaults  annotations:    policies.kyverno.io/title: Auto-Inject CleanStart Security Defaults    policies.kyverno.io/category: Pod Security    policies.kyverno.io/severity: medium    policies.kyverno.io/description: >-      Automatically injects CleanStart security defaults into pods      that don't specify them. Adds non-root, read-only FS, capability      drop, and resource defaults.spec:  rules:    # Inject pod-level security context    - name: inject-pod-security-context      match:        any:          - resources:              kinds:                - Pod      mutate:        patchStrategicMerge:          spec:            securityContext:              +(runAsNonRoot): true              +(runAsUser): 65532              +(runAsGroup): 65532              +(fsGroup): 65532              +(seccompProfile):                type: RuntimeDefault     # Inject container-level security context    - name: inject-container-security-context      match:        any:          - resources:              kinds:                - Pod      mutate:        foreach:          - list: "request.object.spec.containers"            patchStrategicMerge:              spec:                containers:                  - (name): "{{ element.name }}"                    securityContext:                      +(readOnlyRootFilesystem): true                      +(allowPrivilegeEscalation): false                      +(privileged): false                      +(capabilities):                        drop:                          - ALL     # Inject default resource requests    - name: inject-resource-defaults      match:        any:          - resources:              kinds:                - Pod      mutate:        foreach:          - list: "request.object.spec.containers"            patchStrategicMerge:              spec:                containers:                  - (name): "{{ element.name }}"                    resources:                      +(requests):                        cpu: "100m"                        memory: "128Mi"                      +(limits):                        cpu: "500m"                        memory: "512Mi"     # Add CleanStart labels    - name: inject-labels      match:        any:          - resources:              kinds:                - Pod      mutate:        patchStrategicMerge:          metadata:            labels:              +(cleanstart.dev/enforced): "true"              +(cleanstart.dev/security-profile): "hardened"

Test the mutation:

# Apply mutation policykubectl apply -f policy-mutate-security-defaults.yaml # Deploy a bare pod (no security context specified)kubectl run bare-pod \  --image=registry.cleanstart.com/python3:3.12.5-prod \  --dry-run=server -o yaml # The output will show injected securityContext:#   securityContext:#     runAsNonRoot: true#     runAsUser: 65532#     readOnlyRootFilesystem: true#     allowPrivilegeEscalation: false#     capabilities:#       drop: ["ALL"]

Policy 8: Require Image Digest (Not Tag)

For maximum supply chain integrity, require image references by digest (immutable) rather than tag (mutable). Digests are content-addressed identifiers that represent the exact image you verified—if even a single byte changes, the digest changes, preventing accidental rollouts to different images due to tag reassignment or image registry compromises.

# policy-require-image-digest.yamlapiVersion: kyverno.io/v1kind: ClusterPolicymetadata:  name: require-image-digest  annotations:    policies.kyverno.io/title: Require Image Digest    policies.kyverno.io/category: Supply Chain Security    policies.kyverno.io/severity: high    policies.kyverno.io/description: >-      In production, images must be referenced by digest (@sha256:...)      not by tag. Tags are mutable; digests are immutable and guarantee      you're running exactly the image you verified.spec:  validationFailureAction: Enforce  background: true  rules:    - name: require-digest      match:        any:          - resources:              kinds:                - Pod              namespaces:                - production                - prod-*      validate:        message: >-          In production namespaces, images must use a digest reference          (e.g., registry.cleanstart.com/python3@sha256:abc123...), not a tag.          Get the digest: crane digest registry.cleanstart.com/python3:3.12.5-prod        pattern:          spec:            containers:              - image: "*@sha256:*"

Get image digests:

# Get the digest for a CleanStart imagecrane digest registry.cleanstart.com/python3:3.12.5-prod# Output: sha256:a1b2c3d4e5f6... # Use in your deploymentimage: registry.cleanstart.com/python3@sha256:a1b2c3d4e5f6...

Deploying All Policies Together

Recommended Rollout Strategy

Don't enforce everything at once. Roll out in phases, progressively tightening controls as teams adapt and compliance improves.

# Phase 1: Audit mode (see violations without blocking)# Change all policies to:#   validationFailureAction: Audit kubectl apply -f policy-require-cleanstart-registry.yamlkubectl apply -f policy-block-latest-tag.yamlkubectl apply -f policy-require-resource-limits.yaml # Check violations (policy reports)kubectl get policyreport -Akubectl get clusterpolicyreport # Phase 2: Enforce non-breaking policies# These won't break existing workloads if already using CleanStart:kubectl apply -f policy-block-latest-tag.yaml          # Enforcekubectl apply -f policy-require-resource-limits.yaml    # Enforce # Phase 3: Enforce security policieskubectl apply -f policy-enforce-pod-security.yaml       # Enforcekubectl apply -f policy-require-cleanstart-registry.yaml # Enforce # Phase 4: Enforce supply chain policieskubectl apply -f policy-verify-image-signatures.yaml    # Enforcekubectl apply -f policy-require-sbom-attestation.yaml   # Enforce # Phase 5 (production only): Enforce digest requirementkubectl apply -f policy-require-image-digest.yaml       # Enforce

Monitoring Policy Violations

# View all policy violations across clusterkubectl get policyreport -A -o wide # Detailed violation reportkubectl get policyreport -n default -o yaml # Count violations by policykubectl get clusterpolicyreport -o json | \  jq '.items[].results[] | select(.result=="fail") | .policy' | \  sort | uniq -c | sort -rn # Watch for new violations in real-timekubectl get events --field-selector reason=PolicyViolation -w

Namespace Exceptions

Some namespaces (monitoring, kube-system) may need different rules. Rather than creating blanket exceptions, define explicit allowlists for system components:

# Exclude system namespaces from registry restrictionspec:  rules:    - name: validate-image-registry      match:        any:          - resources:              kinds:                - Pod      exclude:        any:          - resources:              namespaces:                - kube-system                - kyverno                - monitoring                - istio-system

Complete CleanStart Policy Bundle

Apply all policies at once with a Kustomization, making your entire policy set version-controlled and deployable as a single unit:

# kustomization.yamlapiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationresources:  - policy-require-cleanstart-registry.yaml  - policy-verify-image-signatures.yaml  - policy-require-sbom-attestation.yaml  - policy-enforce-pod-security.yaml  - policy-require-resource-limits.yaml  - policy-block-latest-tag.yaml  - policy-mutate-security-defaults.yaml  # Production only:  # - policy-require-image-digest.yaml
# Apply all policieskubectl apply -k . # Verify all policies are activekubectl get clusterpolicy# NAME                             BACKGROUND   VALIDATE ACTION   READY# require-cleanstart-registry      true         Enforce           True# verify-image-signatures          true         Enforce           True# require-sbom-attestation         true         Enforce           True# enforce-cleanstart-pod-security  true         Enforce           True# require-resource-limits          true         Enforce           True# block-latest-tag                 true         Enforce           True# inject-cleanstart-security-defaults                             True

Troubleshooting

Policy Not Enforcing

# Check Kyverno logskubectl logs -n kyverno -l app.kubernetes.io/name=kyverno --tail=100 # Verify webhook configurationkubectl get validatingwebhookconfigurations kyverno-resource-validating-webhook-cfg -o yaml # Check policy statuskubectl get clusterpolicy require-cleanstart-registry -o yaml | grep -A5 "status:"

Image Verification Timeout

# Increase webhook timeout (default 10s may be too short for signature verification)# In the policy spec:spec:  webhookTimeoutSeconds: 30 # Or in Kyverno Helm values:helm upgrade kyverno kyverno/kyverno \  --namespace kyverno \  --set webhookTimeout=30

Debugging Denied Pods

# See exactly why a pod was deniedkubectl describe pod <pod-name># Events section shows the denial reason and which policy blocked it # Test a manifest without creating the resourcekubectl apply -f my-pod.yaml --dry-run=server# Shows the admission webhook response

What to Read Next

OPA Gatekeeper Policies — Alternative policy engine using Rego. Image Signing with Sigstore — How CleanStart images are signed. CycloneDX SBOM — SBOM format and generation. CIS Hardening — CIS benchmark controls that these policies enforce. Upgrade Patching Playbook — How new image versions are published.