OPA/Gatekeeper Policy Enforcement in Kubernetes

OPA/Gatekeeper Policy Enforcement in Kubernetes

A zero-to-production guide to stopping risky workloads before they ever reach your cluster: how Open Policy Agent and Gatekeeper work, how to write and roll out rules safely, and how to run them at scale.

Imagine you run a large apartment building with 500 tenants. Every tenant has a key, and every tenant can move furniture in and out whenever they like. Most of them are careful. But one day someone installs a gas stove with no ventilation, another tenant blocks the fire exit with boxes, and a third one sets up a noisy workshop at midnight. Nobody did anything “illegal” in the sense of breaking into the building. They all had keys. What was missing was a set of house rules, and someone to check those rules at the door.

Kubernetes clusters behave in exactly the same way. Once a person or a pipeline has permission to create things, Kubernetes will happily accept almost any request. A container that runs with full administrator power on the host machine? Accepted. An image pulled from an unknown website? Accepted. A service exposed to the whole internet by accident? Accepted. This guide teaches you how to add the missing house rules using two tools that work together: Open Policy Agent (OPA) and Gatekeeper.

You do not need to know anything about policy engines to start. Every new word is explained when it first appears, every big idea comes with an everyday comparison, and every chapter builds on the one before it. By the end, you will understand how a single rule travels from a Git repository to a live decision on a production cluster handling millions of requests.

1Why Kubernetes Needs Guardrails

Before learning the tools, we need to understand the gap they fill. This chapter explains what Kubernetes already protects, and what it quietly leaves open.

What Kubernetes is, in one paragraph

Kubernetes is a system that runs software packaged in containers across many computers. You tell it what you want, for example “run five copies of my shopping website,” and it makes that happen. You describe what you want in files called manifests, and you send them to the Kubernetes API server, which is the front door of the cluster. Everything that happens in a cluster starts as a request to that front door.

What RBAC does and does not do

Kubernetes already has a built-in permission system called RBAC, which stands for Role-Based Access Control. RBAC answers one question: “Is this person allowed to perform this action on this kind of object?” For example, it can say that the payments team may create Pods in the payments namespace. A namespace is simply a named section of the cluster, like one floor of our apartment building.

But RBAC only looks at the kind of action and the kind of object. It does not look inside the object. If the payments team is allowed to create Pods, RBAC accepts a safe Pod and a dangerous Pod with the same enthusiasm. It never asks whether the Pod runs as the root user, whether it uses the “latest” image tag, or whether it pulls images from a trusted registry.

Everyday Analogy

RBAC is the key card that opens the building door. It tells the guard who you are and which floors you may enter. It does not tell anyone what you are carrying in your bag. Policy enforcement is the security scanner at the entrance that looks inside the bag and checks it against the house rules.

The kinds of mistakes policies prevent

Real clusters collect the same mistakes again and again. A short list of the most common ones shows why rules matter:

  • Privileged containers. A container that runs with extra powers can often break out and take over the machine it runs on.
  • Untrusted images. Pulling software from a random public registry may bring in malware or unpatched flaws.
  • Missing limits. A container without CPU and memory limits can eat the whole machine and starve its neighbors.
  • Open doors to the internet. A Service of type LoadBalancer can expose an internal tool to the world with one line of configuration.
  • Missing labels. Without an owner label, nobody knows who to call at 3 a.m. when a workload misbehaves, and cost reports cannot be split by team.
!
Real-World Warning

In 2018, security researchers reported that a large car maker’s cloud account was being used to mine cryptocurrency. The cause was a Kubernetes management console that had been left open without a password. One missing guardrail, and someone else was spending the company’s money. Incidents like this are why many organizations now treat “block it before it is created” as a basic requirement.

The scale problem

You can review ten manifests by hand. You cannot review ten thousand. Large companies run hundreds of clusters, with thousands of developers changing things all day. Human review does not scale, and checklists in a wiki are quickly forgotten. The only dependable approach is to teach the cluster itself to check every request automatically, every time, in the same way. That idea is called policy enforcement, and the rest of this guide is about doing it well.

2Policy as Code and Open Policy Agent

Here we meet the first of our two tools. OPA is the “brain” that makes decisions. It is useful far beyond Kubernetes, which is why it is worth understanding on its own.

What “policy as code” means

A policy is a rule written down, such as “every container image must come from our company registry.” Policy as code means you write that rule in a text file that a computer can read, store it in Git like any other source code, and let machines enforce it. This gives you the same benefits developers already enjoy with software: you can review changes, see who changed what and when, test rules before using them, and roll back a bad rule in seconds.

What OPA is

Open Policy Agent, usually shortened to OPA and pronounced “oh-pa,” is an open source, general-purpose policy engine. It is written in the Go language and became a graduated project of the Cloud Native Computing Foundation (CNCF) in early 2021, which is the foundation’s highest maturity level. “General-purpose” means OPA was not built only for Kubernetes. Companies use it to decide whether an API call is allowed, whether a Terraform plan is safe, whether a user may open a record in an application, and much more.

OPA works like a very fast question-answering machine. You hand it three things and it returns an answer:

Input

The question

A JSON document describing what is being attempted, such as a Pod that someone wants to create.

Policy

The rules

Logic written in a language called Rego that describes what is acceptable and what is not.

Data

The reference facts

Extra information the rules may need, such as a list of approved registries or a list of existing namespaces.

Decision

The answer

A result, also in JSON, such as “allowed” or a list of reasons why the request breaks a rule.

Separating deciding from enforcing

The most important design idea in OPA is that it only decides. It never blocks anything by itself. Some other system must ask OPA for a decision and then act on it. This separation is powerful because you can change your rules without touching the application that enforces them.

Everyday Analogy

Think of a courtroom. The judge reads the law and gives a verdict, but the judge does not walk around arresting people. Police officers carry out the verdict. In our story, OPA is the judge, and Kubernetes (through Gatekeeper) is the officer who acts on the verdict.

Who uses OPA in production

Publicly listed adopters of OPA include Netflix, Capital One, Goldman Sachs and Pinterest, among many others. They use it for authorizing service-to-service calls, controlling who can see what data, and checking cloud infrastructure and Kubernetes configuration. The common thread is that one engine and one language can serve many different places, so rules can be shared and taught once.

i
Key Idea

OPA does not understand Kubernetes on its own. It only understands JSON and rules. Something has to translate Kubernetes requests into questions OPA can answer, and has to manage the rules inside a cluster. That helper is Gatekeeper, which we meet in Chapter 4.

3Admission Control: The Checkpoint in Front of the Cluster

To enforce rules, we need a place in Kubernetes where every request can be inspected. That place already exists, and it is called admission control.

The journey of a request

When you run a command such as kubectl apply, nothing is created immediately. Your request travels through a series of steps inside the API server. First, the server checks who you are (authentication). Next, it checks what you are allowed to do (authorization, usually RBAC). Then comes the stage that matters most for us: admission control. Only after all of those checks pass does Kubernetes save the object into its database, which is called etcd.

flowchart LR
  A["kubectl or CI/CD pipeline"] --> B["API Server"]
  B --> C["Authentication"]
  C --> D["Authorization - RBAC"]
  D --> E["Mutating Admission"]
  E --> F["Schema Validation"]
  F --> G["Validating Admission - Gatekeeper webhook"]
  G --> H[("etcd storage")]
  G -.->|"deny"| X["Error returned to the user"]
Figure 1: Where Gatekeeper sits in the life of an API request

Two kinds of admission

Admission has two phases. In the mutating phase, controllers may change the request. For example, a controller may automatically add a default label or inject a helper container. In the validating phase, controllers can only say yes or no. They cannot change anything. Mutating runs first, so validating controllers see the final shape of the object. This order matters: a rule that checks for a label should run after the system that adds the label has finished its work.

Webhooks: asking an outside expert

Kubernetes ships with a few built-in admission controllers, such as one that applies resource quotas and one that enforces the Pod Security Standards. But no built-in list can cover every company’s rules. So Kubernetes offers dynamic admission webhooks. A webhook is simply a web address that the API server calls. For every matching request, the API server sends a package called an AdmissionReview, containing the object, and waits for a reply that says “allowed” or “denied,” with an optional message.

Everyday Analogy

Picture an airport. Passport control checks your identity (authentication). The ticket gate checks that you may board this flight (authorization). The baggage scanner looks inside your luggage (admission). If the scanner calls a specialist to look at a strange object, that phone call is the webhook, and the specialist’s answer decides whether your bag goes through.

