Cloud Security

AWS Security Checklist: 40 Controls for Hardening Your AWS Account

A comprehensive 40-control checklist covering IAM, networking, data protection, and monitoring to harden any AWS account against modern threats.

August 15, 20259 min readShipSafer Team

The CIS AWS Foundations Benchmark is the industry-standard baseline for AWS security, but at over 80 pages it can be daunting to operationalize. This checklist distills it — plus additional controls from the AWS Well-Architected Security Pillar and NIST SP 800-53 — into 40 concrete, actionable items organized by domain. Each item includes the relevant CLI command or configuration snippet.

Identity and Access Management

1. Enable MFA on the Root Account

The root account must have a hardware MFA device (YubiKey or equivalent). Virtual MFA is acceptable but hardware is preferred.

# Verify root MFA status
aws iam get-account-summary --query 'SummaryMap.AccountMFAEnabled'
# 1 = enabled, 0 = not enabled

2. Delete Root Account Access Keys

Root access keys cannot be restricted and grant unlimited API access. Delete them.

aws iam list-access-keys --user-name root 2>/dev/null || echo "No root access keys (expected)"

3. Set Account Password Policy

Enforce complexity, minimum length of 14 characters, and password rotation:

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

4. Enforce MFA for All IAM Users

Attach a policy to all users or the AllUsers group that denies all actions except MFA enrollment when MFA is absent. See the DenyWithoutMFA policy pattern in the misconfigurations guide.

5. No Access Keys for Root

This is separate from #2 — periodically re-verify. Automate with a Config rule:

aws configservice put-config-rule --config-rule '{
  "ConfigRuleName": "root-access-key-check",
  "Source": {"Owner": "AWS", "SourceIdentifier": "IAM_ROOT_ACCESS_KEY_CHECK"}
}'

6. Use IAM Roles for EC2 Instances (Not Access Keys)

Never place access keys on EC2 instances. Attach instance profiles with least-privilege roles instead. Audit for keys on instances:

# Check if any instances have access keys embedded in user data
aws ec2 describe-instances \
  --query 'Reservations[].Instances[].{ID:InstanceId,UserData:UserData}' | \
  grep -i "AKIA"

7. Apply Permission Boundaries to Developer Roles

Permission boundaries cap the maximum effective permissions, preventing privilege escalation even if a role's policies are accidentally broadened.

8. Enable IAM Access Analyzer

Access Analyzer identifies resources shared outside your account or organization:

aws accessanalyzer create-analyzer \
  --analyzer-name org-analyzer \
  --type ORGANIZATION

9. Use SCPs to Enforce Guardrails

If using AWS Organizations, apply Service Control Policies to deny dangerous actions at the OU level. Example: deny disabling CloudTrail:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "DenyCloudTrailDisable",
    "Effect": "Deny",
    "Action": [
      "cloudtrail:DeleteTrail",
      "cloudtrail:StopLogging",
      "cloudtrail:UpdateTrail"
    ],
    "Resource": "*"
  }]
}

10. Rotate Access Keys Regularly

Keys older than 90 days should be rotated. Audit:

aws iam generate-credential-report
aws iam get-credential-report --query 'Content' --output text | base64 -d | \
  awk -F, 'NR>1 && $9 != "N/A" && $9 < "'$(date -d '-90 days' +%Y-%m-%d)'" {print $1, $9}'

Networking

11. Enable VPC Flow Logs

Flow logs capture metadata about network traffic and are essential for incident response:

aws ec2 create-flow-logs \
  --resource-type VPC \
  --resource-ids vpc-12345 \
  --traffic-type ALL \
  --log-destination-type cloud-watch-logs \
  --log-group-name /aws/vpc/flowlogs

12. No Security Groups Open to 0.0.0.0/0 on Admin Ports

Ports 22, 3389, 5432, 3306, 6379, 27017 must not be reachable from 0.0.0.0/0. Use Systems Manager Session Manager for SSH/RDP instead.

13. Delete the Default VPC

# For each region, delete internet gateway, subnets, then VPC
VPC_ID=$(aws ec2 describe-vpcs --filters Name=isDefault,Values=true \
  --query 'Vpcs[0].VpcId' --output text)
IGW_ID=$(aws ec2 describe-internet-gateways \
  --filters Name=attachment.vpc-id,Values=$VPC_ID \
  --query 'InternetGateways[0].InternetGatewayId' --output text)
