A continuous compliance monitoring engine for AWS that evaluates live infrastructure against SOC 2 Trust Service Criteria and NIST 800-53 controls. Features automated evidence collection, cryptographic integrity hashing, trend reporting, and optional AI-assisted control mapping.
Built to demonstrate modern GRC Engineering: treating compliance controls as executable, version-controlled code rather than static spreadsheets and manual screenshots.
┌─────────────────────────────────────────────────────────────────────────────┐
│ Continuous Compliance Engine │
└─────────────────────────────────────────────────────────────────────────────┘
┌──────────────────┐
│ controls/*.yaml │ ◄── Declarative control definitions
│ • soc2_cc.yaml │ (framework, ID, severity, check_function)
│ • nist_800_53 │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ engine/loader │ ◄── Loads YAML, resolves check_function strings
│ • load_controls │ into actual Python callables
│ • resolve_all │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ checks/*.py │ ◄── Pure functions: (boto3.Session) → (Status, str, dict)
│ • iam_checks │ Read-only AWS API calls
│ • s3_checks │
│ • cloudtrail │
│ • ec2_checks │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ engine/runner │ ◄── Parallel execution (ThreadPoolExecutor)
│ • run() │ Catches exceptions → ERROR status
│ • summarize() │ Calculates compliance %
└────────┬─────────┘
│
├──────────────────────┬──────────────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌──────────────┐ ┌────────────────┐
│ engine/evidence │ │ engine/report│ │ Trend Dashboard│
│ • capture() │ │ • render_html│ │ • plot.html │
│ • SHA-256 hash │ │ • write_ │ │ (compliance % │
│ • manifest.json │ │ snapshot │ │ over time) │
└─────────────────┘ └──────────────┘ └────────────────┘
│ │
▼ ▼
evidence/ reports/
(immutable snapshots) (HTML + JSON trends)
┌─────────────────────────────────────────────────────────────────────────────┐
│ AI-Assisted Layer (Optional) │
└─────────────────────────────────────────────────────────────────────────────┘
Unmapped control description
│
▼
┌──────────────────┐
│ engine/ai_mapper │ ◄── Anthropic Claude API
│ • draft_check_ │ Drafts candidate boto3 check function OR
│ function() │ maps to existing check
│ • suggest_ │
│ mapping() │
└──────────────────┘
│
▼
[Human Review Required]
│
▼
checks/*.py (manual commit)
Controls are defined purely in YAML — separating the what (compliance requirement) from the how (boto3 check implementation).
- id: CC6.1-01
title: "Root account has no active access keys"
description: >
The root user must not have active programmatic access keys.
severity: critical
service: iam
check_function: checks.iam_checks.check_root_access_keys
remediation: >
Sign in as root, go to My Security Credentials, and deactivate/delete
any active access keys. Use an IAM role for all automation.Every check is a pure function:
def check_s3_bucket_encryption(session: boto3.Session) -> tuple[Status, str, dict]:
# returns (Status.PASS/FAIL/ERROR, "human-readable message", evidence_dict)- No hidden state — testable in isolation with
moto - Safe by default — strictly read-only, never modifies AWS resources
- Parallelizable — run concurrently via
ThreadPoolExecutor
For every control evaluated, the engine captures a timestamped, SHA-256-hashed snapshot of the raw resource state.
- Evidence is written locally or pushed to an immutable S3 bucket
- A run manifest binds every control to its evidence hash — giving auditors cryptographic proof of what was observed at scan time
- Matches the evidence pipeline architecture of commercial GRC platforms
- HTML Compliance Report: Clean, stakeholder-ready summary with severity-coded findings and specific remediation steps
- JSON Trend Snapshots: Append-only run history for tracking compliance posture over time
- Visual Dashboard: Lightweight Chart.js dashboard showing score progression
Answers the GRC workflow challenge: "How do we quickly onboard new compliance requirements?"
- Drafts candidate boto3 check functions from plain-text control descriptions
- Suggests mappings to existing checks across different frameworks
- Human-in-the-loop: Generated code is displayed for review, never auto-executed
| Service | SOC 2 (CC Series) | NIST 800-53 (Rev 5) | Check Function |
|---|---|---|---|
| IAM | CC6.1-01 | AC-6 | checks.iam_checks.check_root_access_keys |
| IAM | CC6.1-02 | IA-2(1) | checks.iam_checks.check_root_mfa |
| IAM | CC6.1-03 | IA-2(2) | checks.iam_checks.check_iam_users_mfa |
| IAM | CC6.1-04 | IA-5 | checks.iam_checks.check_iam_password_policy |
| IAM | CC6.1-08 | AC-2 | checks.iam_checks.check_iam_unused_credentials |
| S3 | CC6.1-05 | SC-28 | checks.s3_checks.check_s3_bucket_encryption |
| S3 | CC6.1-06 | AC-3 | checks.s3_checks.check_s3_public_access_blocked |
| S3 | CC6.1-07 | CP-9 | checks.s3_checks.check_s3_versioning_enabled |
| CloudTrail | CC7.2-01 | AU-2 | checks.cloudtrail_checks.check_cloudtrail_enabled |
| CloudTrail | CC7.2-02 | AU-9 | checks.cloudtrail_checks.check_cloudtrail_log_file_validation |
| CloudTrail | CC7.2-03 | SC-28-CT | checks.cloudtrail_checks.check_cloudtrail_encrypted |
| EC2 | CC6.6-01 | SC-7 | checks.ec2_checks.check_security_groups_no_unrestricted_sensitive_ports |
| EC2 | CC6.1-EBS | SC-28-EBS | checks.ec2_checks.check_ebs_default_encryption |
- Python 3.9+
- AWS credentials configured (read-only permissions sufficient)
# Clone the repository
git clone https://github.com/Eng-Ryan/aws-compliance-as-code.git
cd aws-compliance-as-code
# Create virtual environment
python3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt# Scan all frameworks against default AWS profile
python main.py scan
# Scan only SOC 2 controls
python main.py scan --frameworks soc2
# Scan with custom output directories and S3 evidence upload
python main.py scan \
--frameworks soc2,nist800-53 \
--output reports/ \
--evidence-dir evidence/ \
--evidence-bucket my-compliance-evidence-bucket \
--profile my-aws-profile- HTML Report: Open
reports/run-<timestamp>_report.htmlin any browser - Evidence Manifest: Inspect
evidence/run-<timestamp>_manifest.jsonfor SHA-256 hashes - Trend History:
python main.py trends --snapshots-dir reports/ --limit 10
Sample CLI Output:
Compliance Posture History (last 10 runs):
Run ID Date Score Pass Fail Error
================================================================================
run-2026-09-14T10-23-45-abc 2026-09-14 10:23:45 85.0% 17 3 0
run-2026-09-14T14-15-02-def 2026-09-14 14:15:02 90.0% 18 2 0
run-2026-09-14T18-47-19-ghi 2026-09-14 18:47:19 95.0% 19 1 0
Sample HTML Report Structure:
- Executive Summary: Overall compliance score, total controls evaluated, PASS/FAIL/ERROR breakdown
- Findings by Severity: Critical → High → Medium → Low, color-coded status badges
- Control Details: Each finding includes:
- Framework and control ID
- Check title and description
- Status (✅ PASS / ❌ FAIL /
⚠️ ERROR) - Human-readable message
- JSON evidence payload
- Copy-pasteable remediation steps
- Evidence Integrity: SHA-256 manifest hash anchors report to immutable evidence snapshots
Execute all configured checks and generate reports.
python main.py scan [OPTIONS]Options:
--frameworks TEXT— Comma-separated list of frameworks to evaluate (default:soc2,nist800-53)--profile TEXT— AWS CLI profile name (default:default)--output PATH— Directory for HTML reports and JSON snapshots (default:reports/)--evidence-dir PATH— Local directory for evidence snapshots (default:evidence/)--evidence-bucket TEXT— Optional S3 bucket to upload evidence manifests (requires write permissions)--controls-dir PATH— Directory containing YAML control definitions (default:controls/)
Example:
python main.py scan --frameworks soc2 --profile prod-readonly --output audit-2026-q3/Display historical compliance scores from past scan snapshots.
python main.py trends [OPTIONS]Options:
--snapshots-dir PATH— Directory containing*_snapshot.jsonfiles (default:reports/)--limit INTEGER— Number of most recent runs to display (default:10)
Example:
python main.py trends --snapshots-dir reports/ --limit 20Generate a candidate boto3 check function from a control description using Claude.
python main.py draft-check CONTROL_ID [OPTIONS]Options:
--framework TEXT— Framework name (e.g.,nist800-53,soc2) (required)--title TEXT— Short control title (required)--description TEXT— Full control description (required)--service TEXT— AWS service (e.g.,iam,s3,ec2) (required)
Example:
python main.py draft-check AC-17 \
--framework nist800-53 \
--title "Remote Access Control" \
--description "The organization authorizes and monitors all remote access sessions." \
--service ec2Requires: ANTHROPIC_API_KEY environment variable
Suggest an existing check function that matches a control description.
python main.py map-control [OPTIONS]Options:
--title TEXT— Control title (required)--description TEXT— Control description (required)
Example:
python main.py map-control \
--title "Multi-Factor Authentication for Privileged Access" \
--description "Require MFA for all administrative console users."Requires: ANTHROPIC_API_KEY environment variable
The entire test suite uses moto to mock AWS services. No real AWS credentials or network calls are required.
# Run all tests
pytest tests/ -v
# Run with coverage report
pytest tests/ --cov=engine --cov=checks -vcompliance-engine/
├── controls/ # Declarative control definitions (YAML)
│ ├── soc2_cc.yaml # SOC 2 Common Criteria controls
│ └── nist_800_53.yaml # NIST 800-53 Rev 5 controls
├── checks/ # Pure, testable boto3 check functions
│ ├── iam_checks.py # Root keys, MFA, password policy, stale creds
│ ├── s3_checks.py # Default encryption, public access block, versioning
│ ├── cloudtrail_checks.py # Multi-region trails, log validation, KMS encryption
│ └── ec2_checks.py # Open security group ports, EBS default encryption
├── engine/ # Core compliance engine
│ ├── models.py # ControlDefinition, CheckResult, Status dataclasses
│ ├── loader.py # YAML parsing & dynamic check function resolution
│ ├── runner.py # ThreadPoolExecutor parallel runner & scoring
│ ├── evidence.py # SHA-256 integrity hashing & manifest generation
│ ├── report.py # Jinja2 HTML report & trend snapshot generation
│ └── ai_mapper.py # LLM-assisted check drafting and control mapping
├── templates/
│ └── report.html.j2 # Jinja2 HTML compliance report template
├── dashboard/
│ └── plot.html # Chart.js compliance posture trend dashboard
├── scripts/
│ └── generate_trend_data.py# Aggregates snapshot JSONs for the dashboard
├── docs/
│ ├── architecture.md # In-depth system design and extension guide
│ └── loom_demo_script.md # 2-3 minute portfolio demo recording script
├── tests/ # Comprehensive pytest + moto test suite
│ ├── conftest.py # Mocked AWS session fixtures
│ ├── test_iam_checks.py
│ ├── test_s3_checks.py
│ ├── test_cloudtrail_checks.py
│ ├── test_ec2_checks.py
│ ├── test_loader.py
│ ├── test_runner.py
│ └── test_evidence.py
├── reports/ # Generated reports (gitignored)
├── evidence/ # Generated evidence snapshots (gitignored)
├── requirements.txt
└── main.py # Click CLI entrypoint
- Continuous vs. Point-in-Time: Traditional audits capture state once a year. This engine can run on an hourly cron / EventBridge schedule to detect drift within minutes.
- Audit Defensibility: Having raw, SHA-256 hashed JSON snapshots means you never have to scramble to produce "proof" for an external auditor — the evidence trail is continuous and cryptographic.
- Multi-Framework Efficiency: A single check function (e.g.
check_root_mfa) simultaneously satisfies SOC 2CC6.1-02and NIST 800-53IA-2(1)— eliminating redundant testing. - Developer-Friendly Remediation: Every failed check output includes specific, copy-pasteable remediation steps — bridging the gap between compliance requirements and engineering execution.
MIT License. See LICENSE for details.