Safeguard
Infrastructure Security

What is Policy as Code

Policy as code turns security and compliance rules into version-controlled, testable code enforced automatically in CI/CD, admission control, and runtime.

Priya Mehta
DevSecOps Engineer
8 min read

Policy as code (PaC) is the practice of writing security, compliance, and operational rules as machine-readable code that a tool automatically evaluates and enforces, instead of relying on a human reviewer to check a pull request or a runbook against a wiki page. A rule like "no S3 bucket may be publicly readable" or "every container image must be signed" gets written in a declarative language — Rego, Sentinel, YAML, or Cedar — and runs as a gate in version control, CI/CD, or the cluster admission controller. If the code violates the policy, the pipeline fails or the deployment is blocked, the same way a unit test fails. Open Policy Agent (OPA), the most widely adopted engine, has been a CNCF graduated project since February 2021 and now ships as the default policy layer inside Styra, Kyverno-adjacent Kubernetes stacks, and dozens of commercial platforms. This piece explains what policy as code actually does, how it differs from infrastructure as code, and where it fits in a modern software supply chain security program.

What Is Policy as Code, Exactly?

Policy as code means expressing a rule — "block any Dockerfile that runs as root," "require an SBOM before a build is promoted to production" — as version-controlled, testable code rather than a PDF or a Confluence page. The rule engine ingests structured input (a Terraform plan, a Kubernetes manifest, a CI pipeline definition) and returns an allow/deny decision plus a human-readable reason. Open Policy Agent, released by Styra in 2016 and donated to the CNCF in 2018, popularized this with its Rego query language: a policy such as deny[msg] { input.resource.public_access == true } can be unit-tested with opa test the same way a developer tests application logic. Because the policy lives in a Git repository, it goes through the same pull-request review, diff history, and rollback process as any other code — which is the entire point. A rule that used to live in a security engineer's head, or in a checklist that gets skipped under deadline pressure, becomes an artifact that runs identically on every commit.

How Is Policy as Code Different From Infrastructure as Code?

Infrastructure as code (IaC) defines what gets built — a VPC, an S3 bucket, a Kubernetes deployment — while policy as code defines what is and isn't allowed to be built. Terraform, CloudFormation, and Pulumi are IaC tools: they provision resources. HashiCorp Sentinel, OPA/Rego, and Kyverno are PaC tools: they inspect the IaC plan or the resulting manifest before or after provisioning and reject anything that breaks a rule. A concrete example: an engineer's Terraform module might correctly provision an RDS instance (IaC doing its job), but a Sentinel policy attached to Terraform Cloud since HashiCorp introduced Sentinel in 2017 can independently reject that same plan if the instance isn't encrypted at rest or sits in a public subnet. The two layers are complementary and deliberately decoupled: IaC authors focus on making infrastructure work, while a separate, centrally maintained policy set — usually owned by security or platform engineering — decides what's permitted, so a single team doesn't have to trust every application team to remember every compliance rule.

What Tools Are Actually Used to Write Policy as Code?

The dominant engine is Open Policy Agent with its Rego language, alongside Kubernetes-native alternatives like Kyverno, which uses plain YAML instead of a new language and hit CNCF incubating status in April 2022. Gatekeeper, OPA's Kubernetes-specific implementation built on CustomResourceDefinitions and admission webhooks, was released in 2018 and is the most common way teams enforce OPA policies directly in a cluster's API server. In the Terraform ecosystem, HashiCorp Sentinel and the open-source Open Policy Agent Terraform provider both evaluate terraform plan JSON output before apply runs. Cloud-specific engines exist too — AWS Cedar (open-sourced in 2023 and now underlying AWS Verified Permissions) and Google's Common Expression Language (CEL), used inside Kubernetes' built-in ValidatingAdmissionPolicy since Kubernetes 1.26 in December 2022. Conftest, a CLI wrapper around OPA, is commonly used to test Dockerfiles, Kubernetes YAML, and Terraform files in CI without deploying a full admission controller. The common thread across all of them is the same: rules are text files that live next to the code they govern and get versioned, tested, and code-reviewed like any other artifact.