Important limits to remember

  • Admission runs only when something is created, updated or deleted. It does not run when someone reads data.
  • Admission never looks back. Objects that already existed before a rule was written are not rechecked at admission time. This gap is the reason Gatekeeper also has an audit feature, covered in Chapter 11.
  • Each webhook has a failure policy. If the webhook server is down, “Fail” rejects the request, and “Ignore” lets it through. This choice has big consequences for both safety and availability, and we discuss it in Chapter 13.

4Meet Gatekeeper: OPA Made for Kubernetes

Gatekeeper is the bridge between OPA’s general decision engine and the specific needs of a Kubernetes cluster.

The early days: OPA with a sidecar

The first way to use OPA in Kubernetes was to run it next to a helper program called kube-mgmt. Policies were stored in ConfigMaps, which are simple Kubernetes objects that hold text. This worked, but it had real problems. There was no standard way to pass settings into a rule, so teams copied and pasted near-identical rules. There was no built-in report of which existing objects already broke the rules. Error messages and status were hard to see. Managing many rules felt like managing loose pieces of paper.

Gatekeeper version 3

Gatekeeper was created to fix these problems. It began as a joint effort between engineers from Google, Microsoft, Red Hat and Styra (the company that created OPA), and it lives as a sub-project of OPA in the CNCF. Version 3 made policy a native part of Kubernetes. Instead of ConfigMaps, rules and their settings are stored as Custom Resource Definitions (CRDs). A CRD is a way to teach Kubernetes about a brand-new kind of object. After Gatekeeper is installed, your cluster understands new object kinds such as ConstraintTemplate, and you manage them with the same kubectl commands you already know.

What Gatekeeper gives you

Prevent

Admission control

Checks every create and update request and rejects those that break a rule, with a clear message.

Detect

Audit

Regularly scans objects that already exist and reports which ones violate current rules.

Reuse

Parameterized templates

One rule can serve many teams by accepting settings, such as a list of allowed registries.

Fix

Mutation

Can automatically add or change fields, such as default labels, before the object is saved.

Observe

Status and metrics

Shows violations directly on the policy object and exposes numbers for monitoring tools.

Share

Policy library

A public collection of ready-made templates covering common security and compliance needs.

i
Naming Note

People often say “OPA” when they mean “Gatekeeper.” Strictly speaking, OPA is the engine and Rego is the language, while Gatekeeper is the Kubernetes-specific program that carries the engine inside the cluster. When someone says “OPA/Gatekeeper,” they mean the combination.

5Architecture and Components

Now we open the box. Gatekeeper is made of a few small parts, and each part has one clear job.

The big picture

Gatekeeper installs itself into its own namespace, usually called gatekeeper-system. Inside, it runs two main groups of Pods. One group handles live requests from the API server. The other group performs the periodic scans. Both groups carry a copy of the OPA engine inside their own program, so there is no separate OPA server to manage and no extra network hop between Gatekeeper and its rule engine.

flowchart TB
  subgraph Authors["Policy Authors"]
    Dev["Platform Engineer"]
    Git["GitOps Repository"]
  end
  subgraph Cluster["Kubernetes Cluster"]
    API["API Server"]
    ETCD[("etcd")]
    subgraph GK["gatekeeper-system namespace"]
      CM["Controller Manager Pods - webhook server, controllers, OPA engine"]
      AUD["Audit Pod - OPA engine"]
    end
  end
  PROM["Prometheus"]
  Dev --> Git
  Git -->|"apply templates and constraints"| API
  API  ETCD
  API -->|"AdmissionReview over HTTPS"| CM
  CM -->|"allow or deny"| API
  CM -->|"watch templates and constraints"| API
  AUD -->|"list existing resources"| API
  AUD -->|"write violations to constraint status"| API
  PROM -->|"scrape metrics"| CM
  PROM -->|"scrape metrics"| AUD
Figure 2: Gatekeeper components and how they talk to the Kubernetes API server

Component by component

ComponentWhat it doesWhy it exists
Controller managerRuns the webhook server that answers live admission calls, plus controllers that watch for new or changed templates and constraints.Handles the real-time path. Usually runs as several replicas for availability.
AuditPeriodically lists existing objects and checks each against all constraints, then writes the results back.Finds problems that admission cannot see, such as objects created before a rule existed.
Embedded OPA engineCompiles and runs the Rego logic inside each Gatekeeper process.Keeps decisions fast because no outside network call is needed.
Webhook configurationsTell the API server which requests to send to Gatekeeper.Creates the checkpoint described in Chapter 3.
Custom resource definitionsAdd object kinds such as ConstraintTemplate, Config and mutation objects.Lets you manage policy like any other Kubernetes object.
Certificate managementCreates and rotates the certificates that secure the connection from the API server.The webhook must use encrypted, trusted communication.

Why two sets of Pods?

The live path and the scanning path have very different needs. The live path must answer in milliseconds and must be highly available, so it runs several replicas that can share the load. The audit path is heavy, because it reads a lot of objects, but it can take its time. Keeping them separate means a slow scan can never make a live request wait.

Everyday Analogy

A supermarket has cashiers and it also has a night-shift inventory team. Cashiers serve customers right now and must never be slow. The inventory team walks the shelves checking for expired food, which takes hours but nobody is waiting on it. Gatekeeper’s webhook Pods are the cashiers, and the audit Pod is the inventory team.

6Constraint Templates and Constraints

This is the heart of how you use Gatekeeper day to day. It is a two-layer idea, and once you see it, everything else falls into place.

Layer one: the ConstraintTemplate

A ConstraintTemplate is a reusable recipe for a type of rule. It contains three things. First, the logic itself, written in Rego. Second, a description of what settings the rule accepts, called parameters. Third, the name of a new object kind that this template will create. For example, a template might define a rule type for “required labels” that accepts a list of label names as a setting.

When you apply a template, something clever happens. Gatekeeper reads it, compiles the logic, and automatically registers a brand-new CRD with the kind name you chose. If your template says its kind is K8sRequiredLabels, your cluster now understands that kind. By convention these names are written in CamelCase and often start with K8s.

Layer two: the Constraint

A Constraint is a single use of a template. It says where the rule applies and which settings to use. A constraint has three important parts:

  • Match. Which objects the rule applies to: which kinds (such as Pods or Namespaces), which namespaces, and optionally which labels.
  • Parameters. The settings passed to the template, such as “the required labels are owner and cost-center.”
  • Enforcement action. What to do when a violation is found: deny, warn, or just record it. Chapter 10 covers this in detail.
Everyday Analogy

A ConstraintTemplate is a blank form, like a “speed limit sign” design with a blank space for the number. A Constraint is one sign actually installed on a road: “30 km/h on School Street.” You design the sign once and install it in as many places as you want, each with its own number.

A worked example in words

Suppose your finance team needs every namespace to carry an owner label and a cost-center label so cloud bills can be split by team. You would take the required-labels template, either from the public library or written yourself. Then you would create one constraint of that kind. Its match section would say “apply to Namespaces.” Its parameters would list the two label names. Its enforcement action would start as record-only. From that moment on, any new namespace missing those labels is reported, and once you switch the action to deny, it is blocked with a message that names the missing labels.

1

Choose or write a template

Start from the community library whenever possible. Write your own only for needs it does not cover.

2

Apply the template

Gatekeeper compiles the logic and registers the new constraint kind. Check the template status to confirm it was accepted.

3

Create a constraint

Pick the scope, provide the parameters and choose an enforcement action.

4

Watch the results

Live requests are checked immediately, and the audit scan fills in the violations list on the constraint.

i
Tip

The public Gatekeeper policy library already includes templates for common needs: required labels, allowed image registries, blocking privileged containers, requiring resource limits, restricting host paths, forcing HTTPS on Ingress, and many more. Learn the library before writing your own rules.

7Rego in Plain Words

Rego is the language inside templates. You do not need to be a programmer to understand how it thinks, and this chapter explains the ideas without any code.

A different way of thinking

Most programming languages are written as instructions: do this, then do that. Rego is declarative, which means you describe the conditions under which something is true and let the engine figure out how to check them. A Rego rule reads like a sentence: “A violation exists when the object is a Pod, and one of its containers uses an image that does not start with an approved prefix.”

The pieces you must know

Input

The review object

Gatekeeper hands the rule the request being checked. The object itself, its operation and its namespace are all reachable from the input.

Parameters

Settings from the constraint

The lists and values set in a constraint appear in the input too, so one rule can behave differently per constraint.

