Cloud security is shared responsibility — the cloud provider secures the platform; you secure what you run on it. Most cloud security incidents come from customer mistakes, not cloud-provider failures. Misconfigured S3 buckets, exposed credentials, overly permissive IAM, missing encryption.
This page covers the foundations: IAM, encryption, network security, secrets, and the operational practices.
The provider secures:
You secure:
The boundary varies by service. Lambda: provider does more. EC2: customer does more. Understand the boundary for each service you use.
Most cloud security failures involve IAM mistakes. The principles:
Grant only permissions that are needed. Refuse "AdministratorAccess" unless genuinely required.
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/data/*"
}
Specific service, specific action, specific resource. Not s3:* and not *:*.
Workloads should authenticate via roles, not user credentials. EC2 has instance profiles; Lambda has execution roles; ECS has task roles. Code calling AWS gets temporary credentials from the role.
This is dramatically more secure than embedded user credentials.
Every human IAM user with console access should have MFA. The root user especially. The cost is minimal; the risk reduction is large.
Production, staging, dev, security tools, billing — separate accounts. Cross-account access via roles. Limits blast radius of compromise.
AWS Organizations lets you manage many accounts coherently.
All data at rest should be encrypted. Most managed services encrypt by default; some don't and need explicit configuration.
The choice between provider-managed keys and customer-managed (KMS) keys is real:
All data in transit should be encrypted with TLS 1.2+.
Most cloud services support this; some require explicit configuration. Check that your application is using TLS, not falling back to plaintext.
KMS (AWS) handles encryption keys at scale. CMKs (Customer Master Keys) encrypt data keys; data keys encrypt actual data.
Key practices:
Instance-level firewall. Default deny; allow specific traffic.
Inbound: TCP 443 from ALB security group only
Outbound: TCP 443 to anywhere
The reference-by-security-group pattern (ALB SG can talk to backend SG) is more secure than CIDR blocks for internal traffic.
Subnet-level firewall. Stateless. Used for broad rules; security groups for specific.
Limit what's in public subnets — only load balancers and bastion hosts. Application servers and databases in private subnets.
For private subnets that need outbound internet (downloads, API calls). Doesn't allow inbound; private resources stay private.
For accessing AWS services without going through the internet. S3 endpoint, DynamoDB endpoint, etc. Faster and more secure than route through internet.
Database passwords, API keys, encryption keys. Never committed to git.
Lambda environment variables, ECS task definitions. These are stored unencrypted in cloud control plane. Reference Secrets Manager / Parameter Store instead.
Application reads secrets at startup or on-demand. Secrets are rotated; service handles the mechanics.
Audit log of all API calls. Enable; ship to a separate account for tamper-resistance.
Network traffic logs. Useful for incident investigation.
Structured; centralized; not in CloudTrail.
Anomaly detection. Catches known-bad patterns (compromised credentials, crypto-mining, data exfiltration). Enable.
Tracks configuration changes. Useful for compliance and post-incident review.
The classic. Bucket made public for some reason; sensitive data exposed. Use:
Access keys in code or in public git repos. Bots scan GitHub continuously for AWS keys.
Use:
Too-broad policies because narrowing is hard. The fix:
0.0.0.0/0:22 (SSH from anywhere). Bots find these; brute-force or use leaked keys. Fix:
Vulnerable libraries, vulnerable AMIs, vulnerable base images. Scan continuously; patch promptly.