Where in the Software Delivery Lifecycle Does Policy as Code Run?

Policy as code runs at four distinct checkpoints: pre-commit/IDE, CI pipeline, admission control at deploy time, and runtime. A pre-commit hook can run conftest test against a Terraform plan before a developer even opens a pull request. In CI, a GitHub Actions or GitLab pipeline step evaluates the same plan or a built container image against a policy bundle and fails the build if a rule like "base image must be from an approved registry" is violated — this is the checkpoint most teams add first because it's cheapest to roll back. At deploy time, Kubernetes admission controllers (Gatekeeper, Kyverno, or native ValidatingAdmissionPolicy) intercept the kubectl apply call itself and reject non-compliant manifests before the API server persists them, closing the gap for anything that bypassed CI. Runtime engines like Falco or cloud-native CSPM tools continuously re-evaluate live resources, catching drift — for example, a security group rule opened manually in the AWS console after deployment, which is exactly the class of change that bypasses every earlier gate. Mature programs run policy as code at all four points because each one catches a different failure mode: developer mistake, pipeline gap, deploy-time exception, and post-deploy drift.

What Kinds of Rules Do Security Teams Actually Codify?

Security teams most commonly codify four categories: cloud misconfiguration, container hardening, secrets and identity, and compliance mapping. Cloud misconfiguration rules block public S3 buckets, unencrypted RDS instances, and overly permissive IAM policies — the same category of issue behind the 2019 Capital One breach, where a misconfigured web application firewall exposed more than 100 million customer records and became a widely cited justification for mandatory PaC guardrails on cloud storage. Container hardening rules reject images running as root, images without a USER directive, or images missing a signed provenance attestation — a requirement that gained urgency after Executive Order 14028 (May 2021) pushed federal software vendors toward SBOM and provenance requirements later formalized in NIST SP 800-218 (SSDF) in February 2022. Secrets and identity rules block hardcoded credentials in manifests and enforce least-privilege service accounts. Compliance mapping rules translate frameworks like PCI DSS 4.0 (mandatory as of March 2025 requirement dates) or CIS Kubernetes Benchmark controls directly into Rego so an auditor's checklist item becomes an automated, continuously-running test rather than a point-in-time manual attestation.

What Are the Limits of Policy as Code?

Policy as code only enforces what someone remembered to write a rule for, and it can't tell you whether a flagged violation is actually exploitable in your environment. A policy engine will flag every container running as root with the same severity, whether that container is internet-facing or an isolated batch job with no network path to sensitive data — without additional context, teams end up with the same alert-fatigue problem PaC was supposed to solve, just moved earlier in the pipeline. Policies also require ongoing maintenance: Kubernetes' admission API, Terraform provider schemas, and cloud APIs change on their own release cadences, and a Rego policy written against a 2023 Terraform AWS provider schema can silently stop matching resources after a provider major-version bump. Because rule-writing requires someone fluent in Rego, CEL, or Sentinel, many security teams end up maintaining fewer, coarser policies than they intend to, and the resulting gaps are often only found during an incident review or a pen test.

How Safeguard Helps

Safeguard turns policy-as-code findings into prioritized, actionable work instead of an undifferentiated queue of violations. Reachability analysis takes every policy hit — a vulnerable dependency, an over-permissioned container, a missing signature — and traces whether the affected code path is actually invoked in your deployed application, so a root-user container with no reachable attack surface doesn't compete for attention with one that's internet-facing. Griffin AI reviews the surrounding code and pipeline context to explain why a policy fired and to draft the fix, and for supported violation classes Safeguard opens an auto-fix pull request with the corrected Terraform, Dockerfile, or manifest already in the diff, so remediation doesn't wait for a ticket to get triaged. Safeguard also generates SBOMs at build time and ingests existing ones from CI, so the component inventory your Rego or Kyverno policies check against stays current rather than going stale between scans.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.