Violation

The special rule name

Gatekeeper templates are built around a rule named violation. Each time it produces a result, a violation with a message is reported.

Conditions

All must be true

Inside one rule, every condition is joined by “and.” If any single condition fails, that rule produces nothing.

Multiple rules

Any may fire

Writing the same rule name several times works like “or.” If any copy succeeds, a violation is reported.

Iteration

Checks every item

Rego naturally loops over lists such as containers, so a single rule covers every container in a Pod.

An important safety property

In Gatekeeper, a rule that cannot find the field it needs simply produces no result. This is a common source of surprise. If a rule looks for a field that is missing from the object, the rule is silent, not angry. A policy author must think carefully about the case where the field is absent, because “missing” often means “unsafe.” For example, a container that has no security settings at all is usually more dangerous than one that sets them explicitly.

Everyday Analogy

Rego is like a list of reasons to reject a loan application. “Reject if income is below the minimum.” “Reject if the application is missing a signature.” The application is approved only when none of the reasons apply. Writing a new reason never requires rewriting the old ones, which is what makes large rule sets easy to grow.

!
Common Trap

Pods can be created directly or through higher-level objects such as Deployments, which create ReplicaSets, which create Pods. A rule written only for Pods runs when the final Pod appears, not when the Deployment is created. This means a bad Deployment can be accepted and then fail quietly later. Chapter 12 explains how expansion templates help teams catch this earlier.

8Internal Working: The Life of One Request

Let us follow a single Pod creation request from the developer’s keyboard to the final yes or no, step by step.

sequenceDiagram
  autonumber
  participant U as Developer
  participant A as API Server
  participant W as Gatekeeper Webhook
  participant O as OPA Engine
  participant E as etcd
  U->>A: kubectl apply Pod
  A->>A: Authenticate and authorize
  A->>W: AdmissionReview request
  W->>W: Find constraints that match
  W->>O: Evaluate templates with object and parameters
  O-->>W: List of violations
  alt Violations found with deny action
    W-->>A: allowed false with message
    A-->>U: Error: request denied
  else No violations
    W-->>A: allowed true
    A->>E: Persist object
    A-->>U: pod created
  end
Figure 3: Sequence of events for one admission decision

Step by step

1

Request arrives

The API server authenticates and authorizes the request, runs mutating admission, and then reaches the validating webhooks.

2

Webhook receives the review

Gatekeeper reads the AdmissionReview and first checks whether the namespace or user is exempt from policy.

3

Constraints are matched

Gatekeeper lists every constraint whose match section fits this object’s kind, namespace and labels. Constraints that do not fit are skipped entirely, saving time.

4

OPA evaluates each match

For each matching constraint, the engine runs the template’s logic with the object and the constraint’s parameters as input and collects any violations.

5

Actions are combined

Violations from constraints set to deny cause rejection. Violations from constraints set to warn are returned as warning messages. Violations from dry-run constraints are only recorded.

6

Response returns

The webhook sends allowed or denied back to the API server, which either saves the object or shows the developer the messages.

Why it is fast

Three design choices keep decisions quick. The OPA engine is embedded, so there is no extra network call. Templates are compiled once when applied, not on every request. And constraint matching filters out most rules before any Rego logic runs. In well-sized clusters, a typical decision takes only a few milliseconds up to a few tens of milliseconds, depending on how many policies match and how complex they are.

i
Good to Know

Gatekeeper returns all messages from all violated constraints in one reply. A developer fixing a Pod does not have to retry five times to find five problems. This is a small detail with a big effect on how much people like the system.

9Data Flow and Lifecycle of a Policy

A rule has a life of its own: it is written, tested, reviewed, delivered, enforced, and finally improved. Seeing the whole loop helps you build a process that is safe and repeatable.

flowchart LR
  A["Author writes template and constraint"] --> B["Test locally with the gator CLI"]
  B --> C["Pull request and peer review"]
  C --> D["Merge to main branch"]
  D --> E["GitOps tool syncs to cluster"]
  E --> F["Template is compiled and constraint kind registered"]
  F --> G["Constraint created in dry-run mode"]
  G --> H["Webhook and audit evaluate"]
  H --> I["Violations reviewed by owners"]
  I --> J["Switch to warn then deny"]
  J --> A
Figure 4: The end-to-end lifecycle of a Gatekeeper policy

Where the data lives

Gatekeeper keeps its important information in three places, and it helps to know which is which:

  • In etcd, as Kubernetes objects. Templates, constraints, and configuration are normal objects stored by the API server. They survive restarts, and they can be backed up like anything else in the cluster.
  • In memory, inside each Gatekeeper Pod. Compiled rules and any replicated cluster data live in memory so that evaluation is fast. If a Pod restarts, it rebuilds this memory from the API server.
  • In status fields and metrics. Results of audits are written onto the constraint objects, and counters are exposed for monitoring tools.

What happens when a policy changes

When you edit a template, each Gatekeeper Pod notices the change by watching the API server, recompiles the logic, and swaps in the new version. If the new logic has an error, the template reports the problem in its status and the old version is not silently replaced by a broken one. When you change a constraint, the very next admission request uses the new settings. There is no restart and no downtime, which is one of the big wins over older approaches.

Everyday Analogy

Think of how a city updates traffic laws. A new law is drafted, debated, announced, and then given a grace period where drivers get warnings instead of fines. Only after everyone has had time to adjust do fines begin. Gatekeeper’s lifecycle is the same: draft, review, warning period, enforcement.

i
Tip

Always store templates and constraints in Git and apply them through an automated pipeline. Editing policies by hand on a live cluster makes it impossible to know later who changed a rule, and it makes recovery after a mistake much harder.

10Enforcement Actions and Scoping

A good rule applied in the wrong place or at the wrong strength causes outages. This chapter shows how to control how hard a rule pushes and where it reaches.

Enforcement actions

ActionWhat the developer seesWhen to use it
denyThe request is rejected with a clear message. This is the default.For rules you are confident about and that everyone has had time to follow.
warnThe request succeeds, but a warning message appears in the command output.As a friendly step before deny, so teams learn about the rule without being blocked.
dryrunNothing visible at request time. Violations are only recorded by audit.For a brand-new rule, to learn how much existing work would break.

Newer versions of Gatekeeper also allow different actions at different enforcement points, for example deny during live admission but only record during audit. This is useful when you want strict control on new changes but do not want old objects to look like emergencies.

Scoping with match

Every constraint has a match section that narrows its reach. The main options are:

Kinds

Which object types

Pick API groups and kinds, such as Pods, Services or Namespaces.

Namespaces

Which namespaces

List the namespaces where the rule applies, or those where it must not.

Selectors

Which labels

Target objects by their own labels, or by the labels on the namespace they live in.

Scope

Cluster or namespaced

Limit a rule to cluster-wide objects or only to namespaced objects.

Exemptions: the safety valve

Some namespaces must never be blocked by your own rules. System namespaces such as kube-system run the components that keep the cluster alive. If a policy accidentally blocks one of those components from restarting, the cluster can enter a state that is hard to repair. Gatekeeper supports excluding namespaces in three ways: per constraint, through a cluster-wide configuration object that can exempt namespaces from the webhook, audit, or other processes, and through a special label that tells the webhook to ignore a namespace entirely.

Use Case: Gradual tightening at a retailer

A large online retailer wants every Pod to have resource limits. The platform team starts the rule as dry-run across all namespaces and finds that 40 percent of namespaces would fail. They send each owner a list, switch the rule to warn for a month, then switch to deny for production namespaces first and development namespaces later. Nobody’s deployment was surprised on the day enforcement started.

!
Common Trap

Do not exempt namespaces in a hurry and forget about them. A long list of “temporary” exemptions slowly turns into a hole in your defenses. Keep exemptions in version control with a comment explaining why each one exists, and review them regularly.

11Audit, Replicated Data and Referential Policies

Admission only guards the front door. Audit walks the halls looking at what is already inside, and replicated data lets rules compare one object with others.

How audit works

The audit Pod wakes up on a timer, with a default of every 60 seconds. It lists the objects in the cluster, checks each one against every matching constraint, and writes any violations onto the constraint object itself. You can then read the violations with a simple kubectl describe on the constraint. By default each constraint stores up to 20 violations, which keeps the object small, while the total violation count is still shown in metrics.

flowchart LR
  T["Timer fires every audit interval"] --> L["Audit lists existing resources"]
  L --> M["Match against each constraint"]
  M --> V["Evaluate with the OPA engine"]
  V --> S["Write violations to constraint status"]
  S --> P["Export metrics and logs"]
  P --> T
