AWS Security Hardening
| Scope | Account-level, network-level, and workload-level hardening |
| Applies to | The WAF + ELB + Auto Scaling reference architecture in this section |
| Skills | IAM, VPC, KMS, GuardDuty, Security Hub, CloudTrail, WAF, Config |
The principle: hardening isn't a checklist you run once — it's layered controls where each
layer assumes the one in front of it will eventually fail. This page walks the layers from the account
boundary inward to the running workload, using the services documented elsewhere in this section.
1 — Account & identity foundation
Root account & IAM
- Root account: MFA enforced, access keys deleted, used for nothing operational.
- Human access via IAM Identity Center (SSO) federated to the corporate directory — no long-lived IAM users for people.
- Workloads use IAM roles, never embedded keys. Least privilege by default; permissions added on evidence, not anticipation.
# Find IAM users with active access keys (should be near-zero for humans)
aws iam list-users --query 'Users[].UserName' --output text \
| tr '\t' '\n' \
| while read u; do
aws iam list-access-keys --user-name "$u" \
--query 'AccessKeyMetadata[?Status==`Active`].AccessKeyId' --output text \
| grep -q . && echo "ACTIVE KEY: $u"
done
# Confirm root has no access keys
aws iam get-account-summary --query 'SummaryMap.AccountAccessKeysPresent'
Guardrails at the org level: Service Control Policies (SCPs) enforce boundaries no account can
escape — denying region use outside approved ones, blocking the disabling of CloudTrail or GuardDuty,
preventing public S3 where it's never allowed. See 01 · Landing Zone.
2 — Detective controls (always-on visibility)
| CloudTrail | Org-wide trail, log file validation on, delivered to a locked S3 bucket in a separate account. |
| GuardDuty | Enabled in every region — threat detection on VPC flow logs, DNS, and CloudTrail. |
| Security Hub | Aggregates findings and scores against CIS / AWS Foundational standards. |
| AWS Config | Records resource state and flags drift from compliance rules. |
# Verify the security services are actually on (a finding if any are off)
aws guardduty list-detectors --query 'DetectorIds' --output text
aws securityhub get-enabled-standards --query 'StandardsSubscriptions[].StandardsArn'
aws cloudtrail describe-trails --query 'trailList[].{Name:Name,Multi:IsMultiRegionTrail,Validation:LogFileValidationEnabled}'
aws configservice describe-configuration-recorders --query 'ConfigurationRecorders[].recordingGroup.allSupported'
3 — Network hardening
- Public exposure limited to the ALB. The app tier and database live in private subnets with no route to an Internet Gateway.
- Security groups reference each other by ID, not CIDR — the ALB's SG is the only source allowed into the app tier's 443; the app tier's SG is the only source allowed into the DB's 3306.
- No
0.0.0.0/0on SSH/RDP anywhere. Administrative access is via Systems Manager Session Manager — no bastion, no open management ports, full session logging.
# Hunt for the classic finding: management ports open to the world
aws ec2 describe-security-groups \
--query "SecurityGroups[?IpPermissions[?ToPort==\`22\` && contains(IpRanges[].CidrIp, '0.0.0.0/0')]].GroupId"
# Connect to an instance with NO open SSH port, fully logged
aws ssm start-session --target i-0abc123def456
Why Session Manager over a bastion: it removes an entire class of exposure — no inbound port,
no SSH keys to manage or leak, no bastion host to patch, and every session is logged to CloudTrail/S3.
The most secure open port is the one that doesn't exist. See 20 · Systems Manager.
4 — Data protection
- Encryption at rest everywhere: EBS volumes, RDS/MariaDB, and S3 with KMS — customer-managed keys where key-policy control or rotation auditing matters.
- Encryption in transit: TLS terminated at the ALB with an ACM certificate; DB connections encrypted.
- S3: Block Public Access on at the account level, bucket policies deny non-TLS requests, versioning + lifecycle for durability and cost.
- Secrets in Secrets Manager with rotation — never in AMIs, user data, or environment files baked into images.
# Account-wide S3 public access block (the single highest-value S3 control)
aws s3control get-public-access-block --account-id 123456789012
# Find unencrypted EBS volumes
aws ec2 describe-volumes --query 'Volumes[?Encrypted==`false`].VolumeId'
# Enforce encryption-by-default for new EBS volumes
aws ec2 enable-ebs-encryption-by-default
5 — Application edge (WAF)
The WAF in front of the ALB runs AWS managed rule groups (Core Rule Set, SQLi, known-bad-inputs, bad-bot). False positives are handled by scoping an override with labels — never by disabling a whole rule group. New rules go in Count mode first, validated against real traffic, then promoted to Block. This is the same discipline covered in depth in the portfolio's WAF material and my Security Engineering work.
6 — Continuous verification
Hardening decays — new resources appear, someone opens a port "temporarily." The controls that keep it honest:
- AWS Config rules flag drift the moment a non-compliant resource is created.
- Security Hub gives a running compliance score against CIS benchmarks.
- GuardDuty surfaces active threats, routed through EventBridge → SNS to the right team.
- External scanning (Nuclei, QualysGuard) probes from the outside to confirm exposure matches intent.
War story tie-in: this mirrors the centralized multi-account security monitoring I built —
org-wide CloudTrail, CloudWatch metric filters, EventBridge, SNS alerting and GuardDuty feeding a single
operational view. Hardening you can't observe is hardening you can't trust.
Hardening checklist (quick reference)
| Layer | Control | Verified by |
|---|---|---|
| Identity | Root MFA, no root keys, SSO for humans, roles for workloads | IAM credential report |
| Org | SCP guardrails, region restrictions | Organizations policy review |
| Detection | CloudTrail + GuardDuty + Security Hub + Config all on | CLI checks above |
| Network | Private subnets, SG-to-SG rules, no 0.0.0.0/0 mgmt | SG audit + Config rule |
| Access | Session Manager, no bastion, no open SSH | SG audit |
| Data | KMS at rest, TLS in transit, S3 public access block | Config rules |
| Edge | WAF managed rules, Count-then-Block, scoped overrides | WAF logs |
| Verification | Config drift, Security Hub score, external scans | Continuous |