aws-compliance-as-code
Automated, repeatable compliance evidence for an AWS account, mapped to NIST 800-53, SOC 2, ISO 27001 and the CIS AWS Foundations Benchmark, and exported as OSCAL.
pip install "aws-compliance-as-code[demo]"
aws-compliance-as-code demo # a fake, misconfigured account; no AWS needed
→ Read the sample report (no install needed): 15 controls run against a deliberately drifted sandbox account built with moto: root without MFA, a *:* break-glass policy, a single-region trail without log validation, partial S3 Block Public Access and more, each with hashed evidence and OSCAL.
Problem
Audit evidence is still mostly collected by hand. Someone logs into the console, takes screenshots of the IAM password policy, exports a CloudTrail config, pastes it into a spreadsheet, and repeats the whole thing next quarter for a different framework. It is slow, it only proves the state of the account on the day the screenshot was taken, nobody can tell whether a screenshot was edited, and the same AWS setting gets re-collected separately for SOC 2, ISO and NIST even though it is one fact.
How it works
controls.yaml ──> run.py ──> checks/*.py ──(read-only AWS API)──> evidence/<date>/<CONTROL>.json ──> oscal_export.py ──> oscal/assessment-results.json
- Control catalog.
controls.yamllists each control once, with a crosswalk to the requirement IDs it satisfies in four frameworks. Test once, satisfy many frameworks. - Checks. Each control names a Python function in
checks/that takes aboto3session, makes read-only API calls and returnsPASS/FAIL, the findings, the API calls used and the raw API response, so an auditor can re-perform the test from the evidence alone. - Hashed evidence.
run.pywrites one file per control toevidence/<YYYY-MM-DD>/<CONTROL-ID>.jsonwith a timestamp, the account ID, the API call, the raw response and a SHA-256 of the raw response as canonical JSON (sorted keys, no spaces). Any edit to the raw data breaks the hash. - OSCAL.
oscal_export.pyturns a day's evidence into an OSCAL 1.1.2 assessment-results document: one observation per control pointing at its evidence file and hash, and one finding per mapped NIST 800-53 control objective (satisfied/not-satisfied). Any GRC tool that reads OSCAL can ingest it. - Tested offline. Every check has unit tests that run against AWS mocked with moto, covering both the compliant and non-compliant case.
.github/workflows/tests.ymlruns them on every push, so the project is verified without needing a live AWS account.
Controls covered
| ID | Control | Check |
|---|---|---|
| IAM-01 | Root account has MFA enabled | check_root_mfa |
| IAM-02 | Root account has no access keys | check_root_access_keys |
| IAM-03 | IAM password policy meets minimum strength | check_password_policy |
| IAM-04 | Access keys are rotated within 90 days | check_access_key_age |
| IAM-05 | Unused credentials are disabled | check_unused_credentials |
| IAM-06 | No policies grant full *:* administrative privileges |
check_no_wildcard_admin |
| LOG-01 | CloudTrail is enabled in all regions | check_cloudtrail_multi_region |
| LOG-02 | CloudTrail log file validation is enabled | check_cloudtrail_log_validation |
| DATA-01 | S3 Block Public Access is enabled at the account level | check_s3_account_public_access_block |
| DATA-02 | S3 buckets have default encryption configured | check_s3_default_encryption |
| DATA-03 | EBS encryption by default is enabled | check_ebs_default_encryption |
| DET-01 | GuardDuty is enabled | check_guardduty_enabled |
| DET-02 | Security Hub is enabled | check_securityhub_enabled |
| NET-01 | VPC flow logs are enabled | not implemented yet |
| CFG-01 | AWS Config recorder is on | not implemented yet |
Framework versions: NIST SP 800-53 Rev. 5, AICPA TSC 2017 (rev. 2022), ISO/IEC 27001:2022 Annex A, CIS AWS Foundations v3.0.0. Mappings are my own judgment and should be checked against the official crosswalks before being relied on in a real audit.
Run it
Requirements: Python 3.11+, the AWS CLI v2, and a read-only profile (SecurityAudit + ReadOnlyAccess).
pip install aws-compliance-as-code
aws configure sso --profile pm
aws-compliance-as-code scan --profile pm # PASS/FAIL table + evidence/<today>/*.json
aws-compliance-as-code oscal evidence/<today> # oscal/assessment-results.json
From a clone, python run.py --profile pm and python oscal_export.py still work, and pytest -q runs every check offline against mocked AWS (moto).
No AWS account? aws-compliance-as-code demo (with the [demo] extra) builds a misconfigured fake account and runs every check against it.
What I'd do at enterprise scale
- Run it continuously. Schedule it in CI with short-lived OIDC credentials (no stored AWS keys) and commit each day's evidence, giving a dated, version-controlled evidence history.
- Many accounts, one run. Run from a security tooling account and assume a read-only audit role in every member account through AWS Organizations, so one nightly job covers hundreds of accounts.
- Lean on native services. Use AWS Config conformance packs and Security Hub's CIS/NIST standards for continuous detection, and keep this pipeline for what auditors actually need: evidence tied to framework requirements, in OSCAL.
- Make evidence tamper-evident beyond the hash. Write evidence to an S3 bucket with Object Lock (WORM) in a separate account, and sign each file or chain the hashes so editing evidence also needs access the editor doesn't have.
- Close the loop. Turn
not-satisfiedfindings into OSCAL POA&M items and tickets with owners and due dates, and track exceptions with expiry dates instead of letting them live forever. - Govern the catalog. Version
controls.yamlwith reviews from compliance, security and the control owners, and validate OSCAL output against the official NIST schemas in CI.
Safety
Every check is read-only and only needs the SecurityAudit / ReadOnlyAccess managed policies. No credentials are stored in this repo. If you run it against a real account, note that evidence files contain the account ID and IAM user names, so keep evidence/ out of public repos.
Metadata
Release files for aws-compliance-as-code 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| aws_compliance_as_code-1.1.0.tar.gz | 20.7 kB | With provenance | Details for aws_compliance_as_code-1.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| aws_compliance_as_code-1.1.0-py3-none-any.whl | Python 3 | none | any | Details for aws_compliance_as_code-1.1.0-py3-none-any.whl |
Total release size: 39.6 kB
Release files / aws_compliance_as_code-1.1.0.tar.gz
| Download URL | aws_compliance_as_code-1.1.0.tar.gz |
|---|---|
| Size | 20.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8d7b69b518456a63bd2164f19894954fbe38ecbea4c098f82fa2e207619b37cb
|
|
BLAKE2b-256 checksum How to use checksums |
15612af3b59d3aefc4dcd40b72dd28487c6dab9276b75b71036e3ebe1ff2dc70
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logRelease files / aws_compliance_as_code-1.1.0-py3-none-any.whl
| Download URL | aws_compliance_as_code-1.1.0-py3-none-any.whl |
|---|---|
| Size | 19.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
39694d8a8883312c8f8099ab79df5ff845c7d62e48be308d7afe20de29e8615b
|
|
BLAKE2b-256 checksum How to use checksums |
2a20f8d5a71cbfddc4a0a9d20a5b570b8d96ce3bdfce58e89ceb8da6b52fb6fd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logSecurity for aws-compliance-as-code 1.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for aws_compliance_as_code-1.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.