AWS Security Hub CIS Benchmark Compliance Guide

Complete guide to implementing CIS AWS Foundations Benchmark with Security Hub including enabling controls, understanding findings, and remediation.

11 min readUpdated 2026-01-14

AWS Security Hub provides automated compliance checks against the CIS AWS Foundations Benchmark, helping you identify security gaps and maintain compliance with industry best practices. This guide covers enabling the CIS standard, understanding controls, and remediating common findings.

This article is part of our comprehensive Cloud Security Tips for 2026 guide covering essential practices for protecting your cloud environment.

CIS Benchmark Sections

SectionFocus AreaControl Count
1Identity and Access Management21 controls
2Logging14 controls
3Monitoring14 controls
4Networking5 controls
5Storage4 controls

Enable Security Hub and CIS Standard

Prerequisites

AWS Config must be enabled before Security Hub:

# Enable AWS Config
aws configservice put-configuration-recorder \
  --configuration-recorder name=default,roleARN=arn:aws:iam::123456789012:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig \
  --recording-group allSupported=true,includeGlobalResourceTypes=true

aws configservice put-delivery-channel \
  --delivery-channel '{
    "name": "default",
    "s3BucketName": "config-bucket-123456789012",
    "configSnapshotDeliveryProperties": {
      "deliveryFrequency": "TwentyFour_Hours"
    }
  }'

aws configservice start-configuration-recorder \
  --configuration-recorder-name default

Enable Security Hub

# Enable Security Hub
aws securityhub enable-security-hub \
  --enable-default-standards

# Or enable without default standards (add manually)
aws securityhub enable-security-hub \
  --no-enable-default-standards

Enable CIS AWS Foundations Benchmark

# Enable CIS v1.4.0 standard
aws securityhub batch-enable-standards \
  --standards-subscription-requests '[{
    "StandardsArn": "arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.4.0"
  }]'

# List enabled standards
aws securityhub get-enabled-standards

# Check standard status
aws securityhub describe-standards-controls \
  --standards-subscription-arn "arn:aws:securityhub:us-east-1:123456789012:subscription/cis-aws-foundations-benchmark/v/1.4.0"

Multi-Account Setup

# From management account: Designate delegated admin
aws securityhub enable-organization-admin-account \
  --admin-account-id 111122223333

# From delegated admin: Enable for all accounts
aws securityhub create-members \
  --account-details '[
    {"AccountId": "444455556666"},
    {"AccountId": "777788889999"}
  ]'

# Auto-enable for new accounts
aws securityhub update-organization-configuration \
  --auto-enable

# Configure central findings aggregation
aws securityhub create-finding-aggregator \
  --region-linking-mode ALL_REGIONS

View Compliance Status

Get Security Score

# Get overall security score
aws securityhub get-security-control-definitions

# Get compliance summary by standard
aws securityhub describe-standards-controls \
  --standards-subscription-arn "arn:aws:securityhub:us-east-1:123456789012:subscription/cis-aws-foundations-benchmark/v/1.4.0" \
  --query 'Controls[*].[ControlId,ControlStatus,SeverityRating]' \
  --output table

View Failed Controls

# List failed CIS controls
aws securityhub get-findings \
  --filters '{
    "ComplianceStatus": [{"Value": "FAILED", "Comparison": "EQUALS"}],
    "ProductName": [{"Value": "Security Hub", "Comparison": "EQUALS"}],
    "GeneratorId": [{"Value": "cis-aws-foundations-benchmark", "Comparison": "PREFIX"}]
  }' \
  --query 'Findings[*].[Title,Compliance.Status,Severity.Label]' \
  --output table

# Get detailed findings for specific control
aws securityhub get-findings \
  --filters '{
    "GeneratorId": [{"Value": "cis-aws-foundations-benchmark/v/1.4.0/1.4", "Comparison": "EQUALS"}]
  }'

Key CIS Controls and Remediation

Section 1: Identity and Access Management

1.4 - Ensure no root account access key exists

# Check for root access keys
aws iam get-account-summary \
  --query 'SummaryMap.AccountAccessKeysPresent'

# Remediation: Delete root access keys via Console
# 1. Sign in as root user
# 2. Navigate to Security Credentials
# 3. Delete any access keys

1.5 - Ensure MFA is enabled for root account

# Check root MFA status
aws iam get-account-summary \
  --query 'SummaryMap.AccountMFAEnabled'

# Remediation: Enable MFA via Console
# Use hardware MFA or virtual MFA app

1.10 - Ensure IAM password policy requires minimum length of 14

# Check current password policy
aws iam get-account-password-policy

