Fundamentals

What Is Policy as Code?

Updated

Policy as code is the practice of expressing security, compliance, and operational rules in a machine-readable language, storing them in version control, and having a policy engine evaluate them automatically against real data. It replaces rules that live in documents and depend on people remembering them. This guide explains how it works, the main tools, and working examples in OPA, Sentinel, AWS Config, and Cedar.

Key Takeaways

  • Policy as code writes rules in a machine-readable language, keeps them in version control, and has an engine evaluate them automatically.
  • Every implementation has four parts: the policy, the input data, the decision engine, and an enforcement point.
  • Policy as code is the technique. Compliance as code is the program that maps those policies to controls and turns decisions into evidence.
  • Leading open tools include OPA (Rego), Conftest, Cedar, Kyverno, and Checkov, alongside Sentinel for Terraform and AWS Config rules for live AWS resources.
  • The strongest programs run the same intent in CI (preventive) and against live resources (detective), and log every decision as evidence.

How does policy as code work?

Every policy as code system, regardless of vendor or language, has the same four parts:

  • Policy: The rule itself, written in a language like Rego, Sentinel, Cedar, or YAML. It lives in Git, gets code review, and has tests.
  • Input: Structured data describing the thing being evaluated: a Terraform plan in JSON, a Kubernetes manifest, an API request, or a cloud resource configuration.
  • Decision engine: The program that evaluates the policy against the input and returns a decision such as allow, deny, or a list of violations.
  • Enforcement point: The place that acts on the decision: a CI job that fails the build, an admission controller that rejects a pod, or an application that denies a request.

Separating the decision from the enforcement is the design choice that makes policy as code scale. The same policy can be evaluated in a pull request, at deploy time, and against live infrastructure, and every evaluation produces the same answer for the same input. That consistency is what a manual review cannot provide.

What is the difference between policy as code and compliance as code?

The terms get used interchangeably, but they sit at different levels. Policy as code is the technique. Compliance as code is the program that uses the technique to meet framework requirements and prove it. The compliance as code guide covers the program side in depth.

DimensionPolicy as codeCompliance as code
ScopeA single rule and its evaluationA control set mapped to one or more frameworks
OutputA decision: allow, deny, or violationsControl status, evidence, and audit-ready reporting
Primary usersPlatform, security, and DevOps engineersGRC engineers, auditors, and leadership
ExampleA Rego rule that denies public S3 bucketsThat rule mapped to SC-7 and CC6.1, with decisions retained as evidence
Used outside compliance?Yes: cost, reliability, and authorization rulesNo: its purpose is meeting obligations

What are the most common policy as code tools?

Most teams pick one general-purpose engine and add specialized tools where they already fit the workflow.

ToolLanguageTypical use
Open Policy Agent (OPA)RegoGeneral-purpose engine for any JSON input; a CNCF graduated project
ConftestRegoRuns OPA policies against config files such as Terraform plans and Kubernetes YAML
HashiCorp SentinelSentinelPolicy checks between plan and apply in HCP Terraform and Terraform Enterprise
AWS Config rulesManaged rules, Lambda, or CloudFormation GuardContinuous evaluation of live AWS resource configurations
CedarCedarApplication authorization decisions; open source from AWS
KyvernoYAMLKubernetes admission control and policy reporting
CheckovPython or YAMLStatic scanning of IaC files against built-in and custom checks

For how these tools fit into a scanning pipeline, see IaC compliance scanning.

What is an example of policy as code?

The examples below all enforce variations of one intent: storage must not be publicly accessible, which maps to boundary protection (SC-7) in NIST SP 800-53.

OPA and Rego against a Terraform plan

This policy reads the JSON output of terraform show -json and returns a violation for any public access block that leaves public ACLs allowed:

package terraform.s3

import rego.v1

deny contains msg if {
	some rc in input.resource_changes
	rc.type == "aws_s3_bucket_public_access_block"
	rc.change.after.block_public_acls != true
	msg := sprintf("%s must set block_public_acls = true (SC-7)", [rc.address])
}

Sentinel in HCP Terraform

Sentinel evaluates the same plan inside the Terraform run itself. The main rule must be true for the run to proceed:

import "tfplan/v2" as tfplan

