AWS Security Best Practices Checklist (2026)

Most AWS breaches are not exotic. They come from a leaked access key with far too many permissions, an S3 bucket left public, or a CloudTrail nobody ever turned on. This is a checklist you can work through account by account, ordered so the highest-impact controls come first. If you only read one section, read "Start here."

Start here (the 20% that stops most incidents) #

Kill long-lived access keys. Static AKIA... keys are the number one cause of AWS compromise. Replace them with IAM roles, and for CI/CD use OIDC federation so pipelines assume a role with no stored secret.

Turn on CloudTrail and GuardDuty in every region. Without them you cannot see the attack, let alone respond.

Block public S3 at the account level. One command closes an entire class of data leaks.

Enforce MFA on every human, lock the root account away.

Everything below expands on these and fills in the rest.

Identity and access #

Identity is the real perimeter in AWS. Get this wrong and the network controls barely matter.

Least privilege by default. Start from deny, grant the specific actions a role needs, and use IAM Access Analyzer to generate policies from real CloudTrail activity instead of guessing.

No long-lived keys for humans or machines. Humans log in through IAM Identity Center (SSO) with short-lived credentials. Workloads use instance roles, task roles, or IRSA. Pipelines use GitHub or GitLab OIDC to assume a role.

MFA everywhere. Require it for console access and enforce it in policy conditions for sensitive actions.

Permission boundaries. Cap what a delegated admin or a self-service role can ever grant, so a mistake in a downstream policy cannot escalate.

Root account lockdown. Hardware MFA, no access keys, no daily use. Alert on any root sign-in.

A small guardrail: deny any action that is not backed by MFA.

json.json

{
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"BoolIfExists": { "aws:MultiFactorAuthPresent": "false" }
}
}

Network #

Treat the network as defense in depth, not the main gate.

Segment with VPCs and subnets. Keep databases and internal services in private subnets with no route to an internet gateway.

Security groups vs NACLs. Security groups are stateful and where most of your rules belong. NACLs are stateless, coarse, and useful as a subnet-wide backstop. Do not try to run everything through NACLs.

No 0.0.0.0/0 on sensitive ports. SSH (22), RDP (3389), and database ports should never be open to the world. Use Session Manager instead of public SSH so you can drop port 22 entirely.

VPC endpoints. Reach S3, DynamoDB, and other services privately so traffic never traverses the public internet.

WAF and Shield. Put AWS WAF in front of public ALBs, CloudFront, and API Gateway. Shield Standard is automatic; consider Shield Advanced for high-value targets.

Data #

Encrypt at rest with KMS. Enable default encryption on S3, EBS, RDS, and snapshots. Use customer-managed keys where you need key rotation and access separation.

Encrypt in transit with TLS. Terminate TLS at the load balancer and enforce HTTPS-only with a bucket or endpoint policy.

S3 Block Public Access. Set it at the account level so no future bucket can be made public by accident:

bash.bash

aws s3control put-public-access-block \
--account-id 123456789012 \
--public-access-block-configuration \
BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true

Tight bucket policies. Grant access by role, not by ACL. ACLs should be disabled (bucket owner enforced).

Secrets in Secrets Manager or SSM Parameter Store, never in environment variables or code. Rotate them, and reference them at runtime.

Backups you have actually restored. Enable versioning, cross-account or cross-region copies for critical data, and test recovery on a schedule.

Detection and logging #

You cannot respond to what you cannot see.

CloudTrail across all regions, delivered to a locked-down, separate logging account with a bucket that has object lock and MFA delete.

GuardDuty for continuous threat detection on API activity, DNS, and network flows.

Security Hub to aggregate findings and score yourself against the AWS Foundational Security Best Practices standard.

AWS Config rules to catch drift: public buckets, unencrypted volumes, wide-open security groups, keys older than 90 days.

Centralized logs and real alerting. Ship CloudWatch and VPC flow logs to one place, and route high-severity findings to a channel a human watches, not an inbox nobody reads.

Workload #

Patch management. Use Systems Manager Patch Manager for EC2. For containers, rebuild from patched base images rather than patching running containers.

Least-privilege task roles. Each Lambda function, ECS task, and EKS pod gets its own narrowly scoped role. Avoid the node instance role shortcut on EKS; use IRSA or Pod Identity so a compromised pod cannot borrow node permissions.

Image scanning in ECR. Turn on enhanced scanning and fail the pipeline on critical findings. This pairs with your broader container vulnerability scanning and dependency and SCA scanning so vulnerable code and libraries never reach production.

Governance #

Controls that hold across dozens of accounts, not just one.

AWS Organizations with SCPs. Use service control policies to deny entire risk classes org-wide: disabling CloudTrail, leaving a home region, creating IAM users, or making buckets public.

Guardrails through Control Tower. Preventive and detective controls applied to every new account by default.

Mandatory tagging. Owner, environment, and data classification on every resource, enforced by policy. You cannot secure what you cannot attribute.

Cost anomalies as a security signal. A sudden spike in EC2 or outbound data transfer is often the first visible sign of cryptomining or exfiltration. Wire cost anomaly alerts into your security review.

The call we'd make #

If you are staring at an account and do not know where to begin, do these five in order: rotate out every static access key, enable CloudTrail and GuardDuty in all regions, apply account-level S3 Block Public Access, enforce MFA and lock the root account, then bring the account under an Organization with a handful of SCPs. That sequence removes the paths attackers use most, and it buys you the visibility to work through the rest of this list calmly.

Cloud security and application security are the same discipline seen from two sides. Once the AWS platform is locked down, the code running on it becomes the next target, so pair this with your application security best practices and keep both moving together.