TL;DR
- Compliance scanning should happen in CI before deployment, not during annual audits
- Checkov, KICS, and Trivy provide pre-built policies mapped to SOC2, HIPAA, PCI-DSS, and CIS benchmarks
- The #1 mistake: running compliance tools manually instead of as automated CI gates
Best for: Teams in regulated industries (healthcare, finance) or pursuing SOC2 certification Skip if: You’re building internal tools with no compliance requirements Read time: 10 minutes
Your SOC2 auditor asks for evidence that all S3 buckets have encryption enabled. You spend three days pulling CloudTrail logs, cross-referencing with Terraform state, and building a spreadsheet. Next quarter, they ask again. And again.
This is compliance theater — reactive evidence gathering instead of proactive enforcement. In 2026, compliance-as-code means your infrastructure can’t be deployed unless it meets the controls. The audit evidence is your CI pipeline history.
The Real Problem
Traditional compliance approaches fail for IaC because they’re designed for static environments. An auditor reviews your AWS console once a year. But your Terraform deploys 50 times a day. By the time the audit happens, the infrastructure has changed thousands of times.
The shift-left approach means:
- Compliance checks run on every pull request
- Non-compliant resources can’t be deployed (not just flagged)
- Evidence is automatically generated and stored
- Drift from compliant state triggers alerts
This isn’t about passing audits faster — it’s about being continuously compliant rather than point-in-time compliant.
IaC Compliance Scanning Tools
Three open-source tools dominate IaC compliance scanning in 2026:
| Tool | Maintainer | Frameworks | Key Strength |
|---|---|---|---|
| Checkov | Palo Alto Networks | Terraform, CloudFormation, K8s, ARM | Pre-built SOC2/HIPAA/PCI mappings |
| KICS | Checkmarx | 15+ IaC formats | Query-based customization |
| Trivy | Aqua Security | IaC + containers + SBOM | Unified scanning pipeline |
All three support CIS Benchmarks, but Checkov has the most explicit compliance framework mappings out of the box.
Checkov for Compliance
Checkov’s built-in policies map directly to compliance standards. Running a SOC2-focused scan:
# Scan Terraform directory for SOC2-relevant checks
checkov -d ./terraform --framework terraform --check CKV_AWS_19,CKV_AWS_20,CKV_AWS_21
# Or use the compliance framework filter
checkov -d ./terraform --compliance-framework soc2
# Output as JUnit XML for CI integration
checkov -d ./terraform -o junitxml > compliance-report.xml
The key insight is that Checkov maps checks to specific compliance controls:
CKV_AWS_19 → SOC2 CC6.1 (Encryption at rest)
CKV_AWS_20 → SOC2 CC6.6 (S3 public access)
CKV_AWS_21 → HIPAA 164.312(e)(2) (Encryption in transit)
Notice how a single resource can satisfy multiple frameworks. Your S3 encryption check covers SOC2, HIPAA, and PCI-DSS simultaneously.
Custom Compliance Policies
Pre-built policies cover common cases, but your organization likely has specific requirements. Checkov supports custom policies in Python or YAML:
# custom_policies/require_cost_center_tag.yaml
metadata:
id: "CUSTOM_AWS_1"
name: "Ensure all resources have cost_center tag"
category: "GOVERNANCE"
guideline: "All resources must have cost_center tag for billing attribution"
definition:
cond_type: "attribute"
resource_types:
- "aws_instance"
- "aws_s3_bucket"
- "aws_rds_instance"
attribute: "tags.cost_center"
operator: "exists"
Run with your custom policy directory:
checkov -d ./terraform --external-checks-dir ./custom_policies
For complex logic, Python policies offer more flexibility:
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
from checkov.common.models.enums import CheckResult, CheckCategories
class RequireApprovedAMI(BaseResourceCheck):
def __init__(self):
name = "Ensure EC2 uses approved AMI from internal registry"
id = "CUSTOM_AWS_2"
supported_resources = ["aws_instance"]
categories = [CheckCategories.GENERAL_SECURITY]
super().__init__(name=name, id=id, categories=categories,
supported_resources=supported_resources)
def scan_resource_conf(self, conf):
ami = conf.get("ami", [""])[0]
approved_prefixes = ["ami-internal-", "ami-approved-"]
if any(ami.startswith(prefix) for prefix in approved_prefixes):
return CheckResult.PASSED
return CheckResult.FAILED
check = RequireApprovedAMI()
CI/CD Integration
Compliance scanning must block deployments, not just report. Here’s a GitHub Actions workflow:
name: Compliance Gate
on:
pull_request:
paths:
- 'terraform/**'
jobs:
compliance-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Checkov
uses: bridgecrewio/checkov-action@v12
with:
directory: terraform/
framework: terraform
output_format: cli,sarif
output_file_path: console,results.sarif
soft_fail: false # Fail the build on violations
skip_check: CKV_AWS_999 # Known exception
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
The soft_fail: false is critical — it ensures non-compliant PRs cannot merge.
Mapping Controls to Evidence
Auditors need evidence, not tool output. Create a compliance matrix that maps your CI checks to specific controls:
| Control ID | Requirement | Tool | Check ID | Evidence Location |
|---|---|---|---|---|
| SOC2 CC6.1 | Encryption at rest | Checkov | CKV_AWS_19 | GitHub Actions logs |
| HIPAA 164.312(a)(1) | Access controls | Checkov | CKV_AWS_40 | GitHub Actions logs |
| PCI-DSS 3.4 | Stored cardholder data | Custom | CUSTOM_PCI_1 | Artifact storage |
Store compliance scan results as build artifacts with retention matching your audit cycle (typically 1-3 years for SOC2).
AI-Assisted Approaches
Writing custom compliance policies requires understanding both the regulation and the IaC resource structure. AI tools excel here.
What AI does well:
- Translating regulatory text into Checkov/KICS policy rules
- Identifying which IaC resources are relevant to specific controls
- Generating test cases for custom policies
- Explaining why a resource fails a particular check
What still needs humans:
- Interpreting ambiguous regulatory language
- Deciding which controls apply to your specific architecture
- Approving exceptions and documenting compensating controls
- Reviewing AI-generated policies for correctness
Useful prompt:
I need a Checkov custom policy (Python) that enforces:
- All RDS instances must have deletion_protection enabled
- Exception: instances with tag "environment=development"
- Map to SOC2 control CC6.1 (logical access controls)
Include unit tests using pytest
When This Breaks Down
Compliance scanning has limitations:
False sense of security: Passing all checks doesn’t mean you’re secure. Compliance frameworks are minimum baselines, not comprehensive security.
Tool coverage gaps: No scanner covers every resource type. New AWS services might not have policies for months.
Runtime vs deploy-time: These tools check what will be deployed, not what’s currently running. A manually-modified resource bypasses all gates.
Exception management: Every organization accumulates exceptions. Without governance, your “compliant” state becomes Swiss cheese.
Consider complementary approaches:
- Policy as Code with OPA/Sentinel for custom enforcement
- AWS Config / Azure Policy for runtime compliance
- Cloud Security Posture Management (CSPM) for continuous monitoring
Decision Framework
Use Checkov when:
- You need explicit SOC2/HIPAA/PCI mappings
- Python-based custom policies fit your team’s skills
- You want the largest pre-built policy library
Use KICS when:
- You need maximum IaC format coverage (15+ formats)
- Query-based customization matches your workflow
- You’re already using Checkmarx for SAST
Use Trivy when:
- You want unified container + IaC scanning
- SBOM generation is required
- You’re in a Kubernetes-heavy environment
Measuring Success
| Metric | Before | After | How to Track |
|---|---|---|---|
| Audit prep time | 2-3 weeks | 1-2 days | Hours logged |
| Compliance violations in prod | Unknown | 0 | CSPM dashboard |
| Time to remediate finding | Days | Hours | PR merge timestamps |
| Policy coverage | 0% | 90%+ resources | Checkov –list |
Warning signs it’s not working:
- Teams requesting too many exceptions
- Compliance scans taking >10 minutes (blocking velocity)
- Auditors rejecting CI logs as evidence
- Scan results ignored because of noise
What’s Next
Start with one compliance framework. If you’re pursuing SOC2:
- Run
checkov -d ./terraform --compliance-framework soc2 --listto see applicable checks - Enable the top 10 highest-severity checks as blocking
- Document exceptions with compensating controls
- Gradually expand coverage each sprint
- Present CI pipeline as audit evidence trail
The goal is making compliance a side effect of good engineering practices, not a separate workstream.
Related articles:
- Policy as Code Testing: OPA vs Sentinel
- Infrastructure as Code Testing
- Secrets Management in CI/CD Testing
- GitOps Workflows for QA and Testing
External resources:
Official Resources
See Also
- Compliance Testing for Infrastructure as Code: Complete Guide - Master compliance testing for IaC with automated validation,…
- Pulumi Testing Best Practices: Unit, Property, and Integration Testing for Infrastructure as Code - Master Pulumi testing with unit tests, property tests, and…
- Cloud Resource Tagging Validation: Automated Compliance Testing - Learn how to validate cloud resource tags across AWS, Azure, and…
- Docker Image Testing and Security: Complete Guide to Container Vulnerability Scanning - Master Docker image security with Trivy, Snyk, and Grype. Learn…
