Post

Kubernetes Policy-as-Code using Kyverno and OPA Gatekeeper (Part 2)

Kubernetes Policy-as-Code using Kyverno and OPA Gatekeeper (Part 2)

In Part 1 of this series, we deployed the VULN-BANK application to Kubernetes and enforced Pod Security Standards using Kyverno ensuring that all containers ran as non-root users and that default CPU and memory limits were automatically injected when not defined. Now, in Part 2, we’ll take Kubernetes policy enforcement a step further by implementing OPA Gatekeeper.

While Kyverno focuses on policy management using simple Kubernetes-native YAML syntax, OPA Gatekeeper allows for more advanced, logic-driven policies using the Rego policy language which is ideal for compliance-heavy or logic-based restrictions.

What We’ll Cover

In this section, we’ll:

  • Install and configure OPA Gatekeeper in our cluster
  • Define a ConstraintTemplate and Constraint to block Pods that use hostNetwork: true or run in privileged mode
  • Test and validate our policies to ensure the cluster rejects insecure configurations
  • Test GitHub Actions to check policies on PRs

Use Case: Block Pods from Using Host Networking and Privileged Mode.

Scenario: As a security professional, we want to prevent applications deployed by the development team from using hostNetwork: true or running in privileged mode due to compliance with regulatory frameworks (e.g., PCI DSS or ISO 27001).

OPA Gatekeeper Implementation – Installation, Policy and Testing

Let’s begin by setting up OPA Gatekeeper.

Step 1: Install Gatekeeper via Helm

1
2
3
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm repo update
helm install gatekeeper gatekeeper/gatekeeper --namespace gatekeeper-system --create-namespace

Gatekeeper install

Verify Gatekeeper pods:

1
kubectl get pods -n gatekeeper-system -w

Gatekeeper pods

Gatekeeper ConstraintTemplates are written in Rego, packaged as CRDs and instantiated through Constraints. A ConstraintTemplate defines the policy logic. So, we’ll create a ConstraintTemplate and a Constraint in the next step.

Step 2: Create a Gatekeeper ConstraintTemplate

Create policies/gatekeeper/templates/block-hostnet-privileged.template.yaml:

The file content can be found here: GitHub Repository

Step 3: Apply Gatekeeper Constraint (to Enforce the Template)

A Constraint is an instance of a template that specifies where the policy should be enforced.

Create policies/gatekeeper/constraints/block-hostnet-privileged.constraint.yaml:

The file content can be found here: GitHub Repository

This ensures the Template is applied to Pod and common workload types (Gatekeeper evaluates the pod template inside workloads).

Apply OPA Gatekeeper Templates and Constraints:

1
2
kubectl apply -f k8s-policies/gatekeeper/templates/block-hostnet-privileged.template.yaml
kubectl apply -f k8s-policies/gatekeeper/constraints/block-hostnet-privileged.constraint.yaml

Apply Gatekeeper policies

Testing and Verification

Test hostNetwork:true

In project folder create k8s/bad-hostnet.yaml Pod, a Pod manifest to violate hostNetwork: true

The file content can be found here: GitHub Repository

Apply the pod manifest, it’s expected for the Gatekeeper to block it:

1
kubectl apply -f k8s/bad-hostnet.yaml

hostNetwork blocked

Test Privileged Container

Create a test Pod k8s/bad-privileged.yaml that violates privileged containers policy.

The file content can be found here: GitHub Repository

Apply the pod manifest, it’s expected Gatekeeper will block this as well:

1
kubectl apply -f k8s/bad-privileged.yaml

Privileged blocked

Tip: Gatekeeper has a local testing tool called gator that lets you validate templates and constraints offline before applying to a cluster, which is very handy in CI.

Why These Policies Matter

  • When hostNetwork is enabled, a Pod shares the host’s network namespace, this gives the Pod potential access to all host interfaces, ports and traffic, breaking network isolation.
  • Running a container in privileged mode gives it near-root access to the host, allowing kernel interactions and system modifications. Attackers could use this to escape the container or tamper with the host OS.
  • Regulatory standards like PCI DSS strictly prohibit this level of exposure. Denying privileged mode ensures compliance and prevents privilege escalation vectors.

Together, these Gatekeeper constraints fortify cluster boundaries, uphold compliance and ensure that only safe workloads are admitted thereby protecting both applications and infrastructure.

CI: GitHub Actions to Check Policies on PRs

We’d use Kyverno test action to validate YAMLs/Helm charts against policies during PRs. To do this, we’d set up two workflows in .github/workflows:

Kyverno Policy Check (Runs Kyverno Checks on Manifests)

In .github folder, create .github/workflows/kyverno-ci.yml

The file content can be found here: GitHub Repository

We’ll test for both manifests that don’t comply to the policies as well as test the compliant manifests.

Kyverno CI workflow

Kyverno CI results

Kyverno CI details

Kyverno CI logs

Kyverno CI compliant

Conclusion

In this two-part series, we’ve implemented a comprehensive Policy-as-Code solution for Kubernetes using both Kyverno and OPA Gatekeeper. We’ve:

  • Deployed a vulnerable application (VULN-BANK) in a local Kubernetes cluster
  • Enforced security best practices using Kyverno (non-root containers, resource limits)
  • Implemented compliance-focused policies using OPA Gatekeeper (blocking hostNetwork and privileged mode)
  • Integrated policy validation into CI/CD pipelines with GitHub Actions

This approach ensures that security and compliance are built into the development lifecycle, reducing human error and automatically enforcing organisational standards before workloads reach production.


Resources:

This post is licensed under CC BY 4.0 by the author.