Skip to content

Lab 03 — Kyverno Policies

Item Details
Lab ID K8S-COMPLIANCE-LAB-03
Difficulty Intermediate to Advanced
Estimated Time 5–7 Hours
Environment Kubernetes Training Cluster
Platform Kubernetes, Kyverno, Helm and kubectl
Cost Free
Primary Role Kubernetes Security Engineer
Supporting Roles DevSecOps Engineer, Platform Engineer, Cloud Security Engineer, Compliance Analyst
Module Kubernetes Benchmarks & Compliance
Previous Lab Lab 02 — Gatekeeper Policies
Next Lab Lab 04 — Compliance Automation

CloudNova Technologies has deployed OPA Gatekeeper to enforce several Kubernetes governance controls.

The platform team has now identified additional requirements that extend beyond policy validation.

The organisation needs a policy engine that can:

  • Validate incoming Kubernetes resources
  • Mutate resources automatically
  • Generate supporting resources
  • Verify container images
  • Audit existing workloads
  • Produce policy reports
  • Enforce configuration standards using Kubernetes-native YAML

Current issues include:

  • Workloads missing recommended security settings
  • Containers running without resource limits
  • Images using mutable tags
  • Missing ownership labels
  • Service Account tokens mounted unnecessarily
  • Workloads without seccomp configuration
  • Namespace security labels applied inconsistently
  • Developers manually adding repetitive security settings
  • Policy exceptions not formally documented
  • Limited reporting on policy violations

CloudNova Technologies has selected Kyverno to extend its policy-as-code and compliance automation capabilities.

Your mission is to deploy Kyverno, implement validation and mutation policies, generate supporting security configurations, test compliant and non-compliant workloads, and produce an enterprise policy-governance assessment.

By completing this lab, you will learn how to:

  • Explain Kyverno architecture
  • Compare Kyverno with OPA Gatekeeper
  • Install Kyverno using Helm
  • Validate Kyverno components
  • Create ClusterPolicies
  • Create Namespaced Policies
  • Configure Audit and Enforce modes
  • Validate required labels
  • Require non-root containers
  • Block privileged workloads
  • Require resource requests and limits
  • Restrict mutable image tags
  • Require seccomp profiles
  • Mutate workloads automatically
  • Disable automatic Service Account token mounting
  • Generate namespace security resources
  • Review PolicyReports
  • Configure policy exceptions
  • Produce an enterprise governance report
Developer or CI/CD Pipeline
Kubernetes API Server
Kyverno
┌─────────┼─────────┐
│ │ │
Validate Mutate Generate
│ │ │
└─────────┼─────────┘
Policy Decision
┌─────────┴─────────┐
│ │
Allowed Rejected
Policy Reports and Audit Evidence
Policy Requirement
Policy as Kubernetes YAML
Audit Mode
Violation Analysis
Remediation and Exceptions
Enforce Mode
Continuous Compliance
Capability Purpose
Validate Reject or report non-compliant resources
Mutate Automatically modify incoming resources
Generate Create or synchronise supporting resources
Verify Images Verify image signatures and attestations
Cleanup Remove resources based on policy conditions
Policy Reports Record policy results and violations
Exceptions Allow controlled policy exclusions

By the end of this lab, you will have:

  • Installed Kyverno
  • Verified its controllers and webhooks
  • Created validation policies
  • Created mutation policies
  • Created a generation policy
  • Configured Audit mode
  • Configured Enforce mode
  • Required workload labels
  • Blocked privileged containers
  • Required non-root execution
  • Required resource controls
  • Restricted mutable image tags
  • Applied seccomp defaults
  • Disabled unnecessary Service Account token mounting
  • Reviewed policy reports
  • Tested policy exceptions
  • Produced an enterprise Kyverno assessment

Perform this lab only in an authorised training cluster.

Do not:

  • Apply untested policies directly to production
  • Place all new policies in Enforce mode immediately
  • Create broad exclusions without approval
  • Exclude security namespaces without documented justification
  • Delete policy reports before evidence collection
  • Disable Kyverno webhooks to bypass controls
  • Use mutation to hide insecure workload design
  • Assume a mutated workload is automatically production-ready

Before starting, ensure that you have:

  • A Kubernetes training cluster
  • kubectl
  • Helm
  • Cluster administrator permissions
  • Internet access
  • Visual Studio Code
  • Git Bash or PowerShell
  • Basic Kubernetes YAML knowledge
  • Completion of Lab 02 recommended
