Compliance as Code

By Davy Rogers

SOC 2 controls as automated tests, not screenshots in a spreadsheet.

Most teams experience compliance as a fire drill: once a year, someone gathers screenshots into a spreadsheet to prove controls were in place, and a week later the configuration has drifted and the evidence is already a lie. Compliance as Code flips that. You express the controls as automated checks that run continuously, so the evidence is always current and drift is caught in minutes instead of at next year's audit.

The shift, side by side:

TraditionalAs Code
Annual auditContinuous verification
ScreenshotsAutomated tests
Drift found at the next auditDrift found in minutes

What the frameworks actually ask for

Strip away the paperwork and most frameworks ask for the same kinds of technical control, which is what makes them automatable:

  • SOC 2. Access control, change management, encryption, logging, incident response.
  • ISO 27001. Configuration management, cryptography, secure development.
  • PCI DSS. Secure configurations, vulnerability management, MFA, audit trails.

Express controls as checks

Policy engines let you write a control as a rule. Here's "S3 buckets must be encrypted" as an OPA policy:

deny[msg] {
  bucket := input.resource.aws_s3_bucket[name]
  not bucket.server_side_encryption_configuration
  msg := sprintf("S3 bucket '%s' not encrypted", [name])
}

Checkov runs hundreds of infrastructure checks out of the box, many already tagged with the frameworks they map to (SOC 2, CIS, NIST):

checkov -d . --framework terraform

Kyverno enforces policy at the Kubernetes admission gate, and branch protection (required PRs, approvals, status checks) is itself a change-management control you can point an auditor at.

Collect the evidence automatically

The other half of the work is proving the control held, which you can also automate. Generate evidence on a schedule and store it immutably:

- run: aws iam generate-credential-report > evidence/iam.json
- run: aws s3 cp evidence/ s3://compliance-evidence/$(date +%Y-%m-%d)/

Use Object Lock on that bucket so the evidence can't be altered after the fact.

Catch drift continuously

terraform plan -detailed-exitcode  # Exit code 2 means drift

Run it every few hours and alert on any change, so the gap between "compliant" and "drifted" is measured in hours, not months.

Where to start

Don't try to automate the whole framework at once. Start where it hurts most:

  1. Automate evidence for your top five failing controls.
  2. Add the compliance checks to CI.
  3. Build a dashboard and turn on drift detection.
  4. Expand from there.

The goal was never to eliminate audits. It's to make them boring, because the evidence is always current, always available, and never a scramble. Start with your most painful controls and grow the coverage from there.