Infrastructure scanning with Checkov or Trivy compared with custom policies using OPA and Conftest.
Compliance

Compliance as Code: Which Approach Fits Your Team

Compare Checkov, OPA, Conftest, and Trivy for compliance as code, with a practical policy example and clear enforcement boundaries.

Reviewed for technical accuracy: October 1, 2026

  • Checkov and Trivy can check IaC before deployment; timing depends on where you run them
  • OPA evaluates policy decisions; the calling system must enforce them
  • Conftest applies Rego tests to structured configuration in local and CI workflows
  • Combine pre-deployment checks, live-state validation, owned exceptions, and traceable evidence
  • A passing technical check is not proof of complete regulatory compliance

Compliance as code means expressing the technical parts of your controls as versioned, repeatable checks. Policy as code is the rule language and evaluation mechanism behind those checks. Neither term means that a passing infrastructure scan proves that an organization meets every requirement of SOC 2, HIPAA, or another framework. People, process, scope, and evidence still matter.

For infrastructure teams, the practical choice is where a check runs and who maintains it: static analysis in a pull request, a policy decision on a proposed plan, or a check against deployed resources. These approaches complement each other. A scanner can block a deployment when the pipeline treats a failure as a gate.

Checkov, OPA, Conftest, and Trivy Compared

The comparison below uses the same criteria for each tool: input, execution point, policy ownership, and the main boundary. It describes the documented open-source capabilities, not an independently measured performance benchmark. Review the linked documentation for the version you install.

ToolInput and execution pointPolicy ownershipUseful fitMain boundary
CheckovIaC files and supported Terraform plan JSON; local checks or CI before applyBuilt-in checks plus custom Python or YAML policiesStart with common IaC misconfiguration checksCLI findings become a deployment gate only when your workflow enforces them
OPAStructured input such as JSON; wherever an integration asks for a decisionYour Rego rules and supporting dataOrganization-specific decisions across services or infrastructureThe caller supplies input and enforces the decision
ConftestStructured configuration files, including YAML, JSON, and HCL; local checks or CIYour Rego rules, using OPATest repository configuration with a small command-line workflowYou maintain the rules and connect failures to your release process
TrivySupported IaC files through trivy config; local checks or CIBuilt-in misconfiguration checks plus custom checksAdd IaC checks to a broader security scanning workflowConfiguration checks and package vulnerability scanning answer different questions

Checkov documents static analysis and custom checks. OPA separates policy decisions from enforcement, while Conftest packages Rego tests for configuration files. Trivy documents pre-deployment IaC misconfiguration scanning. None of these tools should be categorized as inherently post-deployment-only.

Where tfsec fits. tfsec is a Terraform static-analysis scanner. Its maintainers encourage users to move to Trivy, where they are concentrating development effort. It is not a live-cloud-only scanner. See the official tfsec-to-Trivy guidance.

Approach 1: Build Your Own Policy Checks

Custom policy-as-code gives you control over the rule and its exceptions. You can require approved regions, ownership tags, encryption, or a review from the right team. OPA evaluates the supplied data; your deployment system decides whether a denial stops the run.

The maintenance work is real. Someone must define the input schema, test passing and failing cases, version the policies, and own exceptions. Missing or unknown values need an explicit outcome; an absent field should not silently become evidence that a control passed.

Use this approach when organization-specific rules are important and a team can own them. Conftest is a useful entry point for testing structured configuration in CI. A larger OPA integration can reuse decisions across multiple systems, but it still needs an enforcement path.

Approach 2: Scan IaC Before Deployment and Live State Afterward

Checkov and Trivy can find common configuration weaknesses in a repository before resources are created. Put the scan in the pull request and make the relevant failures block the release. Define which checks matter, how an exception is approved, and where the result is retained.

A pre-deployment scan cannot prove that production still matches the reviewed code. Live-state checks are a separate layer for console changes, resources outside IaC, and conditions that change after release. Keep both views: what was proposed and what is running.

Approach 3: Compliance Built Into the Pipeline

In ops0, compliance checks sit alongside generated IaC and deployment review. The workflow connects policy results to the infrastructure change and its operational context. Review the compliance workflow to decide whether it fits the controls your team needs.

Built-in checks reduce the amount of policy you need to start with. They still require scope review, exception ownership, and evidence retention. A framework label is a mapping to evaluate; it is not a certification or a substitute for an auditor reviewing the wider control environment.

Worked Example: A Production Database Encryption Check

Illustrative lab example. The following input is a deliberately simplified record, not a Terraform plan schema, a customer result, or an ops0 deployment log. The technical control is narrow: a production database must have storage encryption enabled.

Save this normalized input as example.json. In a real integration, derive the value from the proposed resource configuration and validate that the environment, resource address, and encryption value are present and have the expected types.

JSON
{
  "resource_address": "aws_db_instance.orders",
  "environment": "production",
  "storage_encrypted": false
}

Save this rule as policy/encryption.rego. It uses Rego v1 syntax supported by current OPA and Conftest. For this production record, a missing encryption field is treated like a false value.

REGO
package main

deny contains reason if {
  input.environment == "production"
  object.get(input, "storage_encrypted", false) != true
  reason := sprintf("%s requires storage encryption", [input.resource_address])
}
BASH
conftest test example.json --policy policy

Expected lab behavior. The false value should produce a denial. Change it to true and rerun the check; this rule should no longer deny the record. Also test a missing field, an invalid type, and your input-validation failures before using a policy in a release gate. These are expected test cases, not measured results from a customer environment.

This single check does not cover key ownership, rotation, backups, access permissions, or whether an existing unencrypted database can be changed without replacement. Map each requirement to the right evidence and inspect the actual infrastructure plan before deciding how to remediate it.

The Hybrid Approach

Combine built-in checks for common misconfigurations with custom rules for your organization. Then check live resources for changes that bypassed the normal deployment workflow. The important boundary is between a finding and an enforced decision, not between a tool with or without an AI label.

What Auditors Need to Trace

Retain the resource or plan that was checked, the policy version, the result, the time, the reviewer, and any approved exception. Tie the check to the deployment outcome. Record a failed gate as a failed gate; do not label a proposed or hypothetical control as a successful production result.

Choose the approach that lets your team explain a specific change: which control applied, what evidence was evaluated, who approved an exception, and whether the deployed resource still meets the intended setting.

For a product workflow, explore ops0 compliance and policy enforcement. For the wider review and evidence process, see infrastructure audit. Start with one real control and a passing, failing, and missing-input test before expanding the policy library.

Evidence Record Template

Illustrative record template, not an observed deployment. Fill each field from the actual check and approval workflow.

Change: <reviewed commit or plan reference>
Control and policy version: <versioned check>
Result: <actual pass, fail, or error>
Reviewer or exception owner: <recorded identity>
Evidence: <input, check output, approval, deployment result>
Quick answers

What is compliance as code?

Compliance as code expresses security and regulatory controls as repeatable checks that can run during infrastructure review, deployment, and audit workflows.

Can IaC scanning stop a deployment?

Yes. Checkov and Trivy can run before deployment. A scanner stops a release only when the pipeline enforces its result as a gate; live-state checks are still needed for later changes.

How does ops0 support compliance workflows?

ops0 connects compliance checks to generated IaC, deployment workflows, policy gates, drift context, and audit evidence.

Sources
From article to workflow

Connect policy checks with change evidence.

Review proposed configuration, retain policy results and approvals, and check the deployed state through the same workflow.

Related articles

All articles