OPA Gatekeeper lets you enforce custom policies on your Kubernetes resources in Azure Kubernetes Service (AKS).
Let’s see it in action. Imagine you want to ensure all Pods in your AKS cluster are running with specific security contexts. We can use OPA Gatekeeper to deny any Pod creation or update that doesn’t meet these requirements.
Here’s a sample ConstraintTemplate that defines the schema for our policy:
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiresecuritycontext
spec:
crd:
spec:
names:
kind: k8sRequireSecurityContext
validation:
openAPIV3Schema:
type: object
properties:
allowedCapabilities:
type: array
items:
type: string
requiredDropCapabilities:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredcapabilities
violation[{"msg": msg, "details": {"missing_capabilities": missing}}] {
container := input.review.object.spec.containers[_]
required := {cap | cap := input.parameters.requiredDropCapabilities[_]}
present := {cap | cap := container.securityContext.capabilities.drop[_]}
missing := required - present
count(missing) > 0
msg := "Container is missing required dropped capabilities."
details := {"missing_capabilities": missing}
}
violation[{"msg": msg, "details": {"added_capabilities": added}}] {
container := input.review.object.spec.containers[_]
allowed := {cap | cap := input.parameters.allowedCapabilities[_]}
present := {cap | cap := container.securityContext.capabilities.add[_]}
added := present - allowed
count(added) > 0
msg := "Container has disallowed capabilities."
details := {"added_capabilities": added}
}
This ConstraintTemplate defines a k8sRequireSecurityContext kind. It expects parameters for allowedCapabilities and requiredDropCapabilities. The Rego code checks two things:
- Missing Dropped Capabilities: It verifies if any capabilities listed in
requiredDropCapabilitiesare not present in the container’ssecurityContext.capabilities.drop. If there are missing ones, it flags a violation. - Disallowed Added Capabilities: It checks if any capabilities listed in
container.securityContext.capabilities.addare not present in theallowedCapabilitiesparameter. If disallowed capabilities are added, it flags a violation.
Now, let’s create a Constraint that uses this template. We want to ensure that all containers drop the ALL capability and do not add any capabilities.
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: k8sRequireSecurityContext
metadata:
name: require-all-pods-drop-all-capability
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
requiredDropCapabilities: ["ALL"]
allowedCapabilities: []
When you apply this Constraint, Gatekeeper intercepts admission requests. If a Pod creation or update request arrives, Gatekeeper evaluates it against the k8sRequireSecurityContext constraint. If the Pod’s container security context doesn’t meet the specified requiredDropCapabilities and allowedCapabilities, the admission request is denied.
For example, if you try to create a Pod like this:
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: nginx
image: nginx
securityContext:
capabilities:
add: ["NET_ADMIN"] # This will be denied
You’ll receive an error message from the Kubernetes API server, indicating that the Pod creation was blocked by Gatekeeper because the NET_ADMIN capability was added, which is not allowed by our k8sRequireSecurityContext constraint.
The core problem OPA Gatekeeper solves is the lack of a centralized, programmable way to enforce granular policies across your Kubernetes cluster. Kubernetes has built-in admission controllers, but they are often limited in scope and flexibility. Gatekeeper, powered by the Open Policy Agent (OPA), allows you to write custom policies using the Rego language, which can inspect and control any aspect of your Kubernetes resources. This is crucial for security, compliance, and operational best practices.
The Rego language is declarative and designed for policy enforcement. It works by defining rules that evaluate input data (in this case, Kubernetes resource definitions) against a set of policies. When a rule evaluates to true, it generates a "violation," which is then used by the Gatekeeper admission controller to deny the request.
The input.review.object in the Rego code refers to the actual Kubernetes resource being reviewed by the admission controller. input.parameters contains the configuration passed from the Constraint resource. The violation rule is the key part that defines what constitutes a policy breach.
You can define policies for a vast array of scenarios:
- Resource Limits: Enforcing CPU and memory requests/limits on all containers.
- Image Provenance: Ensuring only trusted container images are used.
- Network Policies: Requiring NetworkPolicies to be defined for all namespaces.
- Labels and Annotations: Mandating specific labels for resource management.
- RBAC: Controlling who can access what resources.
The most surprising thing most people don’t realize about OPA Gatekeeper is that it doesn’t just prevent bad configurations; it can also enforce good ones. For instance, you can write a policy that automatically adds a securityContext to a Pod definition if it’s missing, rather than just denying the Pod. This is achieved by defining a mutate function within your Rego, which allows Gatekeeper to modify the resource before it’s persisted.
The next step after enforcing basic security contexts is often to implement network segmentation policies using NetworkPolicies, which Gatekeeper can also manage.