> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Policy as Code with Gatekeeper

> Guide demonstrating how to use OPA Gatekeeper to define and deploy Kubernetes admission policies enforcing required labels, test enforcement modes, and safely audit violations

Built-in Kubernetes admission controllers like `LimitRanger` and `ResourceQuota` help govern cluster resources, but they are limited to resource-specific checks. For richer, custom policy enforcement — for example:

* requiring specific Kubernetes labels on every Pod,
* restricting container images to approved registries, or
* forbidding use of the `latest` tag —

you can extend the admission pipeline using Open Policy Agent (OPA) Gatekeeper.

This guide walks through a concise, safe workflow to author and roll out policies with Gatekeeper:

1. Verify Gatekeeper is running.
2. Create a `ConstraintTemplate` (policy definition containing Rego logic).
3. Apply a `Constraint` (policy instance) that enforces required labels on Pods.
4. Demonstrate `deny` and `dryrun` enforcement modes and how to audit violations safely.

## Prerequisites

* A Kubernetes cluster with Gatekeeper installed and reachable via `kubectl`.
* `kubectl` configured to the target cluster context.

## 1) Verify Gatekeeper components

Confirm the Gatekeeper pods are running:

```bash theme={null}
kubectl get pods -n gatekeeper-system
```

Example output:

```text theme={null}
NAME                                                  READY   STATUS    RESTARTS   AGE
gatekeeper-audit-65f8cb8f99-49x7d                     1/1     Running   0          16m
gatekeeper-controller-manager-5987474568-bz9tr        1/1     Running   0          16m
gatekeeper-controller-manager-5987474568-ksdgp        1/1     Running   0          16m
gatekeeper-controller-manager-5987474568-lm7zs        1/1     Running   0          16m
```

If Gatekeeper pods are not running, install or redeploy Gatekeeper before continuing. Gatekeeper integrates with the Kubernetes admission webhook to enforce policies at request time.

## 2) Create a ConstraintTemplate (policy definition)

A `ConstraintTemplate` serves two roles:

* It defines a new CRD so Gatekeeper can register a custom resource kind.
* It contains the Rego policy logic that Gatekeeper evaluates at admission time.

The following `ConstraintTemplate` defines a `RequiredLabels` kind and enforces that an object has a set of labels provided by the matching `Constraint`:

```yaml theme={null}
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: requiredlabels
spec:
  crd:
    spec:
      names:
        kind: RequiredLabels
  validation:
    openAPIV3Schema:
      type: object
      properties:
        labels:
          type: array
          items:
            type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package requiredlabels

        violation[{"msg": msg}] {
          provided := {label | label := input.review.object.metadata.labels[label]}
          required := {label | label := input.parameters.labels[_]}
          missing := required - provided
          count(missing) > 0
          msg := sprintf("missing required labels: %v", [missing])
        }
```

Apply the template:

```bash theme={null}
kubectl apply -f required-labels-template.yaml
```

When applied, Gatekeeper creates a new CRD for the `RequiredLabels` kind:

```bash theme={null}
kubectl get crd | grep requiredlabels
```

Example output:

```text theme={null}
requiredlabels.constraints.gatekeeper.sh     2026-04-15T16:11:26Z
```

This indicates the API now exposes a `RequiredLabels` resource you can instantiate.

## 3) Create a Constraint (policy instance)

A `Constraint` is an instance of the CRD created by the `ConstraintTemplate`. It configures:

* which resources the policy targets (`match`),
* the enforcement mode (`spec.enforcementAction`), and
* any parameters the template requires (`parameters`).

Example `RequiredLabels` constraint that enforces `team` and `environment` labels on `Pod` resources:

```yaml theme={null}
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: RequiredLabels
metadata:
  name: require-labels
spec:
  enforcementAction: deny
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
  parameters:
    labels:
      - team
      - environment
```

Key fields:

* `spec.enforcementAction`: one of `deny`, `dryrun`, or `warn`.
  * `deny` blocks requests that violate the constraint.
  * `dryrun` records violations but allows requests to succeed.
  * `warn` allows the request and emits a warning.
* `match.kinds`: restricts the constraint to specific API groups/kinds (here, core `Pod`).
* `parameters.labels`: available in Rego as `input.parameters.labels`.

Apply the constraint:

```bash theme={null}
kubectl apply -f require-labels-constraint.yaml
```

Inspect the constraint status and violations:

```bash theme={null}
kubectl describe requiredlabels.constraints.gatekeeper.sh require-labels
```

## Enforcement modes quick reference