# Set compliant password policy
aws iam update-account-password-policy \
  --minimum-password-length 14 \
  --require-symbols \
  --require-numbers \
  --require-uppercase-characters \
  --require-lowercase-characters \
  --allow-users-to-change-password \
  --max-password-age 90 \
  --password-reuse-prevention 24

1.16 - Ensure IAM policies are attached only to groups or roles

# Find users with directly attached policies
aws iam list-users --query 'Users[*].UserName' --output text | \
  xargs -I {} aws iam list-attached-user-policies --user-name {}

# Remediation: Move policies to groups
aws iam add-user-to-group --user-name username --group-name groupname
aws iam detach-user-policy --user-name username --policy-arn arn:aws:iam::aws:policy/PolicyName

Section 2: Logging

2.1 - Ensure CloudTrail is enabled in all regions

# Check for multi-region trail
aws cloudtrail describe-trails \
  --query 'trailList[*].[Name,IsMultiRegionTrail,IsLogging]'

# Create multi-region trail
aws cloudtrail create-trail \
  --name organization-trail \
  --s3-bucket-name cloudtrail-logs-bucket \
  --is-multi-region-trail \
  --include-global-service-events \
  --enable-log-file-validation

aws cloudtrail start-logging --name organization-trail

2.6 - Ensure S3 bucket access logging is enabled on CloudTrail S3 bucket

# Check bucket logging
aws s3api get-bucket-logging --bucket cloudtrail-logs-bucket

# Enable bucket logging
aws s3api put-bucket-logging \
  --bucket cloudtrail-logs-bucket \
  --bucket-logging-status '{
    "LoggingEnabled": {
      "TargetBucket": "access-logs-bucket",
      "TargetPrefix": "cloudtrail-bucket-logs/"
    }
  }'

Section 3: Monitoring

3.1-3.14 - CloudWatch alarms for API activity

# Create metric filter and alarm for unauthorized API calls (3.1)
aws logs put-metric-filter \
  --log-group-name CloudTrail/DefaultLogGroup \
  --filter-name UnauthorizedAPICalls \
  --filter-pattern '{ ($.errorCode = "*UnauthorizedAccess*") || ($.errorCode = "AccessDenied*") }' \
  --metric-transformations '[{
    "metricName": "UnauthorizedAPICallsCount",
    "metricNamespace": "CISBenchmark",
    "metricValue": "1"
  }]'

aws cloudwatch put-metric-alarm \
  --alarm-name "CIS-3.1-UnauthorizedAPICalls" \
  --metric-name UnauthorizedAPICallsCount \
  --namespace CISBenchmark \
  --statistic Sum \
  --period 300 \
  --threshold 1 \
  --comparison-operator GreaterThanOrEqualToThreshold \
  --evaluation-periods 1 \
  --alarm-actions arn:aws:sns:us-east-1:123456789012:security-alerts

# Console sign-in without MFA (3.2)
aws logs put-metric-filter \
  --log-group-name CloudTrail/DefaultLogGroup \
  --filter-name ConsoleSignInWithoutMFA \
  --filter-pattern '{ ($.eventName = "ConsoleLogin") && ($.additionalEventData.MFAUsed != "Yes") }' \
  --metric-transformations '[{
    "metricName": "ConsoleSignInWithoutMFACount",
    "metricNamespace": "CISBenchmark",
    "metricValue": "1"
  }]'

# Root account usage (3.3)
aws logs put-metric-filter \
  --log-group-name CloudTrail/DefaultLogGroup \
  --filter-name RootAccountUsage \
  --filter-pattern '{ $.userIdentity.type = "Root" && $.userIdentity.invokedBy NOT EXISTS && $.eventType != "AwsServiceEvent" }' \
  --metric-transformations '[{
    "metricName": "RootAccountUsageCount",
    "metricNamespace": "CISBenchmark",
    "metricValue": "1"
  }]'

Section 4: Networking

4.1 - Ensure no security groups allow ingress from 0.0.0.0/0 to port 22

# Find security groups with open SSH
aws ec2 describe-security-groups \
  --filters 'Name=ip-permission.from-port,Values=22' \
            'Name=ip-permission.to-port,Values=22' \
            'Name=ip-permission.cidr,Values=0.0.0.0/0' \
  --query 'SecurityGroups[*].[GroupId,GroupName]'

# Remediation: Remove open rule
aws ec2 revoke-security-group-ingress \
  --group-id sg-12345678 \
  --protocol tcp \
  --port 22 \
  --cidr 0.0.0.0/0

4.3 - Ensure VPC flow logging is enabled in all VPCs

