The Problem with Static Policies
Static policies - even the most well-written ones - are just text. They live outside your workflows and have no real enforcement. Someone might define “All S3 buckets must be private” in a policy doc, but who makes sure it stays that way? Usually no one - until an audit happens or a breach forces a cleanup.
The result? A reactive security posture where teams scramble to patch compliance gaps instead of preventing them.
That’s where Policy as Code (PaC) comes in. It bridges the gap between intent and enforcement by encoding your rules as executable, testable logic that lives alongside your code and infrastructure.
What Is Policy as Code?
Policy as Code means expressing rules - like security controls, compliance standards, or architectural constraints - in a machine-readable format so they can be enforced automatically.
Instead of relying on documents and meetings, you define rules in policy files, version them in Git, test them in CI/CD, and enforce them at runtime.
Common use cases include:
- Preventing public S3 buckets or unsecured storage.
- Enforcing resource limits and Kubernetes security contexts.
- Ensuring images only come from trusted registries.
- Validating Terraform or Helm configurations before deployment.
- Enforcing encryption, IAM roles, and cost boundaries.
At its core, PaC makes policies living, testable, and enforceable - not forgotten.
Implementing Policy as Code with OPA (Open Policy Agent)
Open Policy Agent (OPA) is one of the most popular open-source engines for implementing Policy as Code. It’s a general-purpose policy decision engine that works across cloud, CI/CD, microservices, and Kubernetes.
1) Setting Up OPA
You can deploy OPA in several ways:
- As a standalone service (e.g., in Kubernetes as an admission controller).
- As a sidecar next to an application to make runtime authorization decisions.
- As an embedded library inside a tool or service.
- Or integrated directly into CI/CD pipelines for pre-deployment checks.
OPA receives three things:
- Policies (written in its policy language, Rego)
- Data (context such as infrastructure state, configuration, or metadata)
- Queries (questions like “Is this allowed?” or “Does this configuration comply?”)
OPA then returns a decision - for example, “allow” or “deny” - based on the rules.
2) Writing Policies in Rego
Rego is a declarative language designed for writing policies. Here’s a simple example:
5 not input.spec.containers[_].securityContext.runAsNonRoot
6 msg = sprintf("Pod %v must run as non-root", [input.metadata.name])
This policy blocks any Kubernetes Pod that doesn’t run as a non-root user.
Rego policies can define granular conditions, import external data (like allowed registries), and even include unit tests for validation - ensuring policies themselves are reliable and versioned like any other code.
3) Integration Examples
You can embed OPA into your DevOps workflows easily:
- CI/CD Pipelines: Run OPA checks on Terraform plans, Kubernetes manifests, or Dockerfiles before deployment.
- Kubernetes Admission Control: Enforce rules cluster-wide through admission webhooks.
- APIs and Microservices: Use OPA to handle dynamic access control or multi-tenant permission decisions.
For example, in a GitHub Actions pipeline:
1- name: Validate Infrastructure Policies
3 terraform plan -out=tfplan
4 terraform show -json tfplan > plan.json
5 opa eval --data policies/ --input plan.json "data.policies.deny"
If any deny rule triggers, the build fails automatically - preventing violations before deployment.
Enforcing Kubernetes Policies with Kyverno
While OPA is general-purpose, Kyverno is purpose-built for Kubernetes and uses YAML instead of Rego. It’s designed to be developer-friendly and integrates directly into cluster operations.
1) Setup
You install Kyverno as a controller inside your cluster. It intercepts all resource creation and modification requests via the Kubernetes admission controller mechanism.
No need to write extra services - once deployed, Kyverno automatically validates or mutates Kubernetes manifests as they’re applied.
2) Writing Policies in Kyverno
Kyverno policies are standard Kubernetes resources (Policy or ClusterPolicy). Here’s a simple one that blocks containers running as root:
1apiVersion: kyverno.io/v1
4 name: disallow-root-pods
6 validationFailureAction: enforce
8 - name: require-non-root
14 message: "Containers must not run as root"
You can also define mutate rules that automatically fix issues (for example, add missing labels or enforce encryption options).
3) Integrations
Kyverno supports multiple enforcement levels:
- Audit Mode - Logs violations without blocking.
- Enforce Mode - Blocks any non-compliant resource.
You can test policies using the kyverno test CLI or run them as part of your CI pipeline using the kyverno apply command.
Policies can also be applied GitOps-style - committed, versioned, and deployed via ArgoCD or Flux.
Using OPA and Kyverno Together
You don’t have to pick one. Many organizations use both:
- OPA for cross-domain and infrastructure-level policies (CI/CD, Terraform, APIs).
- Kyverno for cluster-level enforcement (Pods, Deployments, ConfigMaps).
Together, they ensure policies are enforced everywhere - from code to cloud. For example:
- Use OPA to prevent Terraform from creating a public S3 bucket.
- Use Kyverno to ensure the Kubernetes service that connects to that bucket uses encrypted connections only.
This layered approach ensures that no matter where the violation happens - design, build, or deploy - something catches it before production.
Final Thoughts
Policy as Code isn’t just about automation - it’s about reliability and trust. When policies are written as code, they can’t be ignored, forgotten, or “interpreted differently.” They enforce themselves. Tools like OPA and Kyverno make this practical and powerful. Instead of static PDFs, you get living rules that continuously protect your systems.
At Olymp Labs, we believe policies shouldn’t live in forgotten documents - they should live with your code.