| Mode | Behavior | Use case |
| - | - | - |
| `deny` | Blocks API requests that violate the constraint | Enforce policy after rollout and remediation |
| `dryrun` | Records violations but allows requests | Audit existing resources safely before enforcing |
| `warn` | Allows requests and emits warnings | Gentle guidance without blocking workloads |

## 4) Test the constraint

Create a namespace for testing if needed:

```bash theme={null}
kubectl create namespace policy-test
```

1. Pod without required labels (expected to be rejected when enforcementAction: deny)

File: `test-pod-no-labels.yaml`

```yaml theme={null}
apiVersion: v1
kind: Pod
metadata:
  name: unlabeled-pod
  namespace: policy-test
spec:
  containers:
    - name: nginx
      image: docker.io/library/nginx
```

Apply it:

```bash theme={null}
kubectl apply -f test-pod-no-labels.yaml -n policy-test
```

Expected rejection when the constraint is in `deny` mode:

```text theme={null}
Error from server (Forbidden): error when creating "test-pod-no-labels.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [require-labels] missing required labels: {"environment", "team"}
```

2. Pod with required labels (allowed)

File: `test-pod-with-labels.yaml`

```yaml theme={null}
apiVersion: v1
kind: Pod
metadata:
  name: labeled-pod
  namespace: policy-test
  labels:
    team: platform
    environment: prod
spec:
  containers:
    - name: nginx
      image: nginx
```

Apply it:

```bash theme={null}
kubectl apply -f test-pod-with-labels.yaml -n policy-test
```

Expected success:

```text theme={null}
pod/labeled-pod created
```

## Dryrun — audit without breaking workloads

A safe rollout strategy is to start in `dryrun` mode so you can discover which resources would be blocked, then remediate them before switching to `deny`.

Switch the constraint to `dryrun`:

```bash theme={null}
kubectl patch requiredlabels require-labels \
  --type=merge \
  -p '{"spec":{"enforcementAction":"dryrun"}}'
```

Now retry creating the unlabeled pod:

```bash theme={null}
kubectl apply -f test-pod-no-labels.yaml -n policy-test
```

It should be admitted:

```text theme={null}
pod/unlabeled-pod created
```

List pods in the test namespace:

```bash theme={null}
kubectl get pods -n policy-test
```

Example output:

```text theme={null}
NAME            READY   STATUS    RESTARTS   AGE
labeled-pod     1/1     Running   0          54s
unlabeled-pod   1/1     Running   0          13s
```

View recorded violations (example excerpt)

Use `kubectl describe` on the Constraint to review violations recorded while in `dryrun`. Example messages:

```text theme={null}
Enforcement Action: dryrun
Kind: Pod
Message: missing required labels: {"environment", "team"}
Name: unlabeled-pod
Namespace: policy-test
Version: v1
```

Violations may include other cluster resources (including system Pods) that lack the labels. Use this information to:

* identify which resources would be blocked,
* remediate or patch existing resources, or
* narrow the constraint `match` scope to avoid unintended impact.

Safe rollout pattern: start with `dryrun` to collect violations, remediate or adjust scope for failing resources, and then switch `enforcementAction` to `deny` to fully enforce the policy.

## Summary

* ConstraintTemplate: defines a new CRD and contains the Rego logic evaluated at admission.
* Constraint: an instance of that CRD that scopes the policy, supplies parameters, and sets enforcement behavior.
* Enforcement modes:
  * `deny` — block violating requests
  * `dryrun` — record violations but allow requests (use for auditing)
  * `warn` — allow and emit warnings
* Best practice: audit with `dryrun` first, remediate, then move to `deny`.

For more policies and examples:

* Gatekeeper policy library: [https://github.com/open-policy-agent/gatekeeper/tree/master/library](https://github.com/open-policy-agent/gatekeeper/tree/master/library)
* Gatekeeper documentation: [https://open-policy-agent.github.io/gatekeeper/](https://open-policy-agent.github.io/gatekeeper/)

> **[Watch Video](https://learn.kodekloud.com/user/courses/prep-course-certified-cloud-native-platform-engineer-cnpe/module/35a7fadb-02d8-4557-a819-2e4dcfa970cc/lesson/4808f9b3-7985-47bf-95e5-d3e2368d1aa5)**

> **[Practice Lab](https://learn.kodekloud.com/user/courses/prep-course-certified-cloud-native-platform-engineer-cnpe/module/35a7fadb-02d8-4557-a819-2e4dcfa970cc/lesson/ec93bd81-3b25-4469-9194-50fabe8b8a18)**


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.