Kyverno CEL policy controls help stop unsafe workloads before Kubernetes creates them. This guide installs Kyverno 1.19 with Helm, creates a clean policy workspace, tests policies in Audit mode, and then changes them to Deny mode after review.
How to Install Kyverno 1.19 and Secure Kubernetes Workloads with CEL
Table of Contents
- What You Will Build
- Requirements for Kyverno Setup
- Step 1: Create a Kyverno Project Folder
- Step 2: Add the Kyverno Helm Repository
- Step 3: Install Kyverno 1.19
- Step 4: Install the Kyverno CLI
- Step 5: Create a Safe Test Namespace
- Step 6: Understand Audit Mode and Deny Mode
- Step 7: Block Privileged Containers
- Step 8: Test the Privileged Container Rule
- Step 9: Require Non-Root Containers
- Step 10: Require CPU and Memory Requests and Limits
- Step 11: Restrict Host Network, PID, and IPC
- Step 12: Allow Only Approved Image Registries
- Step 13: Generate Namespace Baseline Resources
- Step 14: Test Namespace Resource Generation
- Step 15: Create a Compliant Test Pod
- Step 16: Review Policy Reports
- Step 17: Change Policies from Audit to Deny
- Step 18: Roll Back Safely
- Conclusion

What You Will Build
The goal is to build a practical Kubernetes security baseline that:
- Blocks privileged containers.
- Requires containers to run as non-root.
- Requires CPU and memory requests and limits.
- Blocks host network, PID, and IPC namespace access.
- Allows images only from approved registries.
- Creates basic resources automatically in new production namespaces.
- Lets you test every rule before it blocks real applications.
For full Kubernetes protection, you can use Kyverno together with runtime security like Falco. Kyverno checks manifests before workloads start, while Falco can detect suspicious behavior after a container is already running.
For the runtime security setup, you can check the Falco Runtime Security Setup on Kubernetes.
Requirements for Kyverno Setup
Before installing Kyverno, make sure you have access to a Kubernetes cluster and that kubectl is configured correctly.
You need:
-
A Kubernetes cluster.
-
A Linux machine, VPS, or admin workstation with access to that cluster.
-
kubectlinstalled. -
Helm 3 installed.
-
Cluster-admin permissions.
-
A test cluster or a non-critical namespace for the first policy tests.
Run these commands to check your local tools:
Check which Kubernetes cluster your terminal is connected to:
Then confirm that you can create Kyverno policy resources:
Both commands should return Yes. Do not start by enforcing these rules on system namespaces such as kube-system, kyverno, or the namespace where Falco runs. Start with a controlled application namespace first.
Step 1: Create a Kyverno Project Folder
Before creating YAML files, make a clear working folder on your admin machine. This keeps policies, test workloads, and future CI files in one place.
-
policies/stores Kyverno YAML policy files. -
workloads/stores good and bad example Pods for testing. -
tests/can store CI checks, test cases, or future Kyverno CLI test files.
This simple structure makes policies easier to manage in Git later.
Step 2: Add the Kyverno Helm Repository
Helm installs Kubernetes applications from charts. Kyverno publishes its official chart in the Kyverno Helm repository.
First, add the repository and download the newest chart information:
Check the chart versions that Helm can see:
Look for a Kyverno 1.19 release before continuing. Helm is the recommended Kyverno installation option because it supports repeatable configuration and upgrades.
Step 3: Install Kyverno 1.19
Kyverno runs several controllers inside your Kubernetes cluster. The admission controller is the most important step because it receives workload requests and checks them with your policies.
Install Kyverno in its own namespace:
Wait for the admission controller to be ready and check all Kyverno Pods:
The Pods should eventually show Running status. If a Pod is still starting, wait a little longer:
Press Ctrl+C once all required Pods are running. Confirm the installed Helm release:
Kyverno uses Kubernetes admission webhooks to inspect resources during creation and update requests. Confirm that its webhooks exist:
If the commands return Kyverno-related entries, the admission layer is installed.
Step 4: Install the Kyverno CLI
The Kyverno CLI lets you check policies with YAML files before you deploy them to Kubernetes. This is useful for local testing, CI pipelines, and GitOps workflows.
Set the Kyverno version and download the Linux AMD64 CLI archive:
Extract the archive and install the binary package:
Confirm the CLI works:
If you use ARM64, download the ARM64 build instead of the linux_x86_64 archive. Use the release files that match your server architecture.
Step 5: Create a Safe Test Namespace
Policies should not be enforced across the entire cluster immediately. A safer method is to target only namespaces with a specific label. Create a namespace for testing:
Add the label used by every workload policy:
Check the label:
All workload validation policies in this guide only apply to namespaces with this label:
This approach gives you control. You can test policies in policy-lab, then label a staging namespace, and only later label production application namespaces.
Step 6: Understand Audit Mode and Deny Mode
Before creating the first rule, understand the two policy actions:
-
Auditreports failures but lets the workload continue. -
Denyrejects workloads that do not meet the rule.
Always start in Audit mode. This lets you find workloads that need changes without breaking deployments. The policy configuration looks like this in Audit mode:
After testing and fixing workloads, change it to Deny mode:
Kyverno can create PolicyReports that show which workloads passed or failed. ValidatingPolicy includes policy reporting support for these CEL-based validation checks.
Step 7: Block Privileged Containers
A privileged container has deep access to the host. It can bypass many normal container isolation controls and should not be used for common application workloads. Create the policy file:
Save and exit. Then, apply the policy and check that Kubernetes created it:
The CEL expression checks every container in the Pod. It passes when privileged is missing or set to false. It fails only if a container sets:
Step 8: Test the Privileged Container Rule
You should test a policy with a failing workload before moving to the next policy. Create an unsafe test Pod:
First, run a local policy test:
Because the policy is in Audit mode, Kubernetes will allow the Pod to be created, but Kyverno should report a violation:
Check policy reports and delete the unsafe Pod after testing:
Step 9: Require Non-Root Containers
Running containers as root gives an attacker more power if the application is compromised. A safer default is to run the application process with a non-root UID. Create the policy file:
Apply it with:
This rule checks every regular container. It requires this field:
A stronger workload configuration also sets a fixed non-root UID:
The container image must support this user ID. If an application writes to protected paths or needs root-only ports, fix the image or its file permissions before enforcing this policy.
Step 10: Require CPU and Memory Requests and Limits
Resource settings protect the Kubernetes node and other workloads. Requests tell the scheduler what a Pod needs. Limits stop one container from using unlimited CPU or memory. Create the policy file:
Apply the policy:
A compliant container needs settings like these:
The policy checks whether values exist. It does not decide whether 100m or 128Mi is the correct size for your application. Set values based on real application usage, then monitor and adjust them.
Step 11: Restrict Host Network, PID, and IPC
Kubernetes Pods are normally isolated from the host. Settings such as hostNetwork, hostPID, and hostIPC weaken that separation. Create the policy file:
Then, apply it:
This policy allows the normal Kubernetes default, where these fields are unset or false. It rejects a Pod if it requests access such as:
Host access may be needed by certain infrastructure DaemonSets, node monitoring agents, or network components. This is why these policies target only labeled application namespaces and do not apply to system namespaces.
Step 12: Allow Only Approved Image Registries
Image registry rules help reduce the risk of deploying unreviewed images from unknown sources. They also help ensure that applications use your company registry, approved GitHub Container Registry organization, or another trusted registry. Create the policy file:
Apply the policy:
This policy validates the image path, not the image signature. For stronger supply-chain control, use Kyverno ImageValidatingPolicy for signature and verification when your organization is ready.
Step 13: Generate Namespace Baseline Resources
New namespaces often need the same base controls. Creating them manually is slow and easy to forget. A Kyverno GeneratingPolicy can create Kubernetes resources automatically after a matching resource is created. Kyverno supports CEL-based generation for this purpose.
This example automatically creates:
-
A default-deny ingress
NetworkPolicy. -
A
ResourceQuotato limit total resource use.
Create the file:
Apply with:
The generated default-deny ingress policy blocks incoming traffic to all Pods in the namespace until you create separate allow rules. This is a safe default, but it can stop application traffic if you do not add rules for ingress controllers, monitoring, DNS-related needs, or internal services.
The quota values are example values. Adjust CPU, memory, and Pod limits based on the namespace purpose and your cluster capacity.
Step 14: Test Namespace Resource Generation
Create a fresh namespace with the required label:
Add the label:
Check for the generated resources:
Check the NetworkPolicy:
Check the ResourceQuota:
If the resources do not appear, check the generating policy and Kyverno logs:
Step 15: Create a Compliant Test Pod
A good test needs both failing and passing examples. This Pod includes the settings required by the policies in this guide. Create the file:
Paste the YAML below. Replace the image registry name with one allowed by your registry policy:
Test it with the Kyverno CLI:
Then apply it to Kubernetes and check the Pod:
If the image does not exist in your registry, the Pod may fail to pull the image. That does not mean the policy failed. Check policy behavior separately from image availability:
Remove the test Pod when finished:
Step 16: Review Policy Reports
Audit mode is useful only if you review the results. Kyverno reports show whether a workload passed or failed each policy. List policy reports across all namespaces:
View reports from the test namespace:
Search for failures:
If you need more detail, check the admission controller logs:
Do not change a policy to Deny mode until the Audit reports show that your expected workloads are ready.
Step 17: Change Policies from Audit to Deny
After the test results look good, enforce one policy at a time. Start with the privileged container rule because it is clear and usually has fewer exceptions. Open the policy file:
Find this block and replace it with Deny:
Save the file and apply it:
Now try applying the unsafe privileged Pod again:
Kubernetes should reject the request because the Pod sets privileged: true. After that works, enforce the remaining policies:
Before enforcing each file, change its validationActions block from Audit to Deny.
Step 18: Roll Back Safely
If a policy blocks a workload unexpectedly, switch it back to Audit mode instead of deleting it immediately. Open the policy file:
Change the action back to:
Apply the file again:
To delete one policy, you can use:
To delete all policies:
To clean up the test namespaces, you can run:
Conclusion
Kyverno 1.19 gives Kubernetes teams a simple way to enforce workload security before containers start. Its newer CEL-based policy types let you write clear rules for privileged access, non-root users, resource limits, host namespace controls, trusted image sources, and generated namespace defaults.
Start every CEL policy in Audit mode, review results, fix workloads, then switch to Deny mode for one policy. This avoids surprise outages while building a stronger production security baseline.
For clusters that need stable performance and full infrastructure control, deploy Kubernetes on PerLod dedicated servers.
For current CEL syntax and policy fields, see the official Kyverno ValidatingPolicy documentation.