Figure 5: The repeating audit loop

Why audit matters

There are three situations where audit is the only thing that catches a problem. First, the object existed before the rule did. Second, the rule was in dry-run or warn mode when the object was created. Third, the webhook was unavailable and failing open, so the request slipped through. Audit is your safety net for all three, and it is also the feature that compliance teams love, because it gives an always-fresh report of how the cluster measures against its rules.

Everyday Analogy

A restaurant has a health inspector who checks every delivery at the back door (admission). The same restaurant also gets surprise kitchen inspections (audit), because food that was fine on delivery day can spoil in the fridge, and because the rules may have changed since the last visit.

Replicated data for referential rules

Some rules cannot be decided by looking at one object alone. For example, “no two Ingress objects may use the same hostname” requires knowing about all the other Ingress objects. To support this, Gatekeeper has a configuration object where you list which kinds of objects should be copied into the engine’s memory. Rules can then look through this copy, called the inventory, while making a decision.

!
Cost Warning

Every kind you replicate is stored in memory in every Gatekeeper Pod, and kept updated through watches on the API server. Replicating something large like all Pods or all Secrets in a big cluster can use a great deal of memory. Replicate only what your rules truly need, and nothing more.

Use Case: Preventing hostname collisions

A software-as-a-service company hosts many customer sites on shared clusters. One customer once accidentally claimed another customer’s domain name in an Ingress, and traffic went to the wrong place. The platform team added a referential rule that rejects any Ingress hostname already used by a different namespace. The mistake can no longer happen, and the rule needed only the Ingress kind in the replicated data.

12Mutation, Expansion and External Data

Gatekeeper can do more than say no. It can quietly fix common mistakes, understand objects that create other objects, and consult outside systems.

Mutation: fixing instead of blocking

Blocking a developer for forgetting something small is annoying, and it creates support tickets. Mutation lets Gatekeeper change the object on its way in. It uses its own set of object kinds. One kind (Assign) can set any field, for example to set a default pull policy. One (AssignMetadata) can add labels and annotations. One (ModifySet) can add or remove items from a list, such as extra arguments to a container. Newer versions also include a kind for rewriting image references, which is handy for redirecting images to an internal mirror.

Everyday Analogy

When you hand in a form with the date left blank, a friendly clerk might write today’s date for you instead of sending you to the back of the line. Mutation is that friendly clerk. Validation is the strict clerk who refuses forms with mistakes. A good office uses both.

i
Order Matters

Gatekeeper’s mutation runs in the mutating phase, so it always happens before validation. This means you can mutate a missing label into place and then validate that the label exists, and the validation will pass. Remember this when you wonder why a rule is not triggering.

Expansion: seeing the Pods hidden inside a Deployment

Remember the trap from Chapter 7: a rule that checks Pods does not fire when a Deployment is created, because the Pods do not exist yet. Expansion templates solve this. They tell Gatekeeper how a higher-level object, such as a Deployment, turns into Pods. Gatekeeper then builds an imaginary Pod, tests it against Pod rules, and can warn or reject the Deployment right away. Developers get fast feedback at the moment they apply the Deployment, not minutes later when Pods fail to appear.

External data: asking another system

Sometimes the facts needed to decide are not inside the cluster. For example, “has this image been scanned and signed?” is a question for an image-signing service. Gatekeeper’s external data feature lets a policy call a registered provider service during evaluation. Use this carefully. Every outside call adds time to the request, and a slow provider can slow every deployment in the cluster. Providers should be fast, highly available, and called only when truly needed.

The best policy is the one a developer never has to think about, because the platform already did the right thing for them.

13Security: Protecting the Guard Itself

A guard who can be tricked, bribed or switched off is not a guard. This chapter covers how to make sure Gatekeeper cannot be bypassed, and how to keep it from becoming a danger of its own.

The fail-open versus fail-closed decision

Every webhook has a failure policy that decides what happens when Gatekeeper cannot be reached. With “Ignore,” also called fail-open, the request is allowed. With “Fail,” also called fail-closed, the request is rejected. The standard Gatekeeper installation uses the first option, because rejecting everything whenever Gatekeeper has trouble can bring a cluster to a halt, including the very Pods that Gatekeeper needs in order to recover.

Fail open (Ignore)

  • Cluster keeps working if Gatekeeper is down
  • Safer for system recovery
  • Audit later catches objects that slipped through
  • Risk: an attacker who can overload the webhook may bypass rules

Fail closed (Fail)

  • No unchecked request ever gets in
  • Strongest guarantee for regulated environments
  • Risk: a Gatekeeper outage blocks all matching deployments
  • Needs excellent availability engineering to be safe

Many mature teams choose fail-open for general use and fail-closed only for a narrow set of high-risk resources, combined with several replicas, Pod disruption budgets and spreading Pods across zones.

Closing the common bypass paths

  • Protect the policy objects. Use RBAC so that only the platform team can create, change or delete templates, constraints and Gatekeeper configuration. Anyone who can delete a constraint can switch off the rule.
  • Protect the namespace. Restrict who can edit anything inside gatekeeper-system, including the webhook configuration objects.
  • Guard the ignore label. The label that makes a namespace skip the webhook is powerful. Write a rule, enforced by Gatekeeper itself, that only authorized users may add this label.
  • Cover all entry points. Policies should apply to Pods created through Deployments, Jobs, CronJobs and direct Pods. Remember that ephemeral containers and Pod updates are also paths worth checking.
  • Keep the webhook secure. Allow only the API server to reach the webhook with network policies where possible, and keep certificate rotation healthy.
  • Trust your supply chain. Install Gatekeeper from verified images, pin versions, and review any third-party template before using it. A template is code that runs inside your control plane path.
ANTI-PATTERN 01Avoid
What people do

They give every developer permission to edit constraints “to move faster” and exempt their own namespaces whenever a rule gets in the way.

Why it hurts

Policy becomes a suggestion. Within months, the exemptions outnumber the rules, and an auditor finds that the controls exist only on paper.

Better approach

Make exemptions a reviewed pull request with an owner and an expiry date. Give developers fast read access to violations so they can fix problems themselves, but keep write access to policies with the platform team.

Relation to the Pod Security Standards

Kubernetes has a built-in feature, Pod Security Admission, that enforces three broad levels of Pod safety: privileged, baseline and restricted. It replaced the older PodSecurityPolicy, which was removed in Kubernetes 1.25. Gatekeeper is a good companion to it: the built-in feature covers the standard Pod safety baseline cheaply, and Gatekeeper handles all the company-specific rules that the built-in one cannot express.

14Monitoring, Logging and Metrics

You cannot trust what you cannot see. Gatekeeper gives you three windows into its behavior: status fields, logs and metrics.

Window one: status on the objects

The easiest place to look is the constraint itself. Its status shows the time of the last audit, the total number of violations, and the list of the first few violating objects with their messages. The template status shows whether each Gatekeeper Pod accepted the template, and surfaces compile errors. When something seems wrong, always check these two statuses first.

Window two: logs

Gatekeeper logs in a structured format. The webhook can log every denied request, and the audit Pod logs each violation it finds along with the audit run it belongs to. In a busy cluster, denied-request logs can be noisy, so send them to a central logging system and search by constraint name or namespace. Logs are also where you learn that the webhook is rejecting requests for technical reasons, such as certificate trouble.

Window three: metrics

Gatekeeper exposes metrics in the Prometheus format, a widely used monitoring standard. Exact names can differ slightly between versions, but the useful families are:

Requests

Request count and latency

How many admission requests were processed, split by allowed or denied, and how long each took.

Violations

Violation totals

Current violations by constraint and enforcement action, as found by the last audit.

Audit

Audit duration and last run

How long scans take and when the last one finished. A stale timestamp means the audit is stuck.

Inventory

Templates and constraints

How many templates and constraints are loaded and whether any are in an error state.

Alerts worth setting

  • Admission latency crossing a safe fraction of the webhook timeout.
  • No successful audit in several audit intervals.
  • A sudden jump in denied requests, which may mean a bad rule or a bad deployment pipeline.
  • Gatekeeper Pods restarting, being out of memory, or unavailable.
  • Templates in error state.
Everyday Analogy

The cockpit of an airplane has gauges, warning lights and a flight recorder. Status fields are the gauges you glance at, metrics are the warning lights that trigger alarms, and logs are the flight recorder you study after something unusual happens.

15Performance and Scalability