aws ec2 detach-internet-gateway --internet-gateway-id $IGW_ID --vpc-id $VPC_ID
aws ec2 delete-internet-gateway --internet-gateway-id $IGW_ID
# Then delete subnets and VPC

14. Use Private Subnets for Compute

EC2 instances, ECS tasks, and Lambda functions should run in private subnets with no direct route to the internet gateway. Use NAT gateways for outbound-only internet access.

15. Enable AWS Network Firewall for Egress Filtering

For workloads requiring internet access, deploy Network Firewall with domain-based filtering to block connections to known malicious hosts and restrict egress to known-good destinations.

16. Use VPC Endpoints for AWS Services

Route S3, DynamoDB, SSM, and Secrets Manager traffic through VPC endpoints to keep it off the public internet:

aws ec2 create-vpc-endpoint \
  --vpc-id vpc-12345 \
  --service-name com.amazonaws.us-east-1.secretsmanager \
  --vpc-endpoint-type Interface \
  --subnet-ids subnet-private1 subnet-private2 \
  --security-group-ids sg-endpoint

Data Protection

17. Enable S3 Block Public Access at Account Level

aws s3control put-public-access-block \
  --account-id $(aws sts get-caller-identity --query Account --output text) \
  --public-access-block-configuration \
    BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true

18. Enable S3 Versioning and MFA Delete on Critical Buckets

Versioning protects against accidental or malicious deletion. MFA Delete requires MFA for permanent deletion:

aws s3api put-bucket-versioning \
  --bucket critical-data-bucket \
  --versioning-configuration MFADelete=Enabled,Status=Enabled \
  --mfa "arn:aws:iam::123456789012:mfa/root-account-mfa-device 123456"

19. Enable Default Encryption on All S3 Buckets

Use SSE-KMS with customer-managed keys so you control key rotation and access.

20. Enable EBS Encryption by Default

aws ec2 enable-ebs-encryption-by-default
aws ec2 get-ebs-encryption-by-default

21. Encrypt RDS Instances

Enable encryption at creation. For existing unencrypted databases, create a snapshot, copy it with encryption enabled, and restore.

22. Rotate KMS Keys Annually

Enable automatic key rotation for all customer-managed KMS keys:

aws kms enable-key-rotation --key-id <KEY_ID>

23. Store Secrets in Secrets Manager, Not Environment Variables

Audit Lambda functions and ECS task definitions for secrets in environment variables:

aws lambda list-functions --query 'Functions[].FunctionName' --output text | \
  xargs -I{} aws lambda get-function-configuration --function-name {} \
  --query 'Environment.Variables'

24. Enable S3 Access Logging

Log requests to critical buckets to a separate logging bucket:

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

Monitoring and Detection

25. Enable CloudTrail Multi-Region Trail

A single multi-region trail with log file validation enabled and logs sent to a locked S3 bucket in a separate security account.

26. Enable AWS Config

Config records configuration changes to resources and evaluates compliance against rules:

aws configservice put-configuration-recorder \
  --configuration-recorder name=default,roleARN=arn:aws:iam::123456789012:role/ConfigRole \
  --recording-group allSupported=true,includeGlobalResourceTypes=true

27. Enable GuardDuty in All Regions

GuardDuty uses ML and threat intelligence to detect anomalous activity. Enable it across all regions and for all accounts in your organization:

aws guardduty create-detector --enable \
  --data-sources '{"S3Logs":{"Enable":true},"EKSAuditLogs":{"Enable":true},"MalwareProtection":{"ScanEc2InstanceWithFindings":{"EbsVolumes":{"Enable":true}}}}'

28. Enable Security Hub

Security Hub aggregates findings from GuardDuty, Inspector, Macie, and third-party tools, and runs CIS and AWS Foundational Security Best Practice checks:

aws securityhub enable-security-hub \
  --enable-default-standards

29. Enable Amazon Macie

Macie uses ML to discover and protect sensitive data (PII, credentials) in S3:

aws macie2 enable-macie
aws macie2 create-classification-job \
  --job-type SCHEDULED \
  --name "Daily S3 Scan" \
  --schedule-frequency '{"dailySchedule":{}}' \
  --s3-job-definition '{"bucketDefinitions":[{"accountId":"123456789012","buckets":["my-bucket"]}]}'

