AWS cloud security is not a single feature you turn on. It is a set of overlapping controls — identity, network, data, and detection — that work together to reduce your attack surface.
Most security breaches on AWS are not caused by AWS failures. They are caused by misconfigured IAM policies, publicly accessible S3 buckets, unencrypted data, and missing detection controls. All of them are preventable. All of them are things you control.
This guide covers the six pillars of AWS security, the specific controls in each, and the mistakes that get teams breached.
The AWS shared responsibility model (your security starts here)
AWS secures the infrastructure — the physical data centers, the hypervisor, the hardware, the global network. You secure everything you put on that infrastructure.
AWS is responsible for:
- Physical data centers and hardware
- Global network infrastructure
- Hypervisor and host OS
- Managed service infrastructure (the RDS database engine, the Lambda runtime)
You are responsible for:
- IAM users, roles, and policies
- Network configuration (VPCs, security groups, NACLs)
- Data encryption at rest and in transit
- Operating system patches on EC2 instances
- Application security
- Monitoring and detection
The most important sentence in AWS security: misconfigured, not breached. The vast majority of AWS security incidents are self-inflicted — someone configured something wrong. Understanding what you own prevents most of them.
Pillar 1 — IAM: Identity and Access Management
IAM controls who can do what in your AWS account. It is the most critical security control and the most commonly misconfigured.
The principle of least privilege
Every IAM user, role, and service should have the minimum permissions required to do its job — nothing more.
What this looks like in practice:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-app-bucket/*"
}
]
}
This Lambda function can read and write objects in one specific bucket. It cannot list buckets, delete objects, create buckets, or touch any other AWS service. Least privilege means your blast radius when something goes wrong is limited.
What least privilege is not:
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
This is AdministratorAccess. Never attach it to application roles, Lambda functions, or EC2 instance profiles. Save it for break-glass admin scenarios with MFA enforcement.
IAM security rules every account needs
Enable MFA on the root account — immediately
The root account has unlimited access to everything in your AWS account including billing and account closure. It cannot be restricted by SCPs or permission boundaries. Protect it with MFA and never use it for daily work.
Never create IAM access keys for the root account
If root access keys exist, delete them. There is no legitimate reason for them.
Use roles, not users, for application access
EC2 instances, Lambda functions, ECS tasks — none of them should have IAM users or access keys. Attach an IAM role. AWS automatically rotates the temporary credentials. No secrets to store, no rotation to manage, no credentials to leak.
Use IAM roles for cross-account access
If your application needs to access resources in another AWS account, use a cross-account IAM role. Never pass IAM access keys between accounts.
IAM Access Analyzer
IAM Access Analyzer identifies resources that are accessible from outside your account — S3 buckets, IAM roles, KMS keys, Lambda functions, SQS queues, Secrets Manager secrets.
# Enable Access Analyzer for your account
aws accessanalyzer create-analyzer \
--analyzer-name "account-analyzer" \
--type ACCOUNT
Run this in every region you use. Review findings weekly. Any external access that isn't intentional is a finding worth investigating.
Pillar 2 — VPC: Network Security
Your VPC is your private network in AWS. Network security controls what can reach your resources and what your resources can reach.
Security groups vs NACLs
These two controls are frequently confused. They serve different purposes.
| Security Groups | NACLs | |
|---|---|---|
| Level | Instance (resource) level | Subnet level |
| Stateful | Yes — return traffic automatic | No — must allow both directions |
| Rules | Allow only (no deny) | Allow and deny |
| Default | Deny all inbound, allow all outbound | Allow all |
| Best for | Controlling access to specific resources | Broad subnet-level controls |
Security group best practices:
# Create a security group for a web server
aws ec2 create-security-group \
--group-name web-server-sg \
--description "Web server security group" \
--vpc-id vpc-0123456789abcdef0
# Allow HTTPS from anywhere (not HTTP — use HTTPS only)
aws ec2 authorize-security-group-ingress \
--group-id sg-0123456789abcdef0 \
--protocol tcp \
--port 443 \
--cidr 0.0.0.0/0
# Allow SSH only from your office IP — never from 0.0.0.0/0
aws ec2 authorize-security-group-ingress \
--group-id sg-0123456789abcdef0 \
--protocol tcp \
--port 22 \
--cidr 203.0.113.0/24
The most dangerous security group rule:
Port 22 (SSH), Source: 0.0.0.0/0
This opens SSH to the entire internet. Your server will be receiving brute force attempts within minutes of being created. Use AWS Systems Manager Session Manager instead of SSH — no open ports required.
VPC design for security
Public subnet: Resources that need direct internet access — Load Balancers, NAT Gateways.
Private subnet: Application servers, databases — never directly internet-accessible.
Isolated subnet: Databases and sensitive data stores that should not even reach the internet outbound.
Internet Gateway
↓
Public Subnet (ALB, NAT Gateway)
↓
Private Subnet (EC2, ECS — outbound via NAT)
↓
Isolated Subnet (RDS, ElastiCache — no internet)
Most applications only need one thing in the public subnet: the load balancer. Everything else — application servers, databases, caches — should be in private or isolated subnets.
VPC Flow Logs
Enable VPC Flow Logs to capture all network traffic metadata for your VPC. This is essential for security investigation.
aws ec2 create-flow-logs \
--resource-type VPC \
--resource-ids vpc-0123456789abcdef0 \
--traffic-type ALL \
--log-destination-type cloud-watch-logs \
--log-group-name /aws/vpc/flow-logs \
--deliver-logs-permission-arn arn:aws:iam::123456789012:role/flowlogsRole
Without flow logs, when something suspicious happens you have no record of what network traffic occurred.
Pillar 3 — S3: Data Security
S3 misconfiguration is one of the most common causes of AWS data breaches. Public S3 buckets have exposed customer data, credentials, and intellectual property at companies of all sizes.
Block public access — account level
# Block all public access for the entire account
aws s3control put-public-access-block \
--account-id 123456789012 \
--public-access-block-configuration \
BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
This single command prevents any S3 bucket in your account from being made public — even if someone accidentally applies a public bucket policy. Run it on every AWS account you own.
S3 bucket policies: what to deny
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyNonHTTPS",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}
This denies any request that doesn't use HTTPS. No application should be reading S3 over unencrypted HTTP.
Enable default encryption
aws s3api put-bucket-encryption \
--bucket my-bucket \
--server-side-encryption-configuration '{
"Rules": [{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "aws:kms",
"KMSMasterKeyID": "arn:aws:kms:us-east-1:123456789012:key/your-key-id"
}
}]
}'
Enable S3 encryption by default for every bucket. Use KMS (not SSE-S3) for buckets containing sensitive data — KMS gives you audit logs of every decryption.
Pillar 4 — KMS: Encryption Key Management
AWS Key Management Service manages the encryption keys for your data at rest. When you enable encryption on RDS, S3, EBS, or DynamoDB, KMS is managing the key.
Customer managed keys vs AWS managed keys
AWS managed keys (aws/service): AWS creates and manages these. You cannot see or control the key policy. Fine for basic encryption.
Customer managed keys (CMKs): You create and control these. You can restrict who can use the key, enable automatic rotation, and see audit logs of every encryption and decryption operation.
# Create a customer managed key
aws kms create-key \
--description "Production database encryption key" \
--key-usage ENCRYPT_DECRYPT
# Enable automatic annual rotation
aws kms enable-key-rotation \
--key-id your-key-id
For sensitive data (PII, financial records, health information), use CMKs. The audit log alone — every encryption and decryption recorded in CloudTrail — is worth the small cost.
CloudTrail + KMS = who accessed what data
Every KMS decrypt operation is logged in CloudTrail with: who made the request, what key was used, when, and from what IP. This is the audit trail that compliance frameworks require and that incident responders use to determine the scope of a breach.
Pillar 5 — GuardDuty: Threat Detection
Amazon GuardDuty is AWS's managed threat detection service. It analyzes CloudTrail, VPC Flow Logs, and DNS logs to identify malicious activity — without you configuring any rules.
# Enable GuardDuty
aws guardduty create-detector \
--enable \
--finding-publishing-frequency SIX_HOURS
What GuardDuty detects:
- Unusual API calls from impossible geographic locations (credential compromise)
- EC2 instances communicating with known malicious IPs
- Cryptocurrency mining on your compute resources
- IAM access from Tor exit nodes
- S3 bucket reconnaissance from external accounts
- Port scanning from your EC2 instances
GuardDuty findings go to Security Hub, EventBridge, and SNS. Wire a finding to a Lambda function that auto-remediates or alerts your on-call channel.
# Create EventBridge rule: GuardDuty HIGH finding → SNS alert
aws events put-rule \
--name "guardduty-high-findings" \
--event-pattern '{
"source": ["aws.guardduty"],
"detail-type": ["GuardDuty Finding"],
"detail": {
"severity": [{"numeric": [">=", 7]}]
}
}' \
--state ENABLED
Cost: $4/month for a low-traffic account. This is mandatory. The detection value far exceeds the cost.
Pillar 6 — CloudTrail: Audit Logging
CloudTrail records every API call made in your AWS account — who called what API, when, from where, and with what result. It is the foundation of all AWS security investigation.
# Enable CloudTrail in all regions (mandatory for security)
aws cloudtrail create-trail \
--name "global-audit-trail" \
--s3-bucket-name my-cloudtrail-logs \
--is-multi-region-trail \
--enable-log-file-validation \
--include-global-service-events
aws cloudtrail start-logging --name global-audit-trail
--is-multi-region-trail — captures API calls in every region, including global services. Without this, an attacker operating in eu-west-1 while your trail only covers us-east-1 leaves no trace.
--enable-log-file-validation — CloudTrail signs log files so you can verify they haven't been tampered with.
The AWS Security Checklist
Immediate (do today)
- [ ] Enable MFA on root account
- [ ] Delete root account access keys if they exist
- [ ] Block public S3 access at account level
- [ ] Enable GuardDuty in every region
- [ ] Enable CloudTrail as a multi-region trail
This week
- [ ] Enable EBS default encryption per region
- [ ] Enable S3 default encryption on all buckets
- [ ] Run IAM Access Analyzer and review external findings
- [ ] Audit security groups for
0.0.0.0/0SSH/RDP rules - [ ] Enable VPC Flow Logs on all VPCs
This month
- [ ] Implement least-privilege IAM for all application roles
- [ ] Move all EC2 access to SSM Session Manager (eliminate SSH)
- [ ] Enable AWS Config for configuration compliance monitoring
- [ ] Set up GuardDuty findings → SNS/PagerDuty alerting
- [ ] Enable AWS Security Hub as unified findings dashboard
Frequently asked questions
What is the most common AWS security mistake?
Overly permissive IAM policies — either AdministratorAccess attached to application roles, or wildcard actions on specific services when only 2-3 actions are needed. The second most common is publicly accessible S3 buckets.
Is AWS secure by default?
AWS infrastructure is secure by default. Your configuration is not. S3 buckets are private by default but can be made public. Security groups deny all inbound by default but can be opened to 0.0.0.0/0. The defaults are secure — the common mistakes are configurations that override those defaults.
Do I need all six pillars for a small project?
At minimum: enable GuardDuty, block public S3 access, use IAM roles (not users) for application access, and enable MFA on root. These four controls prevent most common AWS security incidents regardless of project size.
How much does AWS security cost?
GuardDuty: ~$4/month for low traffic. CloudTrail: free for management events, ~$2/month per region for S3 storage. Security Hub: ~$0.001 per finding after the first 10,000. KMS: $1/key/month + $0.03 per 10,000 API calls. Total for a properly secured small account: under $20/month.
What is the AWS Well-Architected Framework security pillar?
AWS's security pillar covers six areas: identity and access management, detection, infrastructure protection, data protection, incident response, and application security. It maps directly to the six pillars in this guide. The full documentation is at docs.aws.amazon.com/wellarchitected.
Practice these controls hands-on
Reading about IAM policies and security groups is useful. Deploying them incorrectly in a real environment — seeing what breaks and why — builds the intuition that actually matters in production.
The Security Fortress path in Cloud Edventures covers every control in this guide hands-on: IAM least privilege lab, VPC security groups and NACLs, S3 bucket policy configuration, KMS key creation and rotation, GuardDuty enabling and findings, and CloudTrail audit trail setup — in isolated real AWS sandboxes with automated validation.
No AWS account needed. No billing risk.
👉 cloudedventures.com/labs/track/aws-cloud-foundations
Which AWS security control has caused you the most pain to configure? Drop a comment.
Top comments (0)