Rancher’s OPA admission policy lets you enforce cluster-wide rules, but most people only think of it for denying bad things, not for enforcing good things.

Imagine you have a fleet of Kubernetes clusters managed by Rancher, and you want to ensure every single Pod deployed across them adheres to a strict set of security and operational guidelines. You don’t want to manually check each deployment; you want an automated guardian. That’s where Rancher’s OPA Admission Policy comes in. It acts as a gatekeeper, intercepting API requests before they are applied to the cluster and evaluating them against predefined policies written in the Open Policy Agent (OPA) Rego language. If a request violates a policy, OPA denies it, preventing the problematic resource from being created or modified.

Let’s see it in action. Suppose we want to enforce that all Pods must have resource limits defined.

First, we need to configure the OPA integration within Rancher. Navigate to your cluster in Rancher, then go to Apps & Marketplace -> Chart Repositories. Ensure you have the rancher-charts repository enabled. Then, go to Apps & Marketplace -> Marketplace and search for opa-gatekeeper. Install it, accepting the default configuration for now.

Once installed, you’ll find a new section in your cluster’s navigation called Policy or Constraint Templates and Constraints.

Now, let’s create a Rego policy that checks for resource limits. This policy will be implemented as an OPA ConstraintTemplate and then a Constraint.

Here’s a Rego policy to enforce CPU and memory limits on containers:

package k8srequired.limits

violation[{"msg": msg}] {
  container := {c | input.review.object.spec.containers[_] == c}
  not container.resources.limits.cpu
  msg := "Container must have CPU limits defined."
}

violation[{"msg": msg}] {
  container := {c | input.review.object.spec.containers[_] == c}
  not container.resources.limits.memory
  msg := "Container must have memory limits defined."
}

This Rego code defines two rules, violation. The first rule checks if a container in the Pod spec (input.review.object.spec.containers[_]) has a limits.cpu field defined. If it doesn’t, it generates a violation with a specific message. The second rule does the same for limits.memory.

In Rancher, you’d create a ConstraintTemplate that references this Rego code. The ConstraintTemplate tells Gatekeeper how to run your Rego policy.

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlimits
  annotations:
    description: "Require containers to have CPU and memory limits."
spec:
  crd:
    spec:
      names:
        kind: k8sRequiredLimits
      validation:
        # Schema for the `parameters` field of a `Constraint`
        openAPIV3Schema:
          type: object
          properties: {} # No parameters needed for this simple policy
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequired.limits

        violation[{"msg": msg}] {
          container := {c | input.review.object.spec.containers[_] == c}
          not container.resources.limits.cpu
          msg := "Container must have CPU limits defined."
        }

        violation[{"msg": msg}] {
          container := {c | input.review.object.spec.containers[_] == c}
          not container.resources.limits.memory
          msg := "Container must have memory limits defined."
        }

After creating the ConstraintTemplate, you then create a Constraint that uses this template. This is where you apply the policy to specific namespaces or globally.

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: k8sRequiredLimits
metadata:
  name: pod-must-have-limits
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pods"]
    # To apply to all namespaces, omit the `namespaces` field.
    # To apply to specific namespaces:
    # namespaces:
    #   - "default"
    #   - "production"

With this Constraint in place, any attempt to create a Pod without CPU or memory limits will be rejected by the OPA admission controller.

The mental model is that OPA Gatekeeper acts as a webhook server. Kubernetes API server sends admission review requests (for Pod creation, updates, etc.) to this webhook. Gatekeeper then evaluates these requests against the policies defined by your ConstraintTemplate and Constraint resources. If any policy finds a violation, Gatekeeper sends back an allowed: false response with a denial message, and the API server rejects the request.

The surprising part is how flexible Rego is. You can write policies that check for anything in the Kubernetes object, not just simple presence or absence. You can compare fields, iterate through lists, and even call external data sources (though that’s more advanced). For instance, you could enforce that container images must come from an approved registry, or that all deployments must have specific labels.

The most common use case for OPA Gatekeeper is denial, but it’s equally powerful for enforcement. You can write policies that require certain fields to be present, like resource limits or specific labels, ensuring a baseline level of quality and manageability across your cluster. It’s not just about saying "no" to bad configurations; it’s about saying "yes" only to good ones.

The next logical step is to explore how to use parameters within ConstraintTemplates to make your policies more dynamic, allowing for different configurations without writing entirely new Rego code for each variation.

Want structured learning?

Take the full Rancher course →