Most AWS breaches don't start with a zero-day. They start with a defaulted-open security group, an access key committed to a repo, or an IAM role that quietly accumulated * permissions over three years. Gartner's widely cited prediction — that through 2025 the overwhelming majority of cloud security failures would be the customer's fault, not the provider's — has aged into a truism. AWS gives you an enormous set of controls; the failure mode is almost always in how they're configured. This guide is organized around the four surfaces attackers actually target — identity, data, network, and the infrastructure-as-code that provisions all three — with concrete controls you can apply this week. Most of these are controls DevOps teams already own, which is exactly why solid aws devops security best practices need to live in the same pipeline that ships the infrastructure, not a separate audit checklist someone runs quarterly.
Start With the Shared Responsibility Model
AWS secures the cloud; you secure what you put in it. That line sounds obvious until you map it to a specific service. For S3, AWS guarantees the durability and physical security of the storage layer, but bucket policies, encryption settings, and public-access blocks are entirely yours. For EC2, AWS secures the hypervisor, but the OS patch level, the security group rules, and the instance metadata configuration are yours. Every control below lives on your side of that line, which is exactly why they get missed — there's no AWS default that fully protects you.
Lock Down Identity First
Identity is the new perimeter, and the root account is the crown jewel. Enable MFA on the root user, delete its access keys entirely, and never use it for day-to-day work. Everything else should route through IAM roles and short-lived credentials via AWS IAM Identity Center rather than long-lived access keys.
The single highest-leverage habit is scoping policies to explicit actions and resource ARNs instead of wildcards. Compare a lazy policy to a scoped one:
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::acme-reports/*"
}
That is safe. "Action": "s3:*" on "Resource": "*" is a lateral-movement invitation. Run IAM Access Analyzer's unused-access findings monthly to strip permissions that roles were granted but never exercised — in most accounts, roles use well under half the access they hold. For a deeper treatment of least-privilege patterns, see our guide to least-privilege IAM policy design.
Add organization-wide guardrails with Service Control Policies (SCPs) in AWS Organizations. An SCP that denies disabling CloudTrail or removing S3 public-access blocks stops a compromised account from covering its tracks, regardless of that account's IAM permissions.
Protect Data at Rest and in Transit
Since 2023, new S3 buckets block public access and apply default encryption automatically, but existing buckets and cross-account grants still leak. Enforce encryption and TLS-only access explicitly rather than trusting defaults. This Terraform enforces both:
resource "aws_s3_bucket_policy" "reports" {
bucket = aws_s3_bucket.reports.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Sid = "DenyInsecureTransport"
Effect = "Deny"
Principal = "*"
Action = "s3:*"
Resource = ["${aws_s3_bucket.reports.arn}", "${aws_s3_bucket.reports.arn}/*"]
Condition = { Bool = { "aws:SecureTransport" = "false" } }
}]
})
}
Use KMS customer-managed keys for anything sensitive so you control rotation and can revoke access by disabling the key. Turn on the account-level S3 Block Public Access setting so no future bucket can be made public by accident.
Harden the Network and Instance Metadata
Security groups should default to deny and open only the ports a workload actually needs. The classic mistake is 0.0.0.0/0 on port 22 or 3389 "temporarily." Use SSM Session Manager instead of open SSH, and you can close inbound management ports entirely.
Enforce IMDSv2 on every EC2 instance. The 2019 Capital One breach used a server-side request forgery flaw to reach the metadata endpoint and steal role credentials — IMDSv2's session-token requirement blocks that class of attack. Newer launches default to IMDSv2, but audit older instances:
aws ec2 describe-instances \
--query 'Reservations[].Instances[?MetadataOptions.HttpTokens==`optional`].InstanceId' \
--output text
Any instance returned is still accepting IMDSv1 and should be moved to required.
Catch Misconfigurations Before They Deploy
Turn on CloudTrail (all regions), AWS Config, and GuardDuty as a detection baseline. But detection is after the fact — the cheaper fix is catching misconfigurations in the pull request that introduces them. Scanning Terraform and CloudFormation in CI stops a public bucket or an open security group from ever reaching production. That shift-left approach pairs naturally with infrastructure-as-code scanning in the pipeline and pipeline-native tooling via the Safeguard CLI — putting aws devops security best practices directly in the hands of the engineers writing the Terraform, instead of leaving them as a separate security review step.
AWS Security Checklist
| Control | Setting | Priority |
|---|---|---|
| Root account | MFA on, access keys deleted | Critical |
| IAM policies | Explicit actions + resource ARNs, no * | Critical |
| S3 | Account-level Block Public Access, default + KMS encryption | Critical |
| EC2 | IMDSv2 required, no 0.0.0.0/0 on 22/3389 | High |
| Org guardrails | SCPs deny disabling CloudTrail / public-access blocks | High |
| Detection | CloudTrail all-region, Config, GuardDuty on | High |
| IaC | Terraform/CloudFormation scanned in CI | High |
How Safeguard Helps
Safeguard scans your Terraform and CloudFormation for exactly the misconfigurations above — public S3 buckets, wildcard IAM policies, open security groups, IMDSv1-enabled instances — at the moment the code enters a pull request, using Trivy's IaC engine orchestrated through the Safeguard IaC scanning product. Because it runs in your pipeline through the CLI, findings surface at commit time and tie back to the exact line of HCL that introduced them, so a developer fixes it before merge rather than a security team chasing it in production. Safeguard also generates a software bill of materials for the application code deploying onto that infrastructure through software composition analysis, and Griffin, its AI triage engine, prioritizes findings by real exploitability rather than raw CVSS. If you're weighing this build-time approach against an agentless cloud posture tool, our Safeguard vs Wiz comparison breaks down where each vantage point fits.
Cloud security in 2026 is a configuration discipline, not a product purchase. Start with identity, enforce encryption and least privilege everywhere, and move misconfiguration detection into the pipeline where it's cheapest to fix.
Ready to catch AWS misconfigurations before they ship? Create a free Safeguard account or read the Safeguard documentation to wire IaC scanning into your pipeline today.