Gatekeeper sits on the critical path of every deployment. If it is slow, everything is slow. This chapter shows how to keep it fast at the scale of large organizations.

3 s
default webhook timeout in a standard install
60 s
default time between audit runs
20
default stored violations per constraint

What affects admission speed

  • Number of matching constraints. Each match means running Rego. Narrow matches, such as by kind and namespace, keep this small.
  • Rule complexity. Rules that loop over big lists, or compare every object against every other object, cost more than simple field checks.
  • Replicated data size. Referential rules that scan large inventories get slower as the cluster grows.
  • External data calls. Each outside call adds network time and a new way to fail.
  • Machine resources. Too little CPU makes evaluation queue up. Too little memory causes restarts.

Scaling the live path

Run multiple replicas of the controller manager, typically three or more in production, and spread them across failure zones. Requests from the API server are balanced across them. Give the Pods proper CPU and memory requests so Kubernetes places them on healthy machines. Use Pod disruption budgets so that a node upgrade never takes down all replicas at once. For very high request rates, add replicas before adding bigger machines, since evaluation of separate requests is independent and spreads well.

Scaling the audit path

Audit cost grows with the number of objects and constraints. For clusters with hundreds of thousands of objects, tune the audit interval to a longer period, lower the chunk size so memory stays bounded, and restrict audited kinds to those you really care about. Avoid enabling audit for kinds that change constantly and add little compliance value.

Everyday Analogy

A busy airport adds more security lanes when queues grow, rather than asking one officer to work faster. Adding replicas is adding lanes. Narrow matching is like letting only passengers with carry-on bags into the detailed bag-check lane, while everyone else walks straight through.

i
Tip

Load-test your policy set before a big rollout. Create many objects quickly in a staging cluster with the full set of constraints active, and watch the latency metric. A rule that takes one millisecond is invisible, but one that takes one second would multiply painfully across a cluster running thousands of deployments an hour.

16Testing and Rolling Out Policies Safely

The fastest way to lose trust in a policy system is to break production with a surprise. A calm, repeatable rollout process is what separates mature platform teams from the rest.

Test before you ship

Gatekeeper provides a command-line tool called gator. It lets you run templates and constraints against sample objects on your own computer or in your build pipeline, with no cluster needed. It can also run formal test suites that state which sample objects must pass and which must fail, so that every future change to a template is checked automatically. A good test suite includes at least one passing example, one failing example, and one tricky edge case, such as an object with the checked field missing.

A safe rollout path

1

Write and test locally

Use gator in your build pipeline so no untested rule reaches Git’s main branch.

2

Deploy in dry-run

Let audit show how many existing objects would break. This is the true size of the change.

3

Communicate with owners

Share violation lists with the teams that own each namespace and give them a clear deadline and a clear fix.

4

Move to warn

Developers now see messages whenever they deploy something that breaks the rule, but nothing is blocked.

5

Enforce in stages

Switch to deny in a test cluster, then lower environments, then production. Keep a quick rollback ready.

6

Review and retire

Check each rule regularly. Remove rules that no longer add value, and update exemptions.

Deliver policies with GitOps

GitOps means a tool inside your cluster continuously makes the cluster match what is stored in Git. Templates and constraints are ideal for this. A pull request shows exactly what is changing, reviewers can approve it, and a revert is a single click. One ordering detail is worth knowing: a constraint can only be created after its template has been accepted and its kind registered. Good pipelines apply templates first and constraints second, or retry briefly until the new kind appears.

i
Good to Know

Version your policy bundle. When something breaks, the first question is always “what changed?” A tagged policy release makes that question easy to answer, and rolling back to the last good tag takes seconds.

17Advanced Rego Concepts Without the Code

Once you move past the policy library, you will meet a handful of Rego ideas that explain most of the behavior you see. Here they are in plain language.

Helper rules and shared libraries

A real template rarely has just one rule. Authors split the work into small helper rules, each with a clear name, such as “this container is privileged” or “this image comes from an approved registry.” The main violation rule then reads like a short paragraph that combines the helpers. This makes the logic easier to read, easier to test one piece at a time, and easier to reuse. Gatekeeper templates can also include shared library code, so the same helper can serve several templates without being copied and pasted. When a shared helper is fixed, every template that uses it gets the fix.

Everyday Analogy

Think of a recipe book. Instead of repeating “chop onions finely” in every recipe, the book has one page called “basic techniques” and every recipe says “see page 12.” Helper rules and libraries are that technique page.

Negation: the careful word “not”

Rego lets you say that something must not be true, for example “there is no security setting that forbids privilege escalation.” Negation is very useful, but it behaves in a particular way. It succeeds when the thing it checks cannot be found. That is exactly what you want when you are looking for a missing setting, and exactly what you do not want when a typing mistake makes a field name wrong. A misspelled field name can make a “not” check pass for every object. This is one of the strongest reasons to test rules against both good and bad samples.

Sets, lists and collecting results

Rego has simple collections. A set is a group of unique items, like a bag of different label names. Policies often build a set of the labels that are required, build another set from the labels that are present on the object, and then subtract one from the other. Whatever remains is the list of missing labels, which makes a perfect error message. This way of working, collecting and comparing groups, is called a comprehension, and it replaces many loops you would write in other languages.

Default values for missing fields

Because Kubernetes objects leave many fields empty, rule authors often use a helper that returns a default when a field is absent. For example, a rule can ask for the “allow privilege escalation” setting and treat a missing value as “true,” because that is how Kubernetes behaves when nothing is set. Writing the default explicitly protects you from the silent-pass behavior described in Chapter 7.

Writing messages people can act on

The text that a violation returns is what developers read when they are blocked. A message such as “denied” helps nobody. A message such as “container web uses image from registry example.org, allowed registries are registry.internal and mirror.internal” tells the developer exactly what to change. The best messages name the object, name the field, state the rule, and say what is allowed. Many teams also add a short link to an internal page that explains the policy and how to request an exception.

Why some rules are slow

Rego is fast when the engine can quickly narrow down which data to look at. It is slow when a rule must examine large collections without a clear starting point. The classic slow pattern is a referential rule that walks every object of a kind in the replicated inventory to compare against the one being created. Better rules look up a specific namespace or a specific name directly, which lets the engine jump to the answer. When a rule is slow, look first for loops over big inventories and for repeated work that a helper could compute once.

i
Tip

The language itself changes over time, and recent versions of OPA tightened some syntax. When you copy a template from an old blog post, check it against the current Gatekeeper documentation and test it with gator before trusting it.

18The Policy Library Walkthrough: Common Rules in Words

Most teams start with the same dozen rules. Knowing what each one protects against helps you decide which to switch on first.

RuleThe danger it preventsWho usually objects
Block privileged containersA container with host-level powers can escape and take over the node.Teams running low-level system tools or older monitoring agents.
Require approved image registriesUnknown images may carry malware or unpatched software.Developers testing a public image for the first time.
Disallow the latest tagThe same name can mean different software on different days, which breaks repeatable releases.Teams used to quick experiments.
Require CPU and memory limitsOne runaway container can starve its neighbors and cause outages.Teams that have never measured their usage.
Require owner and cost labelsNobody knows whom to call, and bills cannot be split.Rarely anyone, once the reason is explained.
Block host path volumesMounting the node’s own folders lets a Pod read or change the machine.Log shippers and node agents.
Block host networking and host portsThe Pod can see and interfere with traffic of the whole node.Network tools and some ingress controllers.
Force read-only root filesystemAn attacker who gets in cannot easily write tools or change files.Legacy applications that write temporary files in odd places.
Disallow running as rootRoot inside a container makes every other weakness more dangerous.Applications built without a dedicated user.
Restrict Service typesA LoadBalancer or NodePort can expose a service to the internet by accident.Teams that really do need public endpoints, who should apply for an exception.
Require HTTPS on IngressPlain HTTP exposes passwords and personal data in transit.Almost no one.
Require readiness and liveness probesKubernetes cannot tell when an application is broken, so traffic goes to dead Pods.Teams who have not set up health endpoints yet.

Which should you turn on first?

Start with rules that are cheap to follow and expensive to ignore. Required labels cost developers almost nothing and pay back at once in ownership and billing. Approved registries and no-latest-tag protect your supply chain and make releases repeatable. Blocking privileged containers and host paths removes the most dangerous escape routes. Probes and resource limits improve reliability more than security, and they can come right after.

Everyday Analogy