# List VPCs without flow logs
for vpc in $(aws ec2 describe-vpcs --query 'Vpcs[*].VpcId' --output text); do
  flow_logs=$(aws ec2 describe-flow-logs --filter "Name=resource-id,Values=$vpc" --query 'FlowLogs[*].FlowLogId' --output text)
  if [ -z "$flow_logs" ]; then
    echo "VPC $vpc has no flow logs"
  fi
done

# Enable flow logging
aws ec2 create-flow-logs \
  --resource-type VPC \
  --resource-ids vpc-12345678 \
  --traffic-type ALL \
  --log-destination-type cloud-watch-logs \
  --log-group-name VPCFlowLogs \
  --deliver-logs-permission-arn arn:aws:iam::123456789012:role/FlowLogsRole

Section 5: Storage

5.1 - Ensure S3 bucket has block public access enabled

# Check account-level public access block
aws s3control get-public-access-block --account-id 123456789012

# Enable account-level block
aws s3control put-public-access-block \
  --account-id 123456789012 \
  --public-access-block-configuration '{
    "BlockPublicAcls": true,
    "IgnorePublicAcls": true,
    "BlockPublicPolicy": true,
    "RestrictPublicBuckets": true
  }'

Disable Controls

Disable controls that don't apply to your environment:

# Disable specific control
aws securityhub update-standards-control \
  --standards-control-arn "arn:aws:securityhub:us-east-1:123456789012:control/cis-aws-foundations-benchmark/v/1.4.0/1.20" \
  --control-status DISABLED \
  --disabled-reason "Not applicable - using SSO for user management"

# Re-enable control
aws securityhub update-standards-control \
  --standards-control-arn "arn:aws:securityhub:us-east-1:123456789012:control/cis-aws-foundations-benchmark/v/1.4.0/1.20" \
  --control-status ENABLED

Automated Remediation

Use Lambda and EventBridge for automatic remediation:

# EventBridge rule for specific CIS finding
aws events put-rule \
  --name "RemediateOpenSecurityGroup" \
  --event-pattern '{
    "source": ["aws.securityhub"],
    "detail-type": ["Security Hub Findings - Imported"],
    "detail": {
      "findings": {
        "GeneratorId": [{"prefix": "cis-aws-foundations-benchmark/v/1.4.0/4.1"}],
        "Compliance": {"Status": ["FAILED"]}
      }
    }
  }'

# Lambda function for remediation
import boto3

def lambda_handler(event, context):
    ec2 = boto3.client('ec2')

    for finding in event['detail']['findings']:
        sg_id = finding['Resources'][0]['Id'].split('/')[-1]

        # Remove open SSH rule
        try:
            ec2.revoke_security_group_ingress(
                GroupId=sg_id,
                IpPermissions=[{
                    'IpProtocol': 'tcp',
                    'FromPort': 22,
                    'ToPort': 22,
                    'IpRanges': [{'CidrIp': '0.0.0.0/0'}]
                }]
            )
            print(f"Remediated {sg_id}")
        except Exception as e:
            print(f"Error: {e}")

Generate Compliance Reports

# Export findings to S3
aws securityhub create-insight \
  --name "CIS-Compliance-Report" \
  --filters '{
    "GeneratorId": [{"Value": "cis-aws-foundations-benchmark", "Comparison": "PREFIX"}]
  }' \
  --group-by-attribute ComplianceStatus

# Get findings for reporting
aws securityhub get-findings \
  --filters '{
    "ProductName": [{"Value": "Security Hub", "Comparison": "EQUALS"}],
    "GeneratorId": [{"Value": "cis-aws-foundations-benchmark", "Comparison": "PREFIX"}]
  }' \
  --query 'Findings[*].[GeneratorId,Compliance.Status,Severity.Label,Title]' \
  --output json > cis-report.json

Best Practices

PracticeRecommendation
VersionUse CIS v1.4.0 for new implementations
Multi-AccountUse delegated administrator for centralized view
BaselineAchieve 100% compliance before adding workloads
ExceptionsDocument and justify disabled controls
AutomationImplement automated remediation for common findings
MonitoringTrack compliance score trends over time
ReviewsConduct monthly compliance reviews

Compliance Score Targets

EnvironmentTarget ScoreTimeline
Development80%+Ongoing
Staging90%+Before production
Production95%+Maintain continuously
Regulated100%Required for compliance

Frequently Asked Questions

Find answers to common questions

The CIS AWS Foundations Benchmark is a set of security best practices developed by the Center for Internet Security (CIS) specifically for AWS environments. It covers identity and access management, logging and monitoring, networking, and resource configuration. Security Hub automates compliance checking against CIS controls. Version 1.4.0 includes 58 controls across 5 sections. Following CIS helps meet regulatory requirements and demonstrates security due diligence.

Need Professional Help?

Our team of experts can help you implement and configure these solutions for your organization.