30. Create CloudWatch Metric Filters for Critical Events

Alert on root login, MFA disable, CloudTrail changes, and security group modifications:

# Root login alarm
aws cloudwatch put-metric-alarm \
  --alarm-name RootAccountLogin \
  --metric-name RootAccountLoginCount \
  --namespace CloudTrailMetrics \
  --statistic Sum \
  --period 300 \
  --threshold 1 \
  --comparison-operator GreaterThanOrEqualToThreshold \
  --alarm-actions arn:aws:sns:us-east-1:123456789012:SecurityAlerts

31. Enable CloudTrail Insights

CloudTrail Insights detects unusual write API call volumes that may indicate an ongoing attack or misconfiguration:

aws cloudtrail put-insight-selectors \
  --trail-name my-trail \
  --insight-selectors '[{"InsightType":"ApiCallRateInsight"},{"InsightType":"ApiErrorRateInsight"}]'

32. Enable Inspector for Vulnerability Scanning

AWS Inspector continuously scans EC2 instances, ECR container images, and Lambda functions for vulnerabilities:

aws inspector2 enable --resource-types EC2 ECR LAMBDA

Incident Response Readiness

33. Create a Dedicated Security Account

In AWS Organizations, designate a separate security account as the delegated administrator for GuardDuty, Security Hub, Macie, and CloudTrail. This account cannot be modified by workload account operators.

34. Enable S3 Object Lock on CloudTrail Bucket

Prevent log tampering with WORM (Write Once Read Many) protection:

aws s3api put-object-lock-configuration \
  --bucket cloudtrail-logs-bucket \
  --object-lock-configuration '{
    "ObjectLockEnabled": "Enabled",
    "Rule": {
      "DefaultRetention": {
        "Mode": "COMPLIANCE",
        "Years": 7
      }
    }
  }'

35. Create Runbooks for Common GuardDuty Findings

Document response procedures for UnauthorizedAccess:IAMUser/ConsoleLoginSuccess.B, CryptoCurrency:EC2/BitcoinTool.B!DNS, and Recon:IAMUser/MaliciousIPCaller. Store runbooks in a location accessible even if your primary account is compromised.

36. Enable AWS Backup with Cross-Region Replication

Critical data should have automated backups in a separate region and account to survive ransomware or accidental deletion.

37. Use AWS Systems Manager Parameter Store / Secrets Manager for Rotation

Configure automatic rotation for all database credentials and API keys stored in Secrets Manager.

38. Tag All Resources

Consistent tagging enables cost attribution, security scoping, and automated policy enforcement. Enforce tagging with Config rules or Tag Policies in Organizations:

{
  "tags": {
    "Environment": {"tag_value": {"@@assign": ["production", "staging", "development"]}},
    "Owner": {}
  }
}

39. Enable Trusted Advisor Security Checks

Trusted Advisor identifies open security group rules, public S3 buckets, and IAM users without MFA. Business and Enterprise support tiers expose all checks via API.

40. Automate Compliance Scanning with Prowler

Prowler is an open-source tool that runs over 300 checks against CIS, PCI-DSS, HIPAA, GDPR, NIST, and SOC2 frameworks:

docker run --rm -it \
  -e AWS_ACCESS_KEY_ID \
  -e AWS_SECRET_ACCESS_KEY \
  -e AWS_SESSION_TOKEN \
  toniblyx/prowler:latest \
  -M csv -o /output \
  --compliance cis_level2_aws

Run Prowler weekly or integrate it into your CI/CD pipeline to catch drift before it becomes a breach.

Prioritization

If you're starting from scratch, prioritize in this order:

  1. Root MFA (#1) and delete root access keys (#2)
  2. CloudTrail multi-region trail (#25) and GuardDuty (#27)
  3. S3 Block Public Access (#17) and EBS encryption by default (#20)
  4. MFA enforcement for all IAM users (#4)
  5. Security Hub with CIS benchmark (#28)

Items 1-5 take less than an hour to implement and eliminate the majority of risk from opportunistic attackers. The remaining 35 controls harden your environment against more sophisticated threats and ensure compliance readiness.

AWS
security checklist
IAM
CloudTrail
GuardDuty
CIS benchmark

Check Your Security Score — Free

See exactly how your domain scores on DMARC, TLS, HTTP headers, and 25+ other automated security checks in under 60 seconds.