GitHunt
0X

0xBahalaNa/aws-compliance-as-code

Automated AWS compliance guardrails using Service Control Policies and CloudFormation. Controls enforce audit log protection, encryption at rest, boundary protection, and least functionality, mapped to CJIS Security Policy v6.0, FedRAMP High baseline, and NIST 800-53 Rev. 5.

AWS
CloudFormation
License
Compliance
CJIS
FedRAMP
NIST 800-53

AWS Compliance as Code

This project implements compliance controls as code using AWS Service Control Policies (SCPs) and CloudFormation. Rather than relying on manual compliance checks, I built automated, enforceable guardrails that prevent non-compliant actions at the AWS Organization level and deploy secure infrastructure by default.

The controls in this repository map to requirements from CJIS Security Policy, FedRAMP, and NIST 800-53, demonstrating how compliance frameworks translate into real, enforceable cloud infrastructure policies.

Architecture Overview

graph TD
    A[AWS Organization] --> B[Organization Root]
    B --> C["SCP: Deny Audit Log Deletion"]
    B --> D["SCP: Deny EC2 Actions"]
    B --> E["SCP: Prevent Insecure SSH"]
    B --> F["SCP: Require S3 Encryption"]
    B --> G[Organizational Units / Accounts]
    G --> H[CloudFormation Stack]
    H --> I["Secure S3 Bucket<br/>Public Access Blocked<br/>AES256 Encryption"]
Loading

SCPs are attached at the Organization Root, enforcing preventive guardrails across all accounts. These policies override IAM permissions, including administrator access, so non-compliant actions are blocked before they happen. CloudFormation templates are deployed into individual accounts to provision resources that meet security baselines without manual configuration. Together, they create a defense-in-depth model where organization-level policies and account-level infrastructure work in tandem.

Compliance Frameworks

CJIS Security Policy

The FBI's CJIS Security Policy establishes security requirements for any organization that accesses, stores, or transmits Criminal Justice Information (CJI). This includes law enforcement agencies, cloud service providers hosting CJI, and contractors supporting criminal justice systems. Version 6.0 (released December 2024) restructured the policy from 13 to 20 policy areas, now organized by NIST 800-53 control families: Access Control (AC), Auditing and Accountability (AU), Configuration Management (CM), Systems and Communications Protection (SC), and others. Controls use NIST 800-53 identifiers directly, aligning CJIS requirements with federal cybersecurity standards. Version 6.0 introduces priority levels (P1 through P4) for phased implementation, with FBI audits underway as of October 2025 and full compliance expected by October 2027.

FedRAMP

The Federal Risk and Authorization Management Program (FedRAMP) standardizes security assessments for cloud service providers (CSPs) serving federal agencies. FedRAMP defines three authorization baselines, Low, Moderate, and High, corresponding to the FIPS 199 impact level of the data being processed. Each baseline specifies a set of required NIST 800-53 controls. This project targets FedRAMP High, which requires the most comprehensive set of security controls and applies to systems processing the government's most sensitive unclassified data.

NIST SP 800-53 Rev. 5

NIST Special Publication 800-53 Revision 5 is the authoritative catalog of security and privacy controls for federal information systems. It serves as the foundation for both CJIS and FedRAMP requirements. Controls are organized into families (AC for Access Control, AU for Audit, SC for System and Communications Protection, CM for Configuration Management) and provide the technical specificity needed to translate compliance requirements into enforceable infrastructure policies.

Controls Implemented

Control File Type What It Enforces Security Principle
Deny Audit Log Deletion scp-deny-audit-log-deletion.json SCP (Preventive) Blocks cloudtrail:DeleteTrail and cloudtrail:StopLogging across the organization Audit Integrity
Deny EC2 Actions scp-deny-ec2-actions.json SCP (Preventive) Denies all EC2 actions (ec2:*) org-wide, restricting unauthorized compute usage Least Functionality
Prevent Insecure SSH scp-prevent-insecure-ssh.json SCP (Preventive) Blocks security group rules that open SSH (port 22) to 0.0.0.0/0 in us-west-1 Network Boundary Protection
Require S3 Encryption scp-require-s3-encryption.json SCP (Preventive) Denies S3 bucket creation when encryption is not enabled Data Protection at Rest
Secure S3 Bucket secure-bucket.yaml CloudFormation (IaC) Deploys an S3 bucket with all public access blocked and AES256 server-side encryption Secure by Default

Compliance Framework Mapping

Each control was selected to address specific compliance requirements across CJIS Security Policy, FedRAMP, and NIST 800-53. The combination of preventive SCPs and compliant-by-default IaC templates creates layered enforcement; SCPs act as guardrails that cannot be bypassed even by IAM administrators, while CloudFormation ensures new resources are provisioned to meet baseline security requirements without manual configuration.