Tool Purpose
Kubernetes Policy enforcement platform
Kyverno Kubernetes-native policy engine
Helm Kyverno installation
kubectl Cluster administration and testing
jq JSON review
VS Code Policy development
Git Bash / PowerShell Command execution
lab-03-kyverno-policies/
├── policies/
│ ├── validate-required-labels.yaml
│ ├── validate-non-root.yaml
│ ├── validate-no-privileged.yaml
│ ├── validate-resources.yaml
│ ├── validate-image-digest.yaml
│ ├── validate-seccomp.yaml
│ ├── mutate-security-defaults.yaml
│ ├── mutate-disable-token.yaml
│ └── generate-network-policy.yaml
├── exceptions/
│ └── temporary-policy-exception.yaml
├── manifests/
│ ├── compliant-deployment.yaml
│ ├── missing-labels.yaml
│ ├── root-container.yaml
│ ├── privileged-container.yaml
│ ├── missing-resources.yaml
│ ├── mutable-image.yaml
│ ├── missing-seccomp.yaml
│ └── mutation-test.yaml
├── reports/
│ ├── policy-inventory.md
│ ├── audit-results.md
│ ├── enforcement-results.md
│ ├── exception-review.md
│ └── kyverno-governance-report.md
└── evidence/
├── kyverno-version.txt
├── kyverno-pods.txt
├── webhook-configurations.txt
├── policy-results.txt
├── policy-reports.txt
└── admission-events.txt
Terminal window
mkdir -p lab-03-kyverno-policies/{policies,exceptions,manifests,reports,evidence}
cd lab-03-kyverno-policies
Terminal window
New-Item -ItemType Directory -Force `
-Path lab-03-kyverno-policies\policies
New-Item -ItemType Directory -Force `
-Path lab-03-kyverno-policies\exceptions
New-Item -ItemType Directory -Force `
-Path lab-03-kyverno-policies\manifests
New-Item -ItemType Directory -Force `
-Path lab-03-kyverno-policies\reports
New-Item -ItemType Directory -Force `
-Path lab-03-kyverno-policies\evidence
Set-Location lab-03-kyverno-policies
Terminal window
kubectl cluster-info

Review the current context.

Terminal window
kubectl config current-context

Review permissions.

Terminal window
kubectl auth can-i create clusterpolicies.kyverno.io

Expected:

yes

Task 03 — Add the Kyverno Helm Repository

Section titled “Task 03 — Add the Kyverno Helm Repository”
Terminal window
helm repo add kyverno https://kyverno.github.io/kyverno/

Update repositories.

Terminal window
helm repo update

Review available chart versions.

Terminal window
helm search repo kyverno/kyverno
Terminal window
helm install kyverno kyverno/kyverno \
--namespace kyverno \
--create-namespace

Wait for the installation.

Terminal window
kubectl get pods \
-n kyverno \
-w

Review Pods.

Terminal window
kubectl get pods \
-n kyverno

Review Deployments.

Terminal window
kubectl get deployments \
-n kyverno

Typical components include:

  • Admission Controller
  • Background Controller
  • Cleanup Controller
  • Reports Controller

Save evidence.

Terminal window
kubectl get pods \
-n kyverno \
-o wide \
> evidence/kyverno-pods.txt
Terminal window
helm list \
-n kyverno
Terminal window
helm status kyverno \
-n kyverno

Save the installed chart and application version.

Terminal window
helm list \
-n kyverno \
> evidence/kyverno-version.txt
Terminal window
kubectl get crds | grep kyverno

Review resources such as:

  • ClusterPolicy
  • Policy
  • PolicyException
  • AdmissionReport
  • ClusterAdmissionReport
  • PolicyReport
  • ClusterPolicyReport
Terminal window
kubectl get validatingwebhookconfigurations
Terminal window
kubectl get mutatingwebhookconfigurations

Save evidence.

Terminal window
kubectl get validatingwebhookconfigurations \
> evidence/webhook-configurations.txt
Terminal window
kubectl get mutatingwebhookconfigurations \
>> evidence/webhook-configurations.txt

Create manifests/namespace.yaml.

apiVersion: v1
kind: Namespace
metadata:
name: kyverno-lab
labels:
environment: training
owner: cloud-security
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io-audit: restricted
pod-security.kubernetes.io/warn: restricted

Apply it.

Terminal window
kubectl apply \
-f manifests/namespace.yaml

Task 10 — Understand Kyverno Validation Modes

Section titled “Task 10 — Understand Kyverno Validation Modes”

Kyverno validation policies commonly operate in two modes.

  • Records policy violations
  • Allows resource creation
  • Supports staged rollout
  • Helps identify existing non-compliance
  • Rejects non-compliant resources
  • Prevents insecure configurations
  • Should be used after testing and remediation

Recommended enterprise rollout:

Policy Development
Development Testing
Audit Mode
Violation Review
Remediation
Enforce Mode

Task 11 — Create a Required Labels Policy

Section titled “Task 11 — Create a Required Labels Policy”

Create policies/validate-required-labels.yaml.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-enterprise-labels
annotations:
policies.kyverno.io/title: Require Enterprise Labels
policies.kyverno.io/category: Governance
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Deployment
policies.kyverno.io/description: >-
Requires application, owner, and environment labels on Deployments.
spec:
validationFailureAction: Audit
background: true
rules:
- name: validate-required-labels
match:
any:
- resources:
kinds:
- Deployment
namespaces:
- kyverno-lab
validate:
message: >-
Deployments must define app, owner, and environment labels.
pattern:
metadata:
labels:
app: "?*"
owner: "?*"
environment: "?*"
spec:
template:
metadata:
labels:
app: "?*"
owner: "?*"
environment: "?*"

Apply it.

Terminal window
kubectl apply \
-f policies/validate-required-labels.yaml

Verify.

Terminal window
kubectl get clusterpolicy require-enterprise-labels

Task 12 — Test Missing Labels in Audit Mode

Section titled “Task 12 — Test Missing Labels in Audit Mode”

Create manifests/missing-labels.yaml.

apiVersion: apps/v1
kind: Deployment
metadata:
name: missing-labels
namespace: kyverno-lab
spec:
replicas: 1
selector:
matchLabels:
app: missing-labels
template:
metadata:
labels:
app: missing-labels
spec:
containers:
- name: application
image: nginx:1.27-alpine

Apply it.

Terminal window
kubectl apply \
-f manifests/missing-labels.yaml

Expected:

  • Resource is allowed because the policy is in Audit mode.
  • A policy violation is recorded.
Terminal window
kubectl get policyreports \
-A

Describe the report.

Terminal window
kubectl describe policyreport \
-n kyverno-lab

Review:

  • Policy name
  • Rule name
  • Resource
  • Result
  • Severity
  • Message

Task 14 — Switch Required Labels to Enforce Mode

Section titled “Task 14 — Switch Required Labels to Enforce Mode”

Edit the policy.

spec:
validationFailureAction: Enforce

Apply the updated policy.

Terminal window
kubectl apply \
-f policies/validate-required-labels.yaml

Delete the earlier test Deployment.

Terminal window
kubectl delete deployment missing-labels \
-n kyverno-lab

Attempt to recreate it.

Terminal window
kubectl apply \
-f manifests/missing-labels.yaml

Expected:

Admission denied

Create policies/validate-non-root.yaml.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-non-root-containers
annotations:
policies.kyverno.io/title: Require Non-Root Containers
policies.kyverno.io/category: Pod Security
policies.kyverno.io/severity: high
spec:
validationFailureAction: Enforce
background: true
rules:
- name: require-run-as-non-root
match:
any:
- resources:
kinds:
- Pod
namespaces:
- kyverno-lab
validate:
message: >-
Pods must set runAsNonRoot to true at Pod or container level.
anyPattern:
- spec:
securityContext:
runAsNonRoot: true
- spec:
containers:
- securityContext:
runAsNonRoot: true

Apply it.

Terminal window
kubectl apply \
-f policies/validate-non-root.yaml

Create manifests/root-container.yaml.

apiVersion: v1
kind: Pod
metadata:
name: root-container
namespace: kyverno-lab
labels:
app: root-container
owner: cloud-security
environment: training
spec:
securityContext:
runAsUser: 0
containers:
- name: application
image: nginx:1.27-alpine
securityContext:
runAsNonRoot: false

Apply it.

Terminal window
kubectl apply \
-f manifests/root-container.yaml

Expected:

Admission denied

Create policies/validate-no-privileged.yaml.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-privileged-containers
annotations:
policies.kyverno.io/title: Disallow Privileged Containers
policies.kyverno.io/category: Pod Security
policies.kyverno.io/severity: critical
spec:
validationFailureAction: Enforce
background: true
rules:
- name: block-privileged-containers
match:
any:
- resources:
kinds:
- Pod
namespaces:
- kyverno-lab
validate:
message: Privileged containers are prohibited.
pattern:
spec:
containers:
- securityContext:
privileged: "false"

Apply it.

Terminal window
kubectl apply \
-f policies/validate-no-privileged.yaml

Create manifests/privileged-container.yaml.

apiVersion: v1
kind: Pod
metadata:
name: privileged-container
namespace: kyverno-lab
labels:
app: privileged-container
owner: cloud-security
environment: training
spec:
securityContext:
runAsNonRoot: true
containers:
- name: application
image: nginx:1.27-alpine
securityContext:
privileged: true
runAsNonRoot: true

Apply it.

Terminal window
kubectl apply \
-f manifests/privileged-container.yaml

Expected:

Admission denied

Task 19 — Create a Resource Requirements Policy

Section titled “Task 19 — Create a Resource Requirements Policy”

Create policies/validate-resources.yaml.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-resource-requests-and-limits
annotations:
policies.kyverno.io/title: Require Resource Requests and Limits
policies.kyverno.io/category: Reliability
policies.kyverno.io/severity: medium
spec:
validationFailureAction: Enforce
background: true
rules:
- name: validate-container-resources
match:
any:
- resources:
kinds:
- Pod
namespaces:
- kyverno-lab
validate:
message: >-
Every container must define CPU and memory requests and limits.
pattern:
spec:
containers:
- resources:
requests:
cpu: "?*"
memory: "?*"
limits:
cpu: "?*"
memory: "?*"

Apply it.

Terminal window
kubectl apply \
-f policies/validate-resources.yaml

Create manifests/missing-resources.yaml.

apiVersion: v1
kind: Pod
metadata:
name: missing-resources
namespace: kyverno-lab
labels:
app: missing-resources
owner: cloud-security
environment: training
spec:
securityContext:
runAsNonRoot: true
containers:
- name: application
image: nginx:1.27-alpine
securityContext:
privileged: false
runAsNonRoot: true

Apply it.

Terminal window
kubectl apply \
-f manifests/missing-resources.yaml

Expected:

Admission denied

Task 21 — Require Immutable Image Digests

Section titled “Task 21 — Require Immutable Image Digests”

Create policies/validate-image-digest.yaml.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-image-digests
annotations:
policies.kyverno.io/title: Require Image Digests
policies.kyverno.io/category: Software Supply Chain
policies.kyverno.io/severity: high
spec:
validationFailureAction: Audit
background: true
rules:
- name: validate-image-digest
match:
any:
- resources:
kinds:
- Pod
namespaces:
- kyverno-lab
validate:
message: >-
Container images must be referenced using an immutable sha256 digest.
foreach:
- list: request.object.spec.containers
deny:
conditions:
all:
- key: "{{ element.image }}"
operator: NotMatches
value: "*@sha256:*"

Apply it.

Terminal window
kubectl apply \
-f policies/validate-image-digest.yaml

Task 22 — Test a Mutable Image Reference

Section titled “Task 22 — Test a Mutable Image Reference”

Create manifests/mutable-image.yaml.

apiVersion: v1
kind: Pod
metadata:
name: mutable-image
namespace: kyverno-lab
labels:
app: mutable-image
owner: cloud-security
environment: training
spec:
securityContext:
runAsNonRoot: true
containers:
- name: application
image: nginx:1.27-alpine
securityContext:
privileged: false
runAsNonRoot: true
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi

Apply it.

Terminal window
kubectl apply \
-f manifests/mutable-image.yaml

Because the policy is in Audit mode, the Pod may be admitted while the violation is reported.

Review the report before moving the policy to Enforce mode.

Create policies/validate-seccomp.yaml.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-runtime-default-seccomp
annotations:
policies.kyverno.io/title: Require RuntimeDefault Seccomp
policies.kyverno.io/category: Pod Security
policies.kyverno.io/severity: high
spec:
validationFailureAction: Enforce
background: true
rules:
- name: require-seccomp
match:
any:
- resources:
kinds:
- Pod
namespaces:
- kyverno-lab
validate:
message: >-
Pods must use the RuntimeDefault seccomp profile.
pattern:
spec:
securityContext:
seccompProfile:
type: RuntimeDefault

Apply it.

Terminal window
kubectl apply \
-f policies/validate-seccomp.yaml

Create manifests/missing-seccomp.yaml.

apiVersion: v1
kind: Pod
metadata:
name: missing-seccomp
namespace: kyverno-lab
labels:
app: missing-seccomp
owner: cloud-security
environment: training
spec:
securityContext:
runAsNonRoot: true
containers:
- name: application
image: nginx:1.27-alpine
securityContext:
privileged: false
runAsNonRoot: true
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi

Apply it.

Terminal window
kubectl apply \
-f manifests/missing-seccomp.yaml

Expected:

Admission denied

Task 25 — Create a Security Defaults Mutation Policy

Section titled “Task 25 — Create a Security Defaults Mutation Policy”

Create policies/mutate-security-defaults.yaml.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: add-security-defaults
annotations:
policies.kyverno.io/title: Add Security Defaults
policies.kyverno.io/category: Pod Security
policies.kyverno.io/severity: medium
spec:
rules:
- name: add-pod-security-context
match:
any:
- resources:
kinds:
- Pod
namespaces:
- kyverno-lab
mutate:
patchStrategicMerge:
spec:
securityContext:
+(runAsNonRoot): true
+(seccompProfile):
type: RuntimeDefault
containers:
- (name): "*"
securityContext:
+(allowPrivilegeEscalation): false
+(privileged): false
+(readOnlyRootFilesystem): true
+(capabilities):
drop:
- ALL

Apply it.

Terminal window
kubectl apply \
-f policies/mutate-security-defaults.yaml

Create manifests/mutation-test.yaml.

apiVersion: v1
kind: Pod
metadata:
name: mutation-test
namespace: kyverno-lab
labels:
app: mutation-test
owner: cloud-security
environment: training
spec:
containers:
- name: application
image: nginx:1.27-alpine
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi

Apply it.

Terminal window
kubectl apply \
-f manifests/mutation-test.yaml

Inspect the resulting Pod.

Terminal window
kubectl get pod mutation-test \
-n kyverno-lab \
-o yaml

Review whether Kyverno added:

  • runAsNonRoot
  • RuntimeDefault seccomp
  • allowPrivilegeEscalation: false
  • privileged: false
  • readOnlyRootFilesystem: true
  • Dropped capabilities

Task 27 — Mutate Service Account Token Mounting

Section titled “Task 27 — Mutate Service Account Token Mounting”

Create policies/mutate-disable-token.yaml.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disable-service-account-token-mount
annotations:
policies.kyverno.io/title: Disable Service Account Token Mount
policies.kyverno.io/category: Identity
policies.kyverno.io/severity: medium
spec:
rules:
- name: disable-automatic-token-mount
match:
any:
- resources:
kinds:
- Pod
namespaces:
- kyverno-lab
mutate:
patchStrategicMerge:
spec:
+(automountServiceAccountToken): false

Apply it.

Terminal window
kubectl apply \
-f policies/mutate-disable-token.yaml

Create a new Pod and verify:

Terminal window
kubectl get pod <pod-name> \
-n kyverno-lab \
-o jsonpath='{.spec.automountServiceAccountToken}{"\n"}'

Expected:

false

Task 28 — Create a Generated NetworkPolicy

Section titled “Task 28 — Create a Generated NetworkPolicy”

Create policies/generate-network-policy.yaml.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: generate-default-deny-network-policy
annotations:
policies.kyverno.io/title: Generate Default Deny NetworkPolicy
policies.kyverno.io/category: Network Security
policies.kyverno.io/severity: high
spec:
rules:
- name: generate-default-deny
match:
any:
- resources:
kinds:
- Namespace
names:
- kyverno-lab-generated
generate:
generateExisting: true
synchronize: true
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
name: default-deny-all
namespace: "{{ request.object.metadata.name }}"
data:
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress

Apply it.

Terminal window
kubectl apply \
-f policies/generate-network-policy.yaml

Create the namespace.

Terminal window
kubectl create namespace kyverno-lab-generated

Verify the generated policy.

Terminal window
kubectl get networkpolicy \
-n kyverno-lab-generated
Terminal window
kubectl get clusterpolicies

Describe a policy.

Terminal window
kubectl describe clusterpolicy require-non-root-containers

Review:

  • Validation failure action
  • Background scanning
  • Rule count
  • Readiness
  • Generated resources
  • Policy conditions
Terminal window
kubectl get policyreports \
-A
Terminal window
kubectl get clusterpolicyreports

Export policy-report evidence.

Terminal window
kubectl get policyreports \
-A \
-o yaml \
> evidence/policy-reports.txt
Terminal window
kubectl get admissionreports \
-A
Terminal window
kubectl get clusteradmissionreports

Review recent policy decisions and affected resources.

Task 32 — Review Kyverno Controller Logs

Section titled “Task 32 — Review Kyverno Controller Logs”

List controller Pods.

Terminal window
kubectl get pods \
-n kyverno

Review admission-controller logs.

Terminal window
kubectl logs \
-n kyverno \
deployment/kyverno-admission-controller

Review reports-controller logs.

Terminal window
kubectl logs \
-n kyverno \
deployment/kyverno-reports-controller

Search for:

  • Policy errors
  • Admission denials
  • Mutation failures
  • Background-scan failures
  • Webhook timeouts
  • Generate-policy failures

Create manifests/compliant-deployment.yaml.

apiVersion: apps/v1
kind: Deployment
metadata:
name: compliant-application
namespace: kyverno-lab
labels:
app: compliant-application
owner: cloud-security
environment: training
spec:
replicas: 2
selector:
matchLabels:
app: compliant-application
template:
metadata:
labels:
app: compliant-application
owner: cloud-security
environment: training
spec:
automountServiceAccountToken: false
securityContext:
runAsNonRoot: true
runAsUser: 101
runAsGroup: 101
seccompProfile:
type: RuntimeDefault
containers:
- name: application
image: nginx:1.27-alpine
ports:
- name: http
containerPort: 8080
securityContext:
privileged: false
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
volumeMounts:
- name: temporary-files
mountPath: /tmp
- name: cache
mountPath: /var/cache/nginx
- name: runtime
mountPath: /var/run
volumes:
- name: temporary-files
emptyDir: {}
- name: cache
emptyDir: {}
- name: runtime
emptyDir: {}

The digest policy is currently in Audit mode, allowing the tagged training image while recording the violation.

Apply it.

Terminal window
kubectl apply \
-f manifests/compliant-deployment.yaml

Monitor rollout.

Terminal window
kubectl rollout status \
deployment/compliant-application \
-n kyverno-lab

Task 34 — Validate the Mutated Deployment

Section titled “Task 34 — Validate the Mutated Deployment”

Review the created Pod.

Terminal window
kubectl get pods \
-n kyverno-lab
Terminal window
kubectl get pod <pod-name> \
-n kyverno-lab \
-o yaml

Confirm:

  • Security context exists
  • Service Account token mounting is disabled
  • Seccomp is configured
  • Capabilities are dropped
  • Resource controls exist
  • Required labels exist

Exceptions should be:

  • Business justified
  • Time limited
  • Resource specific
  • Policy specific
  • Approved
  • Logged
  • Reviewed
  • Automatically expired where possible

Document:

Exception ID:
Policy:
Rule:
Resource:
Namespace:
Business Justification:
Risk:
Compensating Controls:
Requested By:
Approved By:
Start Time:
Expiration Time:
Review Date:
Status:

Task 36 — Create a Temporary Policy Exception

Section titled “Task 36 — Create a Temporary Policy Exception”

Create exceptions/temporary-policy-exception.yaml.

apiVersion: kyverno.io/v2
kind: PolicyException
metadata:
name: temporary-image-tag-exception
namespace: kyverno
annotations:
cloudnova.io/owner: platform-security
cloudnova.io/expiry: "2026-08-01T18:00:00Z"
spec:
exceptions:
- policyName: require-image-digests
ruleNames:
- validate-image-digest
match:
any:
- resources:
kinds:
- Pod
namespaces:
- kyverno-lab
names:
- approved-exception-test

The API version and feature configuration must match the installed Kyverno version.

Apply only after validating support.

Terminal window
kubectl apply \
-f exceptions/temporary-policy-exception.yaml

Create a Pod named:

approved-exception-test

Use a tagged image.

Confirm:

  • The named resource receives the approved exception.
  • Other tagged-image workloads remain subject to policy.
  • The exception is visible and documented.
  • The expiration date is tracked operationally.

Task 38 — Compare Gatekeeper and Kyverno

Section titled “Task 38 — Compare Gatekeeper and Kyverno”

Complete the comparison.

Capability Gatekeeper Kyverno
Policy language Rego Kubernetes YAML
Validation Yes Yes
Mutation Yes Yes
Resource generation Limited / External Patterns Native Generate Rules
Image verification Additional integration Native policy capability
Background scanning Yes Yes
Policy reports Supported Supported
Kubernetes-native authoring Partial Strong
Learning curve Rego knowledge required Familiar YAML patterns
Best fit Complex policy logic Kubernetes-native policy operations

Document which engine is most appropriate for:

  • Platform governance
  • Security validation
  • Mutation
  • Resource generation
  • Image verification
  • Complex custom logic

Create reports/policy-inventory.md.

Policy Type Mode Scope Severity Owner
Require enterprise labels Validate Enforce kyverno-lab Medium Platform
Require non-root Validate Enforce kyverno-lab High Security
Disallow privileged Validate Enforce kyverno-lab Critical Security
Require resources Validate Enforce kyverno-lab Medium Platform
Require image digest Validate Audit kyverno-lab High DevSecOps
Require seccomp Validate Enforce kyverno-lab High Security
Add security defaults Mutate Active kyverno-lab Medium Platform
Disable token mount Mutate Active kyverno-lab Medium IAM
Generate NetworkPolicy Generate Active Selected namespace High Network Security

Task 40 — Perform the Enterprise Kyverno Assessment

Section titled “Task 40 — Perform the Enterprise Kyverno Assessment”

Complete the assessment.

Security Domain Expected Control Status
Kyverno availability Controllers healthy
Webhook security Webhooks active and trusted
Policy ownership Owner assigned
Policy documentation Purpose and risk documented
Audit rollout Tested before enforcement
Required labels Enforced
Non-root execution Enforced
Privileged containers Blocked
Resource controls Enforced
Image digests Audited or enforced
Seccomp Enforced
Service Account token Disabled where unnecessary
Mutation controls Reviewed
Generated resources Validated
Policy reports Reviewed
Exceptions Controlled and time limited
Controller logs Monitored
Policy changes Change controlled
Evidence Retained

Rate each area as:

  • Effective
  • Partially Effective
  • Ineffective
  • Not Applicable

Task 41 — Assign the Governance Risk Rating

Section titled “Task 41 — Assign the Governance Risk Rating”

Examples:

  • Kyverno unavailable in production
  • Admission webhook fail-open without approval
  • Privileged containers allowed
  • Broad policy bypass configured
  • Security policies deleted without authorisation
  • Untrusted policy changes applied directly to production

Examples:

  • Non-root policy absent
  • Digest enforcement absent
  • Seccomp not required
  • Service Account tokens mounted unnecessarily
  • Critical policies remain in Audit mode
  • Exceptions have no expiry
  • Mutation policy introduces insecure defaults

Examples:

  • Missing resource controls
  • Incomplete policy reports
  • Policy ownership unclear
  • Manual exception review
  • Missing policy documentation
  • Background scanning disabled

Examples:

  • Naming inconsistency
  • Missing annotations
  • Reporting format issue
  • Minor metadata gap

Task 42 — Create the Enterprise Governance Report

Section titled “Task 42 — Create the Enterprise Governance Report”

Create reports/kyverno-governance-report.md.

Assessment Title:
Enterprise Kyverno Policy Governance Assessment
Assessment Date:
Assessor:
Cluster:
Environment:
Kyverno Version:
Namespace:
Policies Reviewed:
Validation Policies:
Mutation Policies:
Generation Policies:
Policies in Audit Mode:
Policies in Enforce Mode:
Critical Violations:
High Violations:
Medium Violations:
Low Violations:
Required Labels:
Non-Root Enforcement:
Privileged Container Enforcement:
Resource Controls:
Image Digest Enforcement:
Seccomp Enforcement:
Service Account Token Control:
Generated Network Policies:
Policy Reports:
Controller Health:
Webhook Health:
Exception Count:
Expired Exceptions:
Policy Ownership:
Change-Control Status:
Critical Risks:
High Risks:
Medium Risks:
Low Risks:
Required Remediation:
Residual Risk:
Overall Rating:
Production Decision:
Approved
Conditionally Approved
Rejected
Approvals:
Kubernetes Security:
Platform Engineering:
Cloud Security:
Compliance:

Collect:

  • Kyverno version
  • Helm release
  • Controller Pods
  • CRDs
  • Webhooks
  • ClusterPolicies
  • Namespaced Policies
  • PolicyExceptions
  • Policy reports
  • Admission reports
  • Controller logs
  • Compliant workload
  • Rejected workload results
  • Mutated resource output
  • Generated NetworkPolicy
  • Policy inventory
  • Enterprise assessment
  • Governance report

Suggested filenames:

01-kyverno-version.txt
02-helm-release.txt
03-controller-pods.txt
04-kyverno-crds.txt
05-webhook-configurations.txt
06-clusterpolicies.yaml
07-policyexceptions.yaml
08-policyreports.yaml
09-admissionreports.yaml
10-controller-logs.txt
11-compliant-workload.yaml
12-rejected-workload-results.txt
13-mutated-resource.yaml
14-generated-networkpolicy.yaml
15-policy-inventory.md
16-enterprise-assessment.md
17-kyverno-governance-report.md

Delete test workloads.

Terminal window
kubectl delete pod \
mutation-test \
mutable-image \
--namespace kyverno-lab \
--ignore-not-found
Terminal window
kubectl delete deployment \
compliant-application \
--namespace kyverno-lab \
--ignore-not-found

Delete the generated namespace.

Terminal window
kubectl delete namespace kyverno-lab-generated \
--ignore-not-found

Delete the training namespace.

Terminal window
kubectl delete namespace kyverno-lab

Task 45 — Decide Whether to Retain Kyverno

Section titled “Task 45 — Decide Whether to Retain Kyverno”

Retain Kyverno when:

  • The cluster is dedicated to continued policy training.
  • Later labs depend on it.
  • The organisation is evaluating policy automation.
  • Policies and reports must remain available.

Remove it only when the cluster is temporary and no later lab depends on the installation.

Terminal window
helm uninstall kyverno \
-n kyverno
Terminal window
kubectl delete namespace kyverno

Do not remove Kyverno from a shared or production cluster without approved change control.

Control Status
Kyverno installed successfully
Admission Controller healthy
Background Controller healthy
Reports Controller healthy
Cleanup Controller healthy
Validating webhooks active
Mutating webhooks active
Policy ownership documented
Audit mode tested
Enforce mode tested
Required labels enforced
Non-root execution enforced
Privileged containers blocked
Resource controls enforced
Image digest policy configured
Seccomp profile enforced
Security defaults mutated
Service Account token mounting controlled
Supporting resources generated
Policy reports reviewed
Admission reports reviewed
Controller logs reviewed
Policy exceptions controlled
Exception expiry documented
Policy inventory completed
Evidence retained
Governance report approved
  • Restore unhealthy Kyverno controllers.
  • Remove unauthorised policy exclusions.
  • Block privileged containers.
  • Enforce non-root execution.
  • Correct failing webhooks.
  • Remove expired exceptions.
  • Investigate unauthorised policy changes.
  • Move critical policies from Audit to Enforce.
  • Require seccomp profiles.
  • Enforce resource controls.
  • Disable unnecessary Service Account token mounting.
  • Implement image digest enforcement.
  • Establish policy ownership.
  • Integrate policy reports with compliance monitoring.
  • Add signed-image verification.
  • Integrate Kyverno with GitOps.
  • Test policies in CI/CD before cluster deployment.
  • Automate exception expiry.
  • Implement central multi-cluster policy management.
  • Create policy maturity metrics.
  • Continuously evaluate policy performance and coverage.

By completing this lab, you will be able to:

  • Install and validate Kyverno
  • Create Kubernetes-native policies
  • Configure validation controls
  • Configure mutation rules
  • Generate supporting resources
  • Apply Audit and Enforce modes
  • Block privileged and root containers
  • Require resource controls
  • Enforce seccomp settings
  • Restrict mutable image references
  • Disable unnecessary token mounting
  • Review policy and admission reports
  • Manage controlled policy exceptions
  • Compare Kyverno with Gatekeeper
  • Produce enterprise policy-governance reports

What is the main advantage of Kyverno for Kubernetes teams?

Answer: Kyverno allows teams to create and manage policies using Kubernetes-native YAML without requiring a separate policy language for common Kubernetes governance use cases.

What is the difference between Audit and Enforce mode?

Answer: Audit mode records violations while allowing the resource, whereas Enforce mode rejects resources that violate policy.

What does a Kyverno mutation policy do?

Answer: It automatically modifies an incoming Kubernetes resource by adding or changing approved configuration before the resource is stored.

Why should mutation not replace secure application design?

Answer: Mutation can add standard defaults, but workload owners must still understand and maintain secure configurations rather than relying entirely on automatic changes.

What is the purpose of a generate policy?

Answer: A generate policy automatically creates or synchronises supporting Kubernetes resources when matching resources are created.

Why should policies first be tested in Audit mode?

Answer: Audit mode identifies affected workloads and operational impact before enforcement begins, reducing the risk of disrupting legitimate applications.

Why are policy exceptions high-risk?

Answer: Exceptions weaken enforcement and may create unmanaged security gaps when they are broad, permanent, undocumented, or not reviewed.

Why should immutable image digests be required?

Answer: Digests identify exact image content and prevent a mutable tag from resolving to a different image after approval.

Does Kyverno replace Pod Security Admission?

Answer: No. Kyverno complements Pod Security Admission and can enforce additional organisation-specific governance and compliance requirements.

What evidence should be retained for a Kyverno governance review?

Answer: Policies, controller health, webhook configuration, policy reports, admission reports, exceptions, enforcement tests, logs, findings, and approvals should be retained.

In this lab, you deployed Kyverno and implemented enterprise Kubernetes policy-as-code controls using native YAML resources.

You created validation policies to:

  • Require ownership and environment labels
  • Enforce non-root execution
  • Block privileged containers
  • Require resource requests and limits
  • Audit mutable image references
  • Require RuntimeDefault seccomp profiles

You also created mutation policies that:

  • Applied security defaults
  • Disabled unnecessary Service Account token mounting

In addition, you implemented a generate policy to create a default-deny NetworkPolicy automatically.

You tested policies in Audit and Enforce modes, reviewed PolicyReports and AdmissionReports, examined Kyverno controller logs, evaluated controlled exceptions, compared Kyverno with OPA Gatekeeper, and produced an enterprise governance assessment.

Kyverno provides a powerful Kubernetes-native approach to:

  • Prevent insecure configurations
  • Standardise workload defaults
  • Generate required supporting resources
  • Audit existing workloads
  • Automate compliance reporting
  • Enforce organisational governance at admission time

Next Lab: Lab 04 — Compliance Automation

In the next lab, you will automate Kubernetes compliance assessments by integrating CIS Benchmark checks, policy validation, image scanning, configuration analysis, policy reports, evidence collection, CI/CD security gates, compliance dashboards, and scheduled assessment workflows.