Advanced DevSecOps

Policy as code — OPA, Rego, and automatic rule enforcement

Policy as Code transforms security rules — which usually exist only in documents — into executable, testable, versioned code. The Open Policy Agent (OPA) with the Rego language is the most widely adopted standard for this.

What is OPA

OPA is a general-purpose policy engine, decoupled from the application. It receives a JSON input (what is happening), consults a Rego policy (what is permitted), and returns a decision (allow/deny).

OPA architecture:

  Application / pipeline
       │  input (JSON)

    ┌─────┐
    │ OPA │  ←── policy (.rego)
    └─────┘
       │  result: { "allow": true } or { "allow": false, "reasons": [...] }

  Application acts on the decision

Rego language — basic concepts

# policy/deny_root.rego
package kubernetes.admission

import future.keywords.if
import future.keywords.contains

# Deny pods running as root
deny contains msg if {
    input.request.kind.kind == "Pod"
    container := input.request.object.spec.containers[_]
    container.securityContext.runAsUser == 0
    msg := sprintf("Container '%v' must not run as root (UID 0)", [container.name])
}
# policy/require_labels.rego
package kubernetes.admission

# Require mandatory labels on all Deployments
deny contains msg if {
    input.request.kind.kind == "Deployment"
    required_labels := {"owner", "env", "cost-center"}
    existing := {l | input.request.object.metadata.labels[l]}
    missing := required_labels - existing
    count(missing) > 0
    msg := sprintf("Missing required labels: %v", [missing])
}

OPA in Kubernetes — Gatekeeper

Gatekeeper integrates OPA as a Kubernetes admission controller: any resource created or modified passes through policies before being accepted.

# ConstraintTemplate — defines the constraint type
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlabels
        violation[{"msg": msg}] {
          required := input.parameters.labels[_]
          not input.review.object.metadata.labels[required]
          msg := sprintf("Missing required label: %v", [required])
        }
---
# Constraint — applies the rule to Namespaces
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: ns-must-have-owner
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
  parameters:
    labels: ["owner", "env"]

OPA in the CI/CD pipeline

Policies can be evaluated before deployment, during the pipeline itself:

# Evaluate a Kubernetes manifest against an OPA policy
opa eval \
  --input k8s/deployment.yaml \
  --data policy/ \
  --format pretty \
  'data.kubernetes.admission.deny'

# If deny returns non-empty results → pipeline fails
# GitHub Actions — OPA conftest
- name: Policy check with conftest
  run: |
    conftest test k8s/ --policy policy/ --all-namespaces
  # conftest is a CLI wrapper for OPA, supports multiple formats:
  # Terraform, Kubernetes YAML, Dockerfile, JSON, TOML

Practical use cases

Kubernetes / Gatekeeper:
  - Block images without a fixed digest (sha256 only)
  - Require resource limits on all containers
  - Forbid hostNetwork: true and hostPID: true
  - Deny pods without a readinessProbe

CI/CD pipeline:
  - Block deploy to production without security approval
  - Require images to come only from authorized registries
  - Deny Terraform with security group 0.0.0.0/0

API Gateway / Envoy:
  - Request authorization based on JWT claims
  - Per-tenant rate limiting

Testing policies

Policies as code have automated tests:

# policy/deny_root_test.rego
package kubernetes.admission_test

test_deny_root_container if {
    result := deny with input as {
        "request": {
            "kind": {"kind": "Pod"},
            "object": {"spec": {"containers": [
                {"name": "app", "securityContext": {"runAsUser": 0}}
            ]}}
        }
    }
    count(result) > 0
}
opa test policy/ -v
# PASS: test_deny_root_container

Summary

OPA and Rego allow security policies to be versioned, reviewed in PRs, automatically tested, and consistently enforced across Kubernetes, pipelines, and APIs. They replace compliance documents with executable code — the policy passes or fails, without ambiguity.