Control CJIS Security Policy (v6.0) FedRAMP Baseline NIST 800-53 Rev. 5
Deny Audit Log Deletion AU-9 (Protection of Audit Information), AU-12 (Audit Record Generation) AU-9 (L/M/H), AU-12 (L/M/H) AU-9 (Protection of Audit Information), AU-12 (Audit Record Generation)
Deny EC2 Actions CM-7 (Least Functionality), AC-6 (Least Privilege) CM-7 (L/M/H), AC-6 (M/H) CM-7 (Least Functionality), AC-6 (Least Privilege)
Prevent Insecure SSH SC-7 (Boundary Protection), AC-17 (Remote Access) SC-7 (L/M/H), AC-17 (L/M/H) SC-7 (Boundary Protection), AC-17 (Remote Access)
Require S3 Encryption SC-28 (Protection of Information at Rest), SC-13 (Cryptographic Protection) SC-28 (M/H), SC-13 (L/M/H) SC-28 (Protection of Information at Rest), SC-13 (Cryptographic Protection)
Secure S3 Bucket (CFn) SC-28 (Protection of Information at Rest), AC-3 (Access Enforcement) SC-28 (M/H), AC-3 (L/M/H) SC-28 (Protection of Information at Rest), AC-3 (Access Enforcement)

Note: CJIS v6.0 now uses NIST 800-53 control identifiers directly, so the CJIS and NIST columns share the same control IDs. The distinction is that CJIS scopes these requirements specifically to Criminal Justice Information (CJI), while NIST 800-53 applies broadly to federal information systems.

FedRAMP Baseline Key: L = Low, M = Moderate, H = High

Repository Structure

aws-compliance-as-code/
├── secure-bucket.yaml                  # CloudFormation: Secure S3 bucket (public access block + AES256)
├── scp-deny-audit-log-deletion.json    # SCP: Prevent CloudTrail deletion/stop logging
├── scp-deny-ec2-actions.json           # SCP: Deny all EC2 actions org-wide
├── scp-prevent-insecure-ssh.json       # SCP: Block SSH port 22 open to 0.0.0.0/0 (us-west-1)
├── scp-require-s3-encryption.json      # SCP: Require encryption on S3 bucket creation
├── LICENSE.txt                         # MIT License
└── README.md

AWS Services Used

  • AWS Organizations: Hosts the SCPs and enforces guardrails across the account hierarchy
  • AWS CloudFormation: Deploys compliant infrastructure as code (secure S3 bucket template)
  • AWS IAM: Underlying permission system that SCPs override at the organization level
  • AWS S3: Target service for the secure bucket deployment and encryption enforcement
  • AWS CloudTrail: Audit logging service protected by the audit log deletion SCP
  • AWS CLI: Interface for deploying SCPs and CloudFormation stacks

How It Works

Service Control Policies (Preventive Guardrails)

SCPs are attached at the Organization Root and act as permission boundaries that override IAM, even for administrator users. They are preventive controls: non-compliant actions are denied before they execute, regardless of the IAM policies attached to the requesting principal. This makes them ideal for enforcing compliance boundaries that individual account configurations cannot circumvent.

CloudFormation (Compliant by Default)

CloudFormation templates encode security requirements directly into resource definitions. The secure S3 bucket template in this project provisions a bucket with public access blocked and encryption enabled every time it deploys, eliminating the possibility of configuration drift or manual misconfiguration. The template itself serves as auditable documentation of the intended secure state.

Defense in Depth

SCPs prevent non-compliant actions at the organization level. CloudFormation ensures compliant defaults at the resource level. Git version control tracks every policy and template change, creating an auditable history that serves as evidence for compliance audits. This layered approach means a failure in one control does not compromise the overall security posture.

Deployment

Click to expand deployment instructions

Prerequisites

  • AWS account with Organizations enabled
  • IAM user with appropriate permissions
  • AWS CLI v2 installed and configured

Step 1: Discover Organization IDs

Get Organization Root ID:

aws organizations list-roots \
    --query "Roots[0].Id" \
    --output text

Example output:

r-abcd

List Organizational Units (if applicable):

aws organizations list-organizational-units-for-parent \
    --parent-id <ROOT_ID> \
    --query "OrganizationalUnits[*].Id" \
    --output text

Example output:

ou-abcd-12345678 ou-abcd-87654321 ou-abcd-a1b2c3d4

Step 2: Deploy Service Control Policies

Create each SCP:

aws organizations create-policy \
    --content file://<SCP_FILENAME>.json \
    --name <SCP_NAME> \
    --description "<POLICY_DESCRIPTION>" \
    --type SERVICE_CONTROL_POLICY

