AWS Security Checklist for Production (Real Examples)
Most AWS breaches do not happen because of sophisticated zero-day exploits. They happen because of misconfigured S3 buckets, overpermissive IAM policies, and disabled logging. This checklist covers every critical AWS security control with real configuration examples you can apply today.
IAM: Identity and Access Management
IAM is the single most important security layer in AWS. Every other control depends on it. Get IAM wrong and nothing else matters.
Enable MFA on the Root Account
The root account has unrestricted access to everything in your AWS account. Enable hardware MFA (YubiKey preferred) on the root account immediately. Never use the root account for daily operations. Create IAM users or use AWS SSO instead.
Enforce Least Privilege IAM Policies
Every IAM policy should grant the minimum permissions needed. Never use Action: "*" or Resource: "*" in production policies. Here is a real example of a properly scoped policy for an application that needs to read from S3 and write to DynamoDB:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-app-data",
"arn:aws:s3:::my-app-data/*"
]
},
{
"Effect": "Allow",
"Action": [
"dynamodb:PutItem",
"dynamodb:GetItem",
"dynamodb:Query"
],
"Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/my-app-table"
}
]
}
Use IAM Roles Instead of Access Keys
Long-lived access keys are the most common source of AWS credential leaks. Use IAM roles with temporary credentials wherever possible:
- EC2 instances: Use instance profiles (IAM roles attached to EC2)
- ECS/EKS: Use task roles (ECS) or IRSA (EKS)
- Lambda: Use execution roles
- CI/CD: Use OIDC federation (GitHub Actions, GitLab CI) instead of storing access keys
- Cross-account: Use STS AssumeRole
If you must use access keys, rotate them every 90 days and monitor for exposure using the techniques in our API key exposure detection guide.
Enable IAM Access Analyzer
IAM Access Analyzer identifies resources shared with external entities and validates IAM policies against best practices. Enable it in every region:
aws accessanalyzer create-analyzer \
--analyzer-name production-analyzer \
--type ACCOUNT \
--region us-east-1
Check Your Web Infrastructure Security
AWS security is only one layer. Make sure your web application is not exposing secrets through .env files, git directories, or misconfigured headers.
Scan Your Domain FreeS3: Storage Security
Block Public Access (Account Level)
Enable S3 Block Public Access at the account level. This is the single most impactful S3 security control:
aws s3control put-public-access-block \
--account-id 123456789012 \
--public-access-block-configuration \
BlockPublicAcls=true,\
IgnorePublicAcls=true,\
BlockPublicPolicy=true,\
RestrictPublicBuckets=true
Enable Default Encryption
Every S3 bucket should have default encryption enabled. Use SSE-S3 (AES-256) as a baseline, or SSE-KMS for additional control over key management:
aws s3api put-bucket-encryption \
--bucket my-production-bucket \
--server-side-encryption-configuration '{
"Rules": [{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "aws:kms",
"KMSMasterKeyID": "arn:aws:kms:us-east-1:123456789012:key/key-id"
},
"BucketKeyEnabled": true
}]
}'
Enable Versioning and Object Lock
Versioning protects against accidental deletion and ransomware. Object Lock provides immutable backups:
aws s3api put-bucket-versioning \
--bucket my-production-bucket \
--versioning-configuration Status=Enabled
VPC: Network Security
Minimize Security Group Rules
Every security group should follow least privilege. Never use 0.0.0.0/0 for inbound rules except for public-facing load balancers on ports 80 and 443. Here is an example of a properly configured application security group:
# Application server - only accepts traffic from ALB
aws ec2 authorize-security-group-ingress \
--group-id sg-app-server \
--protocol tcp --port 8080 \
--source-group sg-alb
# Database - only accepts traffic from application
aws ec2 authorize-security-group-ingress \
--group-id sg-database \
--protocol tcp --port 5432 \
--source-group sg-app-server
Use VPC Flow Logs
Enable VPC Flow Logs to capture network traffic metadata. This is essential for forensic investigation and anomaly detection:
aws ec2 create-flow-logs \
--resource-type VPC \
--resource-ids vpc-123456 \
--traffic-type ALL \
--log-destination-type cloud-watch-logs \
--log-group-name /vpc/flow-logs/production
Use Private Subnets for Backend Services
Databases, caches, application servers, and internal services should run in private subnets with no direct internet access. Use NAT Gateways for outbound traffic and VPC endpoints for AWS service access. Use the Subnet Calculator to plan your CIDR allocation.
Logging and Monitoring
Enable CloudTrail in All Regions
CloudTrail records every API call in your AWS account. Enable it in all regions with a multi-region trail:
aws cloudtrail create-trail \
--name production-trail \
--s3-bucket-name my-cloudtrail-bucket \
--is-multi-region-trail \
--enable-log-file-validation \
--kms-key-id arn:aws:kms:us-east-1:123456789012:key/key-id
aws cloudtrail start-logging --name production-trail
Enable GuardDuty
GuardDuty provides intelligent threat detection by analyzing CloudTrail, VPC Flow Logs, and DNS logs. Enable it in every region:
aws guardduty create-detector --enable
GuardDuty detects cryptocurrency mining, unauthorized access attempts, compromised instances, and data exfiltration patterns. It costs approximately $1 to $2 per million events analyzed.
Set Up CloudWatch Alarms
Create alarms for critical security events:
- Root account login
- Failed console login attempts (more than 3 in 5 minutes)
- IAM policy changes
- Security group changes
- S3 bucket policy changes
- CloudTrail configuration changes
- Unauthorized API calls
Data Protection
Enable RDS Encryption
All RDS instances should have encryption at rest enabled. This cannot be changed after creation, so enable it from the start. Enable automated backups with a retention period of at least 7 days (35 days recommended for production).
Use AWS Secrets Manager
Never hardcode database passwords, API keys, or other secrets. Use AWS Secrets Manager with automatic rotation:
aws secretsmanager create-secret \
--name production/database/credentials \
--secret-string '{"username":"app_user","password":"generated-password"}'
# Enable automatic rotation
aws secretsmanager rotate-secret \
--secret-id production/database/credentials \
--rotation-lambda-arn arn:aws:lambda:us-east-1:123456789012:function:rotate-db-secret \
--rotation-rules AutomaticallyAfterDays=30
Learn more about securing secrets in our environment variables security guide.
Enable EBS Encryption by Default
aws ec2 enable-ebs-encryption-by-default --region us-east-1
The Complete Checklist
- Root account MFA enabled (hardware key preferred)
- No root access keys exist
- IAM password policy enforced (14+ characters, MFA required)
- All IAM policies follow least privilege
- IAM roles used instead of access keys where possible
- IAM Access Analyzer enabled
- S3 Block Public Access enabled (account level)
- S3 default encryption enabled on all buckets
- S3 versioning enabled on critical buckets
- VPC Flow Logs enabled
- Security groups follow least privilege (no 0.0.0.0/0 on non-public ports)
- Backend services in private subnets
- CloudTrail enabled in all regions with log validation
- GuardDuty enabled in all regions
- CloudWatch alarms for security events
- RDS encryption at rest enabled
- EBS encryption by default enabled
- AWS Secrets Manager for all credentials
- AWS Config enabled for compliance monitoring
- Billing alerts configured
Frequently Asked Questions
How much does AWS security tooling cost?
The core security services are surprisingly affordable. CloudTrail costs $2 per 100,000 management events (first trail is free). GuardDuty costs $1 to $4 per million events. AWS Config costs $0.003 per configuration item. For a small to mid-sized production environment, expect to spend $50 to $200 per month on security tooling. This is negligible compared to the cost of a breach, which averages $3.31 million for organizations under 500 employees.
Should I use AWS Organizations for a single account?
Yes. Even with a single account, AWS Organizations provides Service Control Policies (SCPs) that act as guardrails. You can use SCPs to prevent disabling CloudTrail, removing encryption, or making S3 buckets public. As you grow, you can add separate accounts for staging, development, and security tooling. Multi-account architecture is an AWS best practice for production environments.
What is the most overlooked AWS security control?
CloudTrail log file validation. Many organizations enable CloudTrail but skip log file validation, which means an attacker with access could modify or delete logs to cover their tracks. Always enable log file validation and store CloudTrail logs in a separate, locked-down S3 bucket with Object Lock enabled. Also frequently overlooked: checking what your web application exposes publicly. Run the SecureBin Exposure Checker to catch exposed configuration files that might contain AWS credentials.
Verify Your Web Security Posture
AWS infrastructure security means nothing if your application exposes .env files with database credentials. SecureBin Exposure Checker catches these issues in seconds.
Run Free Security CheckThe Bottom Line
AWS security is not about implementing every possible control. It is about consistently applying the fundamentals: least privilege IAM, encrypted storage, comprehensive logging, and network segmentation. The checklist above covers the controls that prevent the vast majority of AWS breaches. Start at the top, work through each item, and build security into your infrastructure from the beginning. Retrofitting security is always harder and more expensive than building it in from day one.
Related reading: Cloud Misconfigurations That Lead to Breaches, Secure Environment Variables in Production, How to Check if API Key is Exposed, SOC 2 Compliance Checklist.