AWS Security Best Practices 2026 — A Practical Guide
AWS publishes a security pillar in the Well-Architected Framework. CIS publishes benchmarks. Blog posts recycle the same advice from 2019. Here's what actually matters in 2026, written by security engineers, not compliance consultants.
This isn't a checklist. It's a prioritized guide — the things that prevent breaches, not the things that pass audits.
The Foundation: Account Structure
Use AWS Organizations. Always.
If you're running more than one workload on AWS and not using Organizations, stop reading this and go set it up. Everything else depends on it.
Organizations gives you:
- Service Control Policies (SCPs) — hard limits on what any account can do, regardless of IAM
- Consolidated billing — financial visibility
- Account-level isolation — a compromised dev account can't touch prod
Minimum Account Structure
``` Management Account (billing + SCPs only) ├── Security Account (CloudTrail, GuardDuty, Security Hub) ├── Log Archive Account (centralized logging, immutable) ├── Shared Services (CI/CD, artifact repos) ├── Production ├── Staging └── Development ```
Don't run workloads in the management account. Don't put production and development in the same account. These aren't suggestions — they're the minimum for any team that cares about blast radius.
Service Control Policies
SCPs are the most powerful and underused security feature in AWS. They override everything — even root. Use them to:
```json { "Version": "2012-10-17", "Statement": [ { "Sid": "DenyRegionsOutsideUS", "Effect": "Deny", "Action": "", "Resource": "", "Condition": { "StringNotEquals": { "aws:RequestedRegion": ["us-east-1", "us-west-2"] } } } ] } ```
Common SCPs to implement immediately:
- Restrict allowed regions (deny all regions you don't use)
- Prevent disabling CloudTrail
- Prevent disabling GuardDuty
- Prevent leaving the Organization
- Deny access to unused services
- Require IMDSv2 for EC2
IAM: The Most Important Section
IAM misconfigurations are the #1 cause of AWS breaches. Not misconfigured S3 buckets. Not open security groups. IAM.
Stop Using Long-Lived Credentials
In 2026, there is no excuse for IAM access keys in production. Zero.
- Human access: Use IAM Identity Center (SSO) with your identity provider. Short-lived session credentials.
- Application access: Use IAM roles. EC2 instance profiles, ECS task roles, Lambda execution roles. If you're on EKS, use IRSA (IAM Roles for Service Accounts) or Pod Identity.
- CI/CD: Use OIDC federation. GitHub Actions, GitLab CI, and every major CI platform support assuming an IAM role via OIDC without storing credentials.
- Cross-account: Use `sts:AssumeRole`. Never share credentials between accounts.
If you have access keys older than 90 days, rotate them. If you have access keys that can be replaced with a role, delete them.
Least Privilege, For Real
"Follow least privilege" is advice everyone gives and nobody follows. Here's how to actually do it:
- Start with zero permissions. Every new role starts with no policies.
- Use AWS Access Analyzer. It analyzes CloudTrail logs and generates least-privilege policies based on actual usage. After 30 days of running a workload, generate a policy from its actual API calls.
- Use permission boundaries. Set a maximum permission ceiling for roles created by developers. They can grant permissions up to the boundary, but not beyond.
- Review regularly. Use IAM Access Analyzer's unused access findings. If a role hasn't used a permission in 90 days, remove it.
```bash
Generate a least-privilege policy from CloudTrail
aws accessanalyzer generate-policy
--policy-generation-details '{"principalArn": "arn:aws:iam::123456789012:role/my-app-role"}'
--cloud-trail-details '{"trails": [{"cloudTrailArn": "arn:aws:cloudtrail:us-east-1:123456789012:trail/main"}], "startTime": "2025-12-01T00:00:00Z", "endTime": "2026-01-31T00:00:00Z"}'
```
MFA Everywhere
MFA on root accounts. MFA on human IAM users (if you still have them — use SSO instead). MFA for `sts:AssumeRole` on sensitive roles.
Use hardware security keys (FIDO2/WebAuthn) for root accounts and break-glass access. Not SMS. Not TOTP apps. Hardware keys.
The IAM Policies to Audit First
If you're inheriting an AWS account and need to know where the IAM risk is, check these first:
- Policies with `"Effect": "Allow", "Action": "", "Resource": ""` — This is full admin. How many principals have it?
- Roles assumable by `*` or `0.0.0.0/0` — confused deputy attacks
- Users with console access but no MFA — credential stuffing target
- Access keys not rotated in >180 days — long-lived credentials
- Unused roles and users — attack surface you don't need
Or just run a scanner:
```bash pip install stratusec stratusec scan --provider aws --service iam ```
S3: Still Getting People Breached
S3 bucket misconfigurations peaked around 2017-2019, but they still happen. AWS has added multiple layers of protection. Use them.
Block Public Access (Account-Level)
```bash
aws s3control put-public-access-block
--account-id 123456789012
--public-access-block-configuration
BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
```
Do this at the account level. Not per bucket. Account-level public access block prevents anyone from accidentally making a bucket public, regardless of individual bucket policies.
Encryption
- SSE-S3: Default since 2023. All new buckets are encrypted by default.
- SSE-KMS: Use this if you need key management, key rotation, or access controls on the encryption key itself.
- SSE-KMS with bucket keys: Reduces KMS API costs by 99% for high-throughput buckets.
Versioning + Object Lock
For critical data (logs, backups, compliance data):
- Enable versioning — protects against accidental deletion
- Enable Object Lock (Governance or Compliance mode) — prevents even root from deleting objects for a retention period. Essential for log integrity.
Access Logging
Enable S3 server access logging or (better) use CloudTrail data events for S3. Know who accessed what and when.
Networking: The Basics People Skip
Security Groups
- Default deny. Security groups are stateful and deny all inbound by default. Don't add rules you don't need.
- No 0.0.0.0/0 ingress. Ever. Not on port 22, not on port 3389, not on any port. Use Systems Manager Session Manager, EC2 Instance Connect, or a bastion with strict source IP restrictions.
- Use security group references. Instead of CIDR ranges, reference other security groups. `sg-web` allows traffic from `sg-alb`. This way, if instances change IPs, access rules still work.
VPC Design
- Private subnets for everything that doesn't need a public IP. Databases, application servers, internal services — all in private subnets with NAT Gateway for outbound access.
- VPC endpoints for AWS services (S3, DynamoDB, SQS, Secrets Manager). Keeps traffic off the public internet.
- VPC Flow Logs enabled. Send to CloudWatch Logs or S3. You need these for incident investigation.
DNS and Certificates
- Use Route 53 with DNSSEC enabled.
- Use ACM for TLS certificates. Free, auto-renewing. No excuse for expired certs.
- Enforce TLS 1.2+ on all load balancers and CloudFront distributions.
Logging and Monitoring: Non-Negotiable
CloudTrail
CloudTrail must be:
- Enabled in all regions (not just regions you use)
- Sending to a log archive account you can't tamper with
- Configured with log file validation enabled
- Retained for at least 1 year (CIS requires 90 days; a year is better)
Also enable data events for S3 and Lambda. Management events are free; data events cost money but are essential for forensics.
GuardDuty
Enable GuardDuty in every region, every account. It's the best signal-to-noise ratio of any AWS threat detection service.
In 2026, GuardDuty covers:
- CloudTrail anomalies (unusual API calls, credential usage)
- VPC Flow Log analysis (port scanning, crypto mining)
- DNS anomalies (C2 communication)
- EKS audit log analysis
- S3 protection
- Malware scanning
- Runtime monitoring for EC2 and containers
The findings are good. The false positive rate is low. Turn it on.
Config
AWS Config records configuration changes to resources. Enable it. Use conformance packs for automated compliance checking. Send findings to Security Hub.
Security Hub
Security Hub aggregates findings from GuardDuty, Config, Inspector, and third-party tools. It runs its own CIS benchmark checks. It's the single pane of glass for AWS security findings.
Import Stratusec findings into Security Hub using ASFF format:
```bash
stratusec scan --provider aws --output asff |
aws securityhub batch-import-findings --findings file:///dev/stdin
```
Compute: EC2, ECS, EKS, Lambda
EC2
- IMDSv2 required. The instance metadata service v1 is exploitable via SSRF. Require IMDSv2 at the account level via SCP.
- No public IPs unless explicitly needed (and then, behind a load balancer).
- Inspector for vulnerability scanning. It's automatic now — enable it and it scans EC2 instances and Lambda functions.
- Systems Manager for patch management. Don't SSH into instances to patch them.
ECS
- Fargate when possible — no instance management.
- Task roles for each service — no shared credentials.
- ECR image scanning enabled. Block deployments of images with critical CVEs.
- Runtime monitoring via GuardDuty ECS Runtime Monitoring.
EKS
Kubernetes security is its own discipline. The abbreviated version:
- Pod Security Standards — enforce at the namespace level. No privileged containers in production.
- IRSA or Pod Identity — no node-level IAM roles shared across pods.
- Network Policies — default deny between namespaces. Use Calico or Cilium.
- OPA/Gatekeeper — admission control for Kubernetes resources. (Stratusec guardrails integrate here.)
- Control plane logging to CloudWatch — API server, authenticator, controller manager, scheduler.
- Private endpoint — don't expose the API server to the internet.
Lambda
- Least privilege execution roles. Don't give Lambda functions broad access because "it's just a function."
- Environment variable encryption. Use KMS for sensitive values. Or better, use Secrets Manager with automatic rotation.
- VPC placement when functions need to access internal resources. Use VPC endpoints for AWS service calls.
- Code signing for production functions. Prevent unauthorized code deployment.
Encryption
At Rest
- EBS: Encrypted by default (enable the account-level default).
- RDS: Encrypted. Enable at creation — you can't encrypt an existing unencrypted RDS instance without a snapshot/restore.
- S3: Encrypted by default (SSE-S3). Use SSE-KMS for compliance requirements.
- Secrets Manager: For credentials, API keys, database passwords. With automatic rotation.
In Transit
- TLS 1.2+ on all endpoints. Use ALB/NLB/CloudFront security policies that enforce it.
- VPC endpoints keep AWS API traffic internal.
- Private connectivity (PrivateLink, VPC peering, Transit Gateway) for service-to-service communication.
Key Management
- Use KMS for key management. Customer-managed keys (CMKs) for anything that needs key rotation control or cross-account access.
- Enable automatic key rotation (annual) for symmetric CMKs.
- Key policies should restrict who can use vs. who can administer keys.
Automated Scanning: Don't Do This Manually
You cannot manually check all of this across multiple accounts, multiple regions, and hundreds of resources. Automate it.
Option 1: Stratusec (Open Source)
```bash pip install stratusec stratusec init --provider aws stratusec scan --framework cis-aws-3.0 ```
Covers everything in this blog post and more. 500+ checks. Attack path analysis shows you how misconfigurations chain together. Guardrails prevent them from deploying again.
Option 2: AWS-Native
AWS Security Hub + Config Conformance Packs + GuardDuty + Inspector. Covers a lot, but you're managing four different services with four different finding formats.
Option 3: Open Source Scanners
Traditional open source compliance scanners cover CIS benchmarks well. Less depth on attack paths and remediation.
The Best Approach
Use all three layers:
- Preventive: Stratusec guardrails in CI/CD + SCPs in AWS Organizations
- Detective: Stratusec scanning + GuardDuty + Security Hub
- Responsive: Stratusec auto-remediation + incident response playbooks
Quick Wins: Do These Today
If you got this far and want to take action immediately, here are the 10 highest-impact changes ranked by effort vs. impact:
- Enable MFA on all root accounts (5 min per account, prevents account takeover)
- Enable GuardDuty in all regions (10 min, free 30-day trial)
- Block public S3 access at account level (2 min per account)
- Require IMDSv2 via SCP (15 min)
- Run a scan: `pip install stratusec && stratusec scan` (5 min)
- Enable CloudTrail in all regions with log file validation (15 min)
- Delete unused IAM access keys (30 min)
- Enable default EBS encryption (2 min per account)
- Review security groups for 0.0.0.0/0 ingress (15 min)
- Enable Security Hub with CIS benchmark (10 min)
These 10 actions take about 2 hours total and address the majority of AWS breach patterns.