Think about childproofing a house. You do not begin with the rare risks. You first cover the electrical sockets, lock the medicine cabinet and fit a gate at the stairs, because those are the dangers that are both common and severe. Later you worry about the unlikely ones. Policy rollout works best in the same order.

i
Good to Know

Several of these rules overlap with what the built-in Pod security levels already cover, such as privileged containers, host paths and host networking. If you already use the built-in feature at the baseline or restricted level, you can skip duplicates and spend your Gatekeeper effort on the rules that are specific to your company.

19Governing Many Clusters

One cluster is easy. Fifty clusters across three clouds is a different problem, and policy is one of the first things that drifts.

The drift problem

When each cluster owner installs Gatekeeper by hand and picks their own rules, you quickly end up with fifty slightly different security postures. Some clusters block privileged containers, some only warn, and some never installed the rule at all. An auditor asking “are all production clusters compliant?” gets fifty different answers. The cure is to treat policy like any other fleet-wide configuration: define it once, deliver it everywhere, and measure it centrally.

flowchart TB
  REPO["Central policy repository"] --> BASE["Baseline bundle - applies to every cluster"]
  REPO --> PROD["Production bundle - strict, deny actions"]
  REPO --> DEV["Development bundle - relaxed, warn actions"]
  BASE --> C1["Cluster A"]
  BASE --> C2["Cluster B"]
  BASE --> C3["Cluster C"]
  PROD --> C1
  PROD --> C2
  DEV --> C3
  C1 --> MET["Central metrics and compliance dashboard"]
  C2 --> MET
  C3 --> MET
Figure 6: Layered policy bundles delivered to a fleet of clusters

Layering bundles

A practical approach is to build policy in layers. The baseline bundle holds rules every cluster must follow, such as no privileged containers and required ownership labels. An environment bundle adds stricter actions for production and gentler ones for development. A team bundle can add special rules for sensitive workloads, such as payment systems. Each cluster subscribes to the layers that fit it, and a GitOps tool keeps every cluster in line with the repository.

Measuring compliance across the fleet

Each cluster exposes violation and audit metrics. A central monitoring system collects them and shows, for each rule, how many clusters follow it and how many objects break it. Leaders can then see trends: violations going down means teams are fixing things, while a sudden increase after a release points to a problem worth investigating. Managed cloud policy services and multi-cluster tools from the cloud providers do the same job with ready-made dashboards.

Staged delivery to the fleet

Never push a new deny rule to every cluster at once. Start with a small canary group of low-risk clusters, watch the denial and violation metrics for a few days, then widen. If something goes wrong, rolling back a single tagged change in the repository fixes all clusters together.

Everyday Analogy

A hotel chain has one set of safety rules for all its hotels, such as fire exits and kitchen hygiene, plus local rules for each country. The head office does not write fifty separate manuals. It maintains one master manual with local appendices, and inspectors report back to a central team. Layered policy bundles work the same way.

20Troubleshooting Guide

When something goes wrong with a policy system, a calm, ordered checklist saves hours. These are the problems you will meet most often, and where to look first.

Problem: my template does not work

Look at the template’s status. If it has compile errors, the engine could not understand the logic, and the message usually names the line and the problem. If the status shows that some Gatekeeper Pods have not created the template, wait a moment for them to catch up, then check their logs. A common cause is a syntax error copied from an old example.

Problem: I cannot create my constraint

The error usually says the kind is not known. This means the template is not yet ready, or the kind name in the constraint does not match the name in the template. Check spelling and capital letters, since kind names are case sensitive. In pipelines, make sure templates are applied first and that the pipeline waits until the new kind is registered.

Problem: my rule never fires

Work through the layers from outside to inside:

  • Is the constraint matching the object? Check kinds, namespaces and selectors in the match section. A typo in an API group is enough to match nothing.
  • Is the namespace exempt? Check the configuration object and any ignore label.
  • Is the webhook receiving the request? Confirm the webhook configuration covers the operation, such as create and update, and the resource kind.
  • Is the action dry-run? A dry-run constraint never blocks, so you will only see its results in audit.
  • Is the logic silent for a missing field? Test the rule with gator against the exact object that should fail.

Problem: requests are timing out

Check the latency metric and the Pod resources. Slow decisions usually come from too few replicas, too little CPU, a heavy referential rule, or a slow external data provider. Remember that the default timeout is short. If the failure policy is fail-open, timeouts quietly let requests through, which is why you should alert on latency before it reaches the limit.

Problem: audit shows nothing, or looks stale

Check that the audit Pod is running, that its last-run timestamp is recent, and that the kinds you care about are not excluded by the audit settings. If the audit Pod is being restarted for lack of memory, reduce the chunk size or the number of audited kinds.

Problem: Gatekeeper Pods keep restarting

Look at memory first. Replicating large kinds into memory is the most common cause. Next, check the certificates, since the webhook needs a valid serving certificate. Finally, check whether the Pods can reach the API server.

i
Tip

Keep a short runbook for the platform on-call engineer with these exact steps. At three in the morning, nobody remembers which status field to check first. A one-page checklist turns a stressful outage into a routine task.

21Upgrades, Versioning and Disaster Recovery

Gatekeeper sits in the middle of every deployment, so changing it deserves the same care as changing the API server itself.

Upgrading Gatekeeper

Treat each Gatekeeper release like any critical platform upgrade. Read the release notes for changes in default behavior, removed features, and changes to the custom resource definitions. Upgrade a test cluster first, run your policy tests, and watch the latency and audit metrics. Then move through your environments in order. Pin the version in your deployment tooling so that nobody gets a surprise upgrade by accident.

Kubernetes upgrades and compatibility

Each Gatekeeper version supports a range of Kubernetes versions. Before upgrading Kubernetes, check that your Gatekeeper release supports the target version. Webhook behavior and API versions occasionally change between Kubernetes releases, and a mismatch can cause strange admission failures.

Keeping policies healthy over time

  • Version your bundles. Use tags in Git so you can say exactly which version of the rules each cluster runs.
  • Review on a schedule. Every quarter, look at which rules fire most, which are never triggered, and which exemptions are still needed.
  • Retire what no longer helps. A rule that has no violations and no purpose is a maintenance cost.
  • Track deprecations. Kubernetes retires old API versions. A rule that targets a removed API version silently stops matching anything.

Backup and recovery

The good news is that Gatekeeper has very little state of its own. Templates, constraints and configuration live in Git, which is your source of truth, and also in the cluster database. Audit results are rebuilt automatically on the next scan. To recover a lost cluster, you reinstall Gatekeeper, apply the policy bundle from Git, and wait for the audit to repopulate the reports. The only thing worth backing up separately is anything you changed by hand, which is a good reason to never change policies by hand.

Everyday Analogy

Imagine a company rulebook kept in a safe at head office with numbered editions. If a branch office burns down, you do not try to remember what it said. You send the latest numbered edition to the new office. Git is your safe, and tags are the edition numbers.

!
Recovery Trap

While recovering a cluster from scratch, Gatekeeper may start enforcing rules before the system components it protects are healthy. Plan your bootstrap order, and keep system namespaces exempt so a rebuild cannot deadlock on its own policies.

22Compliance, Governance and Exceptions

For many organizations, the real reason to adopt policy enforcement is not curiosity. It is that someone has asked them to prove their systems follow the rules.

Turning frameworks into policies

Security and compliance frameworks, such as the CIS Kubernetes Benchmark, PCI DSS for payment data, SOC 2 for service providers, and many national regulations, contain requirements that sound like policy statements: restrict privileged access, use approved software, encrypt traffic, keep an inventory of assets, and show who is responsible for each system. Many of those statements can be translated directly into constraints. The mapping is simple to describe: each framework control points to one or more rules, each rule has an owner, and the audit report becomes the evidence that the rule is working.

Control

Approved software only

Maps to the allowed-registries rule and the no-latest-tag rule.

Control

Least privilege

Maps to rules that block privileged containers, root users and host access.

Control

Encryption in transit

Maps to the HTTPS-on-Ingress rule and rules that restrict public Services.

Control

Asset ownership

Maps to required owner, team and cost-center labels.

Evidence without screenshots

Traditionally, audit season meant weeks of collecting screenshots and spreadsheets. With policy as code, the evidence is automatic. The Git history shows who proposed and approved each rule. The audit results show the current state of every object. The metrics show trends over time. An auditor can see all of that without anyone preparing a special report.

A healthy exception process

No rule fits every case. A legacy payment system may need a host path that nobody else may use. Rather than weakening the rule for everyone, build a clear path for exceptions:

