A practical look at moving compliance from a periodic checklist to a continuously enforced part of the software delivery pipeline.
The Trouble With Treating Compliance as a Point-in-Time Exercise
In most regulated organisations, compliance still works the same way it did a decade ago: a policy document gets written, a spreadsheet gets built to track it, and someone manually checks systems against that spreadsheet a few times a year. The problem is that infrastructure doesn't stand still between audits. A firewall rule changes, a new cloud resource gets spun up, an access permission gets granted "just for now" and never revoked. By the time the next audit comes around, the gap between what the policy says and what the environment actually looks like can be significant - and nobody notices until it's flagged.
This is the core weakness of manual governance, risk and compliance (GRC) processes. They're accurate at the moment they're performed and increasingly wrong every day after that. For industries where compliance failures carry real consequences - finance, healthcare, critical infrastructure, government - that gap is a genuine risk, not just an administrative inconvenience.
Policy-as-code exists to close that gap. Instead of describing a rule in a document and hoping engineering teams read and remember it, the rule gets written as code and enforced automatically, every time something changes. Many organisations first encounter this approach while working with a managed IT services provider to modernise their broader infrastructure and pipeline setup.
It's also increasingly a security requirement in its own right. As regulators and customers alike expect continuous evidence of control, engaging a cyber security services specialist early in the design of a policy-as-code framework helps ensure the rules encoded actually reflect current threat and compliance expectations, not just historical ones.
What Policy-as-Code Actually Means
Policy-as-code is exactly what it sounds like: taking a governance requirement (an access control rule, a data residency requirement, a security baseline) and expressing it as an executable policy rather than a paragraph of prose. Instead of a document that says "production databases must not be publicly accessible," you write a rule that a computer can evaluate against your actual infrastructure and answer with a definitive yes or no.
This isn't a new concept borrowed from compliance teams. It comes from infrastructure-as-code and DevOps practice, where the same logic already applies to servers and networks: if you can describe your infrastructure in a file and let a tool provision it consistently, you can describe your policies in a file and let a tool enforce them consistently. Tools like Open Policy Agent (OPA), HashiCorp Sentinel, and Conftest have been built specifically to let engineering and security teams do exactly this.
The shift here isn't just technical, it's temporal. Traditional GRC checks compliance after the fact. Policy-as-code checks it before or during deployment, which means a non-compliant change either gets blocked automatically or flagged the moment it's introduced, not discovered six months later during an audit.
From Legal Text to Executable Rule
The hardest part of policy-as-code has nothing to do with writing code. It's translation. Regulatory and internal policy documents are written in legal or procedural language, full of qualifiers, exceptions, and context that a human compliance officer is expected to interpret with judgement. Turning that into a deterministic rule that a machine can evaluate means someone has to make decisions about how those exceptions get handled in practice.
Take a rule like "sensitive customer data must be encrypted at rest, except where a documented legacy system exception has been approved." A human reading that understands the nuance instantly. A policy engine needs that exception explicitly modelled: a list of approved exception IDs, an expiry date on each one, and a fallback behaviour when an exception isn't found. Skipping this step and writing an overly rigid rule is one of the fastest ways to get engineering teams pushing back on policy-as-code altogether, because it starts blocking legitimate, already-approved work.
This is why the most effective implementations treat policy writing as a collaboration between compliance, security, and engineering, not something handed down from one team to another. The compliance team knows what the rule needs to achieve. The engineering team knows what the systems actually look like and where the edge cases live. Both perspectives are needed to write a policy that's strict where it needs to be and pragmatic everywhere else.
Where Policies Live in the Pipeline
Once a policy is written, the next decision is where in the software delivery lifecycle it actually runs. There are generally three points worth considering, and most mature setups end up using a combination of them.
The first is at the infrastructure-as-code stage, where tools like Terraform or CloudFormation define what's about to be built. Running policy checks here, before anything is actually provisioned, is the cheapest place to catch a violation. A pull request that would create a publicly accessible storage bucket can be blocked before it's ever merged.
The second is within the CI/CD pipeline itself, as a gate between build and deploy. This is useful for checks that depend on the built artefact rather than just its configuration, such as scanning a container image for known vulnerabilities or verifying that a service is only calling approved, allow-listed APIs.
The third is at runtime, evaluating the live environment on an ongoing basis. This matters because infrastructure drifts. Someone might make a manual change directly in a cloud console that bypasses the pipeline entirely. Runtime policy checks catch this kind of drift and can trigger automatic remediation or alerting.
Each of these layers connects to the next. A policy written for the infrastructure-as-code stage often gets reused, with minor adjustment, as a runtime check. Building policies as modular, reusable code rather than one-off scripts is what makes this consistency possible across all three layers.
Choosing a Policy Engine
There's no single correct tool here, and the right choice depends heavily on what you're already running. Open Policy Agent, and its Rego policy language, has become something of a default in the Kubernetes and cloud-native world because it's engine-agnostic: the same OPA instance can evaluate policies for Kubernetes admission control, API authorisation, and Terraform plans. HashiCorp Sentinel is tightly integrated with the Terraform and Vault ecosystem and is a natural fit for teams already standardised on HashiCorp tooling. Cloud-specific options, such as AWS Config rules or Azure Policy, trade flexibility for simplicity if your workloads sit entirely within one provider.
What matters more than the specific tool is version control discipline. Policies should live in a git repository, go through pull request review like any other code change, and have a clear rollback path. A policy that's edited directly in a production dashboard, with no history of who changed what or why, defeats the purpose of the exercise. If an auditor asks why a particular control was relaxed on a particular date, the answer should be a commit history, not someone's memory.
Designing for Auditability, Not Just Enforcement
It's tempting to treat policy-as-code purely as an enforcement mechanism: the policy either passes or fails, and that's the end of it. For regulated industries, that's not quite enough. An auditor doesn't just want to know that a system is currently compliant, they want evidence of compliance over time.
This means policy evaluations need to produce a durable, timestamped record, not just a pass or fail returned to a build log that gets overwritten next week. Capturing which policy version ran, against which resource, with what result, and storing that somewhere queryable, turns policy-as-code into an audit trail rather than just a gate. This is often the difference between a policy-as-code implementation that genuinely reduces audit preparation time and one that just moves the manual effort from "checking compliance" to "proving that compliance checks actually happened."
Common Pitfalls
A handful of mistakes show up repeatedly in policy-as-code implementations, and most of them stem from treating it as a purely technical exercise rather than a shared discipline between compliance and engineering. The most common ones are worth calling out directly:
- Writing policies without engineering input. Rules that look correct on paper but ignore how systems actually behave in production end up blocking legitimate, already-approved work, which is one of the fastest ways to get an initiative distrusted.
- Writing policies that are too permissive to matter. Going too far the other way, so the policy technically exists but never actually blocks anything, defeats the purpose just as thoroughly as an overly rigid rule.
- Enabling hard enforcement before testing. Turning on hard blocking against an unvalidated policy is a reliable way to cause an outage. Most successful rollouts start in "monitor only" or "warn" mode, review the false positives, and only then switch to enforcement.
- Treating the policy library as a one-off project. Policies that are never revisited become as stale as the spreadsheets they were meant to replace. A policy-as-code library needs an owner and a review cadence, the same as any other piece of production code.
Getting Started Without Boiling the Ocean
The organisations that succeed with policy-as-code rarely start by trying to encode their entire compliance framework at once. They pick a handful of high-value, well-understood rules first - encryption at rest, public access restrictions, mandatory tagging for cost and ownership tracking - and get those running reliably in monitor mode before expanding scope.
This staged approach does two things. It builds confidence and trust with engineering teams, who see that the system flags real issues without generating constant noise. And it gives the compliance and security teams a working template for how to translate the next policy, and the one after that, into code. Over time, what started as a handful of automated checks becomes a genuine, continuously enforced compliance posture, rather than a document that gets dusted off once a year.
Comments
Loading comments…