public_access_blocks = filter tfplan.resource_changes as _, rc {
	rc.type is "aws_s3_bucket_public_access_block" and
	(rc.change.actions contains "create" or rc.change.actions contains "update")
}

main = rule {
	all public_access_blocks as _, pab {
		pab.change.after.block_public_acls is true and
		pab.change.after.restrict_public_buckets is true
	}
}

AWS Config managed rule, deployed with Terraform

The two policies above are preventive. This AWS Config rule is detective: it continuously evaluates existing buckets, including ones changed outside Terraform. It requires an AWS Config configuration recorder in the account.

resource "aws_config_config_rule" "s3_public_read_prohibited" {
  name        = "s3-bucket-public-read-prohibited"
  description = "SC-7: S3 buckets must not allow public read access"

  source {
    owner             = "AWS"
    source_identifier = "S3_BUCKET_PUBLIC_READ_PROHIBITED"
  }
}

Cedar for application authorization

Policy as code also covers who can do what inside an application. This Cedar policy lets auditors read evidence and blocks deletion by anyone outside an admin group:

permit (
  principal in Group::"auditors",
  action == Action::"readEvidence",
  resource in Folder::"soc2-2026"
);

forbid (
  principal,
  action == Action::"deleteEvidence",
  resource
)
unless { principal in Group::"evidence-admins" };

How do you implement policy as code in a GRC program?

Start with a control that already causes pain in audits and has clean input data. Encryption, public access, and logging settings are common first choices. Then work through a short loop:

  1. Write the rule and tag it with the control IDs it supports, such as SC-7 or CC6.1.
  2. Write unit tests with passing and failing inputs (opa test for Rego) so the policy itself is verified.
  3. Run it in CI in warn-only mode, fix existing violations, then switch it to blocking.
  4. Add a detective rule against live resources to catch drift and manual changes.
  5. Retain every decision with a timestamp so it can serve as audit evidence.
  6. Define an exception process with an owner and an expiry date, recorded in code or in your risk register.

A minimal CI step using Conftest looks like this:

- name: Policy check
  run: |
    terraform plan -out=tfplan
    terraform show -json tfplan > plan.json
    conftest test --policy policy/ --namespace terraform.s3 plan.json

Policy files make excellent audit artifacts because an auditor can read the exact logic that enforces a control. How auditors evaluate that logic is covered in auditing infrastructure as code, and the broader automation roadmap is in GRC automation. For the controls these policies enforce, see what a security control is.

Frequently Asked Questions

What is policy as code?

Policy as code is the practice of writing rules (security, compliance, operational, or authorization) in a machine-readable language, storing them in version control, and having a policy engine evaluate them automatically. Common engines include Open Policy Agent, HashiCorp Sentinel, AWS Config, Cedar, and Kyverno.

What is the difference between policy as code and compliance as code?

Policy as code is the technique: a rule, an engine, and a decision. Compliance as code is the program built on that technique, which maps policies to framework controls, collects the decisions as evidence, and reports posture to auditors and leadership. You can do policy as code without a compliance program, but compliance as code depends on it.

What language does Open Policy Agent use?

Open Policy Agent uses Rego, a declarative query language designed for evaluating structured data such as JSON. A Rego policy describes conditions that should produce a decision, like a deny message, and OPA evaluates those conditions against whatever input you provide, from a Terraform plan to a Kubernetes manifest.

Is AWS Config policy as code?

Yes. AWS Config rules evaluate resource configurations against a desired state and record each resource as compliant or noncompliant. Managed rules are predefined by AWS, and custom rules can be written as Lambda functions or in CloudFormation Guard syntax. Deploying those rules through Terraform or CloudFormation keeps them versioned like any other code.

Where should policy as code run?

Ideally in more than one place. Run it in CI to block noncompliant infrastructure before deployment (preventive), at admission or authorization time to stop bad requests (preventive), and against live resources to catch drift (detective). Each layer catches problems the others miss.

Do GRC professionals need to write policy as code?

GRC engineers increasingly do, because translating a control objective into a precise rule requires compliance judgment as well as coding skill. Even GRC analysts who do not write policies benefit from reading them, since a policy file is often the clearest documentation of how a control actually works.

Write Your First Policy in a Real Lab

GRC Engineering Club members practice policy as code against real cloud accounts and Terraform pipelines, with a community to review their work. Membership is $70 a year.