1

Request

The team opens a pull request or ticket that names the object, the rule, and the business reason.

2

Review

A security reviewer checks the risk and may ask for extra controls, such as network isolation.

3

Narrow exemption

The exception is scoped as tightly as possible: one namespace, one rule, one workload label.

4

Expiry

Every exception carries an end date and an owner. When the date arrives, it is reviewed or removed.

i
Good to Know

An exception with an owner and an expiry date is good governance. An exception that nobody remembers is a hidden hole. Count and report your active exceptions the same way you report violations.

23Operating Model: People, Ownership and Developer Experience

Technology is only half of the story. A policy system lives or dies by how people feel about it, and by who is responsible when it breaks.

Who owns what

Clear ownership prevents most disputes. A typical split looks like this:

GroupResponsibility
Platform teamRuns Gatekeeper, keeps it highly available, maintains the policy repository and the delivery pipeline.
Security teamDecides which controls are required, reviews exceptions, and maps rules to frameworks.
Application teamsFix violations in their own workloads and request exceptions with a reason.
Compliance and auditReads the reports and verifies that the evidence is complete.

Treat the policy system like a service

Because the webhook sits on the path of every deployment, it deserves service-level goals like any critical system. Many teams set targets such as a high percentage of admission requests answered within a short time, and an agreed maximum time for an audit cycle. The targets are tracked on a dashboard, and misses trigger a review. An outage in the policy system is a platform outage, and it should be handled with the same urgency.

Making life easy for developers

Developers accept rules they understand and can follow quickly. Several habits make a big difference:

  • Shift left. Run the same policies in the build pipeline and on the developer’s own computer with gator, so problems appear minutes after the code is written, not at deployment time.
  • Explain every rule. Keep a short page for each policy with the reason, a good example, and how to ask for an exception.
  • Fix by default. Use mutation for harmless defaults so developers are not blocked over small things.
  • Give visibility. Let every team see its own violations in a dashboard without asking the platform team.
  • Listen. Hold regular office hours, track the most common denials, and improve the messages or the rules that cause the most pain.
Everyday Analogy

Airport security works best when passengers know the rules before they arrive: no large liquids, laptops out of bags, and clear signs at every step. The same checkpoint feels hostile when the rules are a surprise. Giving developers the rules early, in the tools they already use, turns the checkpoint into a routine.

24Case Study: A Full Rollout at an Online Marketplace

This is an illustrative story, assembled from patterns that many real teams follow. The company is fictional, but the steps and the lessons are real.

The situation

ShopSphere is an online marketplace with 300 developers, 40 product teams, and 12 Kubernetes clusters across two regions. In one quarter they suffered three incidents: a container with host access was used to read data from a neighboring workload in a test environment, an unlabeled batch job ran for a month and cost the company a large cloud bill before anyone found its owner, and an image pulled from a public registry turned out to contain a known vulnerability. Leadership asked the platform team to make sure these could not happen again.

The plan, month by month

1

Foundation

Install Gatekeeper on all clusters through the GitOps pipeline with three controller replicas and one audit Pod. Add dashboards for latency, audit freshness and violation totals. Exempt system namespaces.

2

Discovery

Deploy five library rules in dry-run: required labels, approved registries, no privileged containers, no host paths and resource limits. The first audit shows thousands of violations, with missing labels the largest group.

3

Communication

The platform team sends each team a personal list of its violations, with a short guide to fixing each one. They hold two question-and-answer sessions and publish a calendar of enforcement dates.

4

Warn phase

Rules switch to warn. Developers see messages in their pipelines. Violations fall by more than half in three weeks. The team improves two confusing error messages after complaints.

5

Staged enforcement

Labels and registry rules switch to deny in development, then staging, then production, a week apart. The privileged and host-path rules are enforced everywhere except for three documented exceptions, each with an expiry date.

6

Steady state

Mutation adds default labels and pull policies. Expansion templates catch bad Deployments at apply time. A quarterly review retires two rules and adds three new ones.

What went wrong along the way

Not everything was smooth. In the second month, a referential rule that compared every Ingress with every other Ingress slowed admission noticeably on the largest cluster. The team rewrote it to look up hostnames directly instead of scanning the whole inventory, and latency returned to normal. In the fourth month, a deny rule briefly blocked a node agent because its namespace had been missed in the exemption list. Because the rule had already been tested in warn mode, the problem showed up as a warning first and was fixed before enforcement.

The results

6 months
from first install to full production enforcement
3
documented exceptions, each with an owner and an expiry
0
repeat incidents of the three original types
Rules were never the hard part. Trust was. Every step that kept developers informed made the next step easier.
i
Lessons to Copy

Start in dry-run, give people their own data, change error messages based on feedback, keep exceptions few and temporary, and measure everything. The same recipe works for a team of ten or a company of ten thousand.

25Gatekeeper Compared with Other Options

Gatekeeper is not the only way to enforce rules in Kubernetes. Knowing the alternatives helps you choose, and often lets you combine them.

ToolRule languageStrengthsWatch out for
OPA/GatekeeperRegoVery flexible, reusable across systems, rich library, strong audit, referential and external data rulesRego has a learning curve. Complex rules need careful testing.
KyvernoKubernetes-style YAMLEasy for Kubernetes teams to read, strong mutation and generation featuresRules are specific to Kubernetes. Very complex logic can be awkward to express.
ValidatingAdmissionPolicyCEL expressionsBuilt into the API server with no extra Pods and no webhook call. Generally available since Kubernetes 1.30.Less powerful than Rego for cross-object checks, and has no audit feature of its own comparable to Gatekeeper’s.
Pod Security AdmissionThree fixed levelsBuilt in, simple, covers standard Pod safetyCannot express company-specific rules.

A quick decision guide

If your team already uses OPA elsewhere, or needs advanced rules that look across objects, Gatekeeper is a natural fit. If your team prefers writing everything in the same style as other Kubernetes files, Kyverno may feel more comfortable. If your rules are simple field checks and you want zero extra components, the built-in policy feature is attractive. Many organizations mix them: built-in Pod security for the baseline, plus Gatekeeper for the organization’s own policy library. Newer Gatekeeper releases are also adding support for the CEL language and the built-in policy engine, so the boundaries between these options keep moving. Check current release notes before deciding.

Gatekeeper strengths

  • Mature CNCF-backed project with wide adoption
  • One policy language that works beyond Kubernetes
  • Powerful audit with built-in reporting
  • Large community library of ready templates
  • Parameterized, reusable templates

Gatekeeper trade-offs

  • Rego takes time to learn well
  • Extra components to run, size and monitor
  • Webhook adds a dependency to the request path
  • Poorly written rules can slow down every deployment

26Design Patterns and Anti-Patterns

After watching many teams adopt policy engines, the same successful habits and the same painful mistakes appear again and again.

Patterns that work

Pattern

Dry-run first, always

Learn the real impact of a rule before it can block anyone.

Pattern

One concern per template

Small, focused templates are easier to test, explain and reuse than one giant template that checks twenty things.

Pattern

Library before custom

Start with community templates, and customize with parameters. Write new Rego only for real gaps.

Pattern

Baseline plus exceptions

Apply strict rules everywhere by default, and handle special cases with narrow, documented, expiring exemptions.

Pattern

Defense in depth

Combine RBAC, network policies, image scanning, runtime security and admission policy. No single layer is complete.

Pattern

Helpful messages

Write error messages that say what is wrong and how to fix it, with a link to documentation. Good messages cut support requests dramatically.

Patterns that hurt

ANTI-PATTERN 02Avoid
What people do

They turn on twenty new deny rules on a Friday afternoon, in production, without telling anyone.

Why it hurts

Deployments fail across many teams at once, people lose trust in the platform, and the quickest fix is to remove the whole policy system.

Better approach

Introduce rules gradually through dry-run and warn, communicate early, and enforce on a calendar that everyone knows.

ANTI-PATTERN 03Avoid
What people do

They write rules that silently pass when a field is missing, assuming a missing field means no problem.

Why it hurts

The most dangerous objects are often the ones that leave a security setting out entirely, because the default is unsafe. The rule stays quiet and gives a false sense of safety.

Better approach

Decide explicitly what a missing field means, and write tests for objects where the field is absent.

ANTI-PATTERN 04Avoid
What people do

They replicate every kind of object into Gatekeeper’s memory “just in case” a future rule needs it.

Why it hurts

Memory use grows with the cluster, Pods are killed for running out of memory, and the webhook becomes unstable.

Better approach

