Cloud misconfiguration — public S3, open security groups, bucket ACLs
Misconfiguration is the number one cause of data breaches in cloud environments. Not malware, not a zero-day exploit — a checkbox checked wrong, an overly permissive policy, a resource accidentally exposed. CSPM (Cloud Security Posture Management) exists precisely to detect these flaws at scale.
Public S3 — the classic leak
S3 buckets with public access have exposed health, financial, and government data belonging to millions of people. The most common mistake: disabling “Block Public Access” without understanding the impact.
# Check whether Block Public Access is enabled on a bucket
aws s3api get-public-access-block --bucket my-bucket
# Safe response (all true):
# {
# "PublicAccessBlockConfiguration": {
# "BlockPublicAcls": true,
# "IgnorePublicAcls": true,
# "BlockPublicPolicy": true,
# "RestrictPublicBuckets": true
# }
# }
# Fix — enable full blocking
aws s3api put-public-access-block \
--bucket my-bucket \
--public-access-block-configuration \
"BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"
Bucket policy that accidentally leaks data:
// BAD — allows public read on all objects
{
"Statement": [{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
}]
}
// GOOD — access only from the application role
{
"Statement": [{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::123456789:role/app-role" },
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
}]
}
Security Groups — overly open ports
Security groups work as stateful firewalls. The most common mistake is opening 0.0.0.0/0 on critical ports:
# List dangerous ingress rules
aws ec2 describe-security-groups \
--query "SecurityGroups[?IpPermissions[?IpRanges[?CidrIp=='0.0.0.0/0']]].{ID:GroupId,Name:GroupName,Rules:IpPermissions}" \
--output table
Ports that must never be open to 0.0.0.0/0 in production:
22 (SSH) → use Systems Manager Session Manager
3389 (RDP) → use SSM or VPN
3306 (MySQL) → access only from app subnet
5432 (Postgres) → same
6379 (Redis) → never exposed to the internet
27017 (MongoDB) → same
443 (HTTPS) → acceptable if it's a public load balancer
Correct pattern:
DB SG → ingress only from app SG, specific port
App SG → ingress from load balancer SG
LB SG → ingress 0.0.0.0/0 on 443 only
Bucket ACL vs bucket policy
ACLs are the legacy mechanism in AWS. AWS recommends disabling ACLs and using bucket policies only:
# Check bucket ownership controls
aws s3api get-bucket-ownership-controls --bucket my-bucket
# Set BucketOwnerEnforced (disables ACLs)
aws s3api put-bucket-ownership-controls \
--bucket my-bucket \
--ownership-controls "Rules=[{ObjectOwnership=BucketOwnerEnforced}]"
Other common misconfiguration vectors
RDS with public access:
aws rds modify-db-instance \
--db-instance-identifier my-db \
--no-publicly-accessible
Public EBS/RDS snapshot:
aws rds describe-db-snapshots \
--query "DBSnapshots[?PubliclyRestored==true]"
Lambda with open resource policy:
Remove policies that grant invocation to "*"
aws lambda remove-permission --function-name my-func --statement-id dangerous-id
CloudFront without forced HTTPS:
ViewerProtocolPolicy: redirect-to-https (never allow-all)
Automated detection
# AWS Config — managed rule for public S3
aws configservice put-config-rule --config-rule '{
"ConfigRuleName": "s3-bucket-public-read-prohibited",
"Source": {
"Owner": "AWS",
"SourceIdentifier": "S3_BUCKET_PUBLIC_READ_PROHIBITED"
}
}'
# Security Hub — enable CIS AWS Foundations Benchmark
aws securityhub enable-security-hub --enable-default-standards
Use tools like Prowler, ScoutSuite, or Checkov for continuous misconfiguration scanning in your pipeline and account.