Security in the cloud is a shared responsibility. AWS secures the physical infrastructure, network, and hypervisor — you are responsible for securing your data, applications, identity controls, and network configuration. Getting this right is not optional. Misconfigured S3 buckets, overly permissive IAM roles, and missing MFA have been responsible for some of the largest cloud data breaches in history. This guide covers the essential AWS security practices every team should implement.
1. Secure the Root Account Immediately
The AWS root account has unlimited power — it can close the account, change billing, and bypass any IAM policy. Protect it aggressively:
- Enable MFA on the root account (use a hardware MFA key like YubiKey, not just a phone app)
- Do not create root access keys. If they exist, delete them.
- Do not use the root account for daily operations — create IAM users for everything
- Store root credentials in a physical safe or secure password manager with emergency access procedures
2. Enforce MFA for All IAM Users
Enforce MFA using an IAM policy condition. Attach this to a group or as an AWS Organizations SCP:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyWithoutMFA",
"Effect": "Deny",
"NotAction": [
"iam:CreateVirtualMFADevice",
"iam:EnableMFADevice",
"iam:GetUser",
"iam:ListMFADevices",
"iam:ListVirtualMFADevices",
"sts:GetSessionToken"
],
"Resource": "*",
"Condition": {
"BoolIfExists": {"aws:MultiFactorAuthPresent": "false"}
}
}
]
}
3. Apply the Principle of Least Privilege
Every IAM user, role, and service should have only the permissions it needs — nothing more. Start by using AWS-managed policies during development, then tighten to custom policies before production. Use IAM Access Analyzer to identify unused permissions and refine policies:
# Enable IAM Access Analyzer
aws accessanalyzer create-analyzer
--analyzer-name my-account-analyzer
--type ACCOUNT
# Review generated findings
aws accessanalyzer list-findings --analyzer-name my-account-analyzer
4. Never Hardcode AWS Credentials in Code
Hardcoded access keys in source code are a critical vulnerability — especially if the code is pushed to a public GitHub repository. The right approach:
- Use IAM roles for EC2, Lambda, ECS, and EKS workloads — no hardcoded keys needed
- Use AWS Secrets Manager or SSM Parameter Store for application secrets
- Enable AWS Config rules to detect access keys older than 90 days
- Use git-secrets or truffleHog pre-commit hooks to prevent accidental commits
# Retrieve a secret from AWS Secrets Manager at runtime
aws secretsmanager get-secret-value
--secret-id prod/myapp/db-credentials
--query "SecretString" --output text
5. Enable AWS CloudTrail
CloudTrail records every API call made in your AWS account — who did what, when, and from where. This is foundational for security auditing and incident response:
# Create a trail that logs to an S3 bucket
aws cloudtrail create-trail
--name my-org-trail
--s3-bucket-name my-cloudtrail-logs
--include-global-service-events
--is-multi-region-trail
--enable-log-file-validation
# Start logging
aws cloudtrail start-logging --name my-org-trail
Enable CloudTrail Insights to automatically detect unusual API activity patterns that may indicate account compromise.
6. Enable Amazon GuardDuty
GuardDuty is a managed threat detection service that continuously analyzes CloudTrail events, VPC Flow Logs, and DNS logs to detect threats like compromised EC2 instances, unauthorized API calls, and crypto mining activity. Enable it with one click in the console — it requires no agents and has no performance impact:
# Enable GuardDuty
aws guardduty create-detector --enable --finding-publishing-frequency FIFTEEN_MINUTES
GuardDuty costs approximately $1–$4 per month for small accounts. The security value far exceeds the cost.
7. Encrypt Data at Rest and in Transit
At rest:
- S3: Enable default encryption with SSE-S3 or SSE-KMS on all buckets
- EBS: Encrypt EBS volumes by default at the account level
- RDS: Enable encryption at creation time (cannot be added later)
# Enable EBS encryption by default for the account
aws ec2 enable-ebs-encryption-by-default
# Enable S3 bucket default encryption
aws s3api put-bucket-encryption
--bucket my-bucket
--server-side-encryption-configuration '{
"Rules": [{"ApplyServerSideEncryptionByDefault": {"SSEAlgorithm": "AES256"}}]
}'
In transit: Enforce HTTPS for all web-facing resources. Use TLS/SSL certificates from AWS Certificate Manager (ACM) — they are free and auto-renew.
8. Block Public S3 Access at the Account Level
# Block all public S3 access for the entire account
aws s3control put-public-access-block
--account-id YOUR_ACCOUNT_ID
--public-access-block-configuration
"BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"
Only override this for specific buckets that legitimately need public access (e.g. a public static website bucket), and document why.
9. Use AWS Config for Compliance
AWS Config continuously records configuration changes and evaluates resources against compliance rules. Enable managed rules like iam-root-access-key-check, s3-bucket-public-read-prohibited, and encrypted-volumes to detect misconfigurations automatically.
10. Use AWS Organizations and SCPs
If you manage multiple AWS accounts (highly recommended for production), use AWS Organizations with Service Control Policies (SCPs) to enforce guardrails across all accounts — preventing anyone in a child account from disabling CloudTrail, creating public S3 buckets, or creating IAM users without MFA.
Summary
AWS security is not a checkbox — it is an ongoing practice. Start with the fundamentals: root account protection, MFA enforcement, least-privilege IAM, CloudTrail logging, and GuardDuty threat detection. These controls cost little but protect against the most common and damaging cloud security incidents.