Replace <SCP_FILENAME> and <SCP_NAME> with the appropriate values for each policy.

Example output:

{
    "Policy": {
        "PolicySummary": {
            "Id": "p-0abc1234",
            "Arn": "arn:aws:organizations::123456789012:policy/service_control_policy/p-0abc1234",
            "Name": "SCP-DenyAuditLogDeletion",
            "Description": "Prevents the deletion of audit logs.",
            "Type": "SERVICE_CONTROL_POLICY",
            "AwsManaged": false
        },
        "Content": "..."
    }
}

List deployed SCPs:

aws organizations list-policies \
    --filter SERVICE_CONTROL_POLICY \
    --query "Policies[].{Name:Name, Id:Id}" \
    --output table

Example output:

----------------------------------------------
|              ListPolicies                  |
----------------------------------------------
|     Name                     |     Id       |
|------------------------------|--------------|
|  SCP-DenyRootUserActions     |  p-1a2b3c4d  |
|  SCP-DenyAuditLogDeletion    |  p-5e6f7g8h  |
|  SCP-PreventOpenSSH          |  p-9j0k1l2m  |
----------------------------------------------

Attach each SCP to the Organization Root:

aws organizations attach-policy \
    --policy-id <POLICY_ID> \
    --target-id <ROOT_ID>

Verify SCPs are attached:

aws organizations list-policies-for-target \
    --target-id <ROOT_ID> \
    --filter SERVICE_CONTROL_POLICY \
    --output table

Example output:

------------------------------------------------------
|              ListPoliciesForTarget                 |
------------------------------------------------------
|     Name                     |        Id           |
|----------------------------------------------------|
|  SCP-DenyRootUserActions     |  p-1a2b3c4d         |
|  SCP-DenyAuditLogDeletion    |  p-5e6f7g8h         |
------------------------------------------------------

Step 3: Deploy CloudFormation Stack

aws cloudformation deploy \
    --stack-name <STACK_NAME> \
    --template-file <STACK_FILENAME.yaml> \
    --capabilities CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND \
    --parameter-overrides \
        OrganizationId=<YOUR_ORG_ID> \
        OrgRootId=<ORG_ROOT_ID>

Example output:

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - <BUCKET_NAME>

Verify deployment:

aws cloudformation describe-stacks \
    --query "Stacks[*].StackName" \
    --output table

Updating Policies and Templates

Update an SCP:

aws organizations update-policy \
    --policy-id <POLICY_ID> \
    --content file://<UPDATED_SCP>.json

Update a CloudFormation stack:

aws cloudformation deploy \
    --stack-name <STACK_NAME> \
    --template-file <STACK_FILENAME>.yaml \
    --capabilities CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND

Resource Cleanup

Detach SCPs:

aws organizations detach-policy \
  --policy-id <POLICY_ID> \
  --target-id <ORG_ROOT_ID>

Delete CloudFormation stack:

aws cloudformation delete-stack \
  --stack-name <STACK_NAME>

Key Takeaways

  • Compliance as Code eliminates drift: By encoding security requirements in CloudFormation, resources are provisioned correctly every time without relying on manual configuration.

  • SCPs enforce boundaries that IAM cannot: Organization-level policies override even administrator permissions, providing a compliance layer that individual account configurations cannot circumvent.

  • Defense in depth through layered controls: Preventive SCPs combined with compliant-by-default IaC creates multiple enforcement points, so a failure in one layer does not compromise the security posture.

  • Automation reduces human error: Codified controls eliminate the inconsistency of manual reviews and create a repeatable, scalable compliance process.

  • Version control as audit evidence: Every policy change is tracked in Git, providing a complete history that serves as compliance evidence during audits.

What This Project Demonstrates

This project demonstrates the core GRC Engineering skill of translating compliance framework requirements into enforceable AWS controls. It showcases hands-on experience with AWS Organizations policy design, SCP authoring with condition-based logic, CloudFormation template development, and compliance framework mapping across CJIS Security Policy, FedRAMP, and NIST 800-53. The inclusion of CJIS and FedRAMP mappings reflects relevance to criminal justice environments and federal cloud authorization requirements.

The controls were selected to illustrate a range of enforcement patterns, from broad service restrictions (ec2:* deny) to condition-based rules (SSH port + CIDR + region matching) to encryption mandates, demonstrating the flexibility of SCPs as a compliance enforcement mechanism.

This foundation positions the project for expansion into CI/CD pipeline guardrails, AWS Config rules for continuous compliance monitoring, drift remediation automation, and multi-account architectures with OU-scoped policies.

References

The following resources informed the design of this project:

0xBahalaNa/aws-compliance-as-code | GitHunt