Replicate only the kinds that existing rules read, and add more only when a real need appears.

27Best Practices and Common Mistakes

A short checklist you can copy into your team’s playbook.

Do

  • Store every template and constraint in Git and deploy by pipeline
  • Test rules with gator, including edge cases and missing fields
  • Run at least three webhook replicas, spread across zones
  • Set CPU and memory requests, plus a Pod disruption budget
  • Exempt system namespaces, and document every other exemption
  • Alert on latency, audit freshness and Pod health
  • Write friendly, actionable error messages
  • Review policies on a regular schedule

Do not

  • Enable deny rules without a dry-run and warn period
  • Let application teams edit constraints freely
  • Rely on admission alone and skip audit
  • Replicate large object kinds without need
  • Call slow external services in the request path
  • Forget that fail-open is the default behavior
  • Copy third-party templates without reading them
  • Treat policies as finished once written

The most common mistakes, explained

  • Locking yourself out. A rule that blocks the cluster’s own system components can stop recovery. Always exempt system namespaces before turning on broad rules.
  • Applying constraints before templates. The constraint kind does not exist yet, so the apply step fails. Order your pipeline correctly.
  • Ignoring init containers and ephemeral containers. A rule that checks only the main containers leaves other container lists unprotected.
  • Checking only Pods. A Deployment can look fine and then produce Pods that fail later. Use expansion or add rules at the Deployment level.
  • Assuming audit is instant. Audit runs on a timer. A new violation may take a full interval to appear.
  • Trusting the default violation limit. If a constraint shows exactly 20 violations, there may be many more. Check the metrics for the true total.
i
Tip

Treat your policy repository like a product. Give it an owner, a changelog, a roadmap, and a place where developers can ask for exceptions or new rules. Policy systems succeed when developers see them as a helpful service instead of an obstacle.

28Real-World and Industry Examples

Gatekeeper is not only a lab tool. It sits underneath major cloud offerings and enterprise platforms.

Microsoft Azure: Azure Policy for Kubernetes

Azure’s policy add-on for Azure Kubernetes Service uses Gatekeeper version 3 under the hood. Cloud administrators pick built-in policy definitions, such as blocking privileged containers or limiting allowed registries, and the add-on installs and configures Gatekeeper so those rules are enforced and reported centrally across many clusters.

Google Cloud: Policy Controller for GKE

Google’s managed policy feature for GKE and Anthos environments is built on Gatekeeper. It ships with a bundle of ready-made constraint templates that follow common security benchmarks, so teams can switch on baseline controls across a fleet of clusters without writing Rego.

Red Hat: OpenShift and advanced cluster management

Red Hat’s multi-cluster management tooling integrates Gatekeeper through an operator so that organizations running OpenShift can distribute the same policies to many clusters and view compliance from a single place.

Regulated industries: banks and insurers

Financial organizations commonly need proof that production workloads follow strict controls, such as approved images only, mandatory resource limits, and ownership labels on everything. Teams in these industries use Gatekeeper’s audit reports as living evidence for internal and external reviewers, instead of collecting screenshots before each audit. Publicly listed OPA adopters in this space include Capital One and Goldman Sachs, who use OPA across several kinds of systems.

Multi-tenant platform teams

A platform team serving hundreds of product teams on shared clusters uses Gatekeeper to enforce tenant boundaries. Typical rules: every namespace has an owner and cost label, workloads cannot mount host paths, Services cannot use node ports, Ingress hostnames cannot collide, and images must come from the internal mirror. These rules give product teams freedom inside a safe box.

i
Pattern Across All of These

Every example uses the same recipe: a library of reusable templates, parameters that adapt rules to each environment, a slow path from dry-run to deny, and audit reports for visibility. The technology is the same at a startup and at a global bank. What changes is the number of constraints and the care taken in rollout.

29Frequently Asked Questions

Short answers to the questions people ask most often.

Q1What is the difference between OPA and Gatekeeper?
OPA is the general-purpose decision engine and Rego is its language. Gatekeeper is the Kubernetes-specific program that embeds OPA, connects it to the API server as an admission webhook, and manages rules as Kubernetes objects.
Q2Do I need to learn Rego to use Gatekeeper?
Not to begin. The community library covers many common rules, and you only need to supply parameters. You will want Rego when your organization has rules the library does not cover.
Q3Does Gatekeeper slow down my deployments?
It adds a small delay, usually a few milliseconds to a few tens of milliseconds per request in healthy setups. Narrow matches, simple rules and enough replicas keep the delay unnoticeable.
Q4What happens if Gatekeeper goes down?
With the standard fail-open setting, requests are allowed through and audit later reports anything that should have been blocked. With fail-closed, matching requests are rejected until Gatekeeper recovers. Run several replicas to make either case rare.
Q5Will Gatekeeper check things that already exist?
Admission does not, but the audit feature does. It scans existing objects on a timer and records violations on each constraint.
Q6Can Gatekeeper change objects, or only block them?
It can do both. The mutation feature can set fields, add labels and annotations, and edit lists before the object is saved. Mutation runs before validation.
Q7Why does my rule not fire on a Deployment?
The rule probably targets Pods, and the Pods do not exist yet when the Deployment is created. Use expansion templates so Gatekeeper tests the implied Pod, or add a matching rule for the Deployment itself.
Q8How do I stop Gatekeeper from blocking system components?
Exempt system namespaces through the configuration object, per-constraint exclusions or the namespace ignore label, and restrict who can use that label.
Q9Should I use Gatekeeper or the built-in Pod Security Admission?
They work well together. Use the built-in feature for the standard Pod safety levels and Gatekeeper for organization-specific rules, audits and referential checks.
Q10How do I know a new rule is safe to enforce?
Run it in dry-run mode, read the audit violations, give owners time to fix them, move to warn, and only then deny. Test the rule with gator beforehand, including edge cases.
Q11Can one team write its own rules without affecting others?
Yes, if constraints are scoped by namespace or label selectors. Keep write access to policies with the platform team or a reviewed pull request process, so a single change cannot break everyone.
Q12Does Gatekeeper protect secrets or runtime behavior?
No. It checks configuration at the moment objects are created or changed. Runtime threats need other tools such as runtime security agents, network policies and image scanning.
Q13What happens to objects that already break a new rule?
Nothing happens to them at creation time, because admission only checks new requests. They stay running, and the audit feature lists them as violations. Teams then fix them on their own schedule, and enforcement only blocks new or changed objects that still break the rule.
Q14Can Gatekeeper block updates as well as new objects?
Yes. By default constraints check both create and update requests. Many rules are written to look only at fields that matter, so a harmless update to an old object is not blocked by an unrelated problem elsewhere in it. Authors should test update cases as carefully as create cases.
Q15Do I need a separate Gatekeeper installation for each environment?
Each cluster runs its own Gatekeeper, because the webhook is part of that cluster’s API request path. What you share across environments is the policy bundle in Git, so every installation receives the same rules with settings suited to its environment.
Q16How many constraints are too many?
There is no fixed number. Cost depends on how many constraints match each request and how heavy their logic is. Clusters run dozens or even hundreds of constraints successfully when matches are narrow and rules are simple. Measure latency instead of guessing.
Q17Is Gatekeeper a replacement for network policies or image scanning?
No. Gatekeeper checks configuration at admission time and in audit. Network policies control traffic between Pods, and image scanning looks for known flaws inside images. They work best together, and Gatekeeper can even require that those other controls are present.

30Summary and Key Takeaways

If you remember only a handful of ideas from this guide, make them these.

Key Takeaways

  • RBAC says who, policy says what. Permissions control who may act. Admission policies check what is inside the request, which is the missing half of cluster security.
  • OPA decides, Gatekeeper enforces. OPA is the engine and Rego is the language. Gatekeeper embeds it, connects it to the API server, and turns policies into native Kubernetes objects.
  • Templates are recipes, constraints are uses. Write the logic once as a ConstraintTemplate, then create many constraints with different scopes, parameters and enforcement actions.
  • Admission prevents, audit detects. Admission blocks new problems at the door, while audit finds old ones and anything that slipped through. You need both.
  • Roll out slowly. Move from dry-run to warn to deny, communicate with owners, test with gator, and deliver through GitOps.
  • Protect the guard. Choose fail-open or fail-closed on purpose, lock down who can edit policies and exemptions, and run multiple healthy replicas.
  • Keep it fast and visible. Narrow your matches, replicate only the data you need, watch latency and audit freshness, and write error messages that help developers fix problems themselves.