☰ All modules Tier 3 · EC2 (instances, storage, ELB, Auto Scaling) GuideCheat sheet ‹ s3rds ›
Contents
  1. IAM roles, instance profiles and the credential chain
  2. IMDSv2
  3. User data and bootstrapping
  4. Security groups and connectivity
  5. Purchasing options and Spot
  6. EBS volumes, snapshots, encryption and AMIs
  7. Storage choice: instance store vs EBS vs EFS
  8. Elastic Load Balancing: ALB, NLB, GWLB
  9. Sticky sessions, TLS and SNI
  10. Auto Scaling
  11. CloudWatch for EC2
  12. Numbers to know
  13. Decision rules
  14. Memory hooks

EC2 — Cheat Sheet (DVA-C02)

Verified against AWS documentation on 2026-10-12 · ⚠️ = changed vs older material: learn the value shown here (older practice material may say otherwise; full list in notes/current-facts.md) · explanations and examples: notes/ec2-mastery-guide.md.

IAM roles, instance profiles and the credential chain

Topic Current facts Memory hook
Instance profile Wraps exactly 1 role (hard limit); 1 profile per instance; IAM console auto-creates a same-name profile; CLI/API: create-instance-profile + add-role-to-instance-profile; launch with the profile name/ARN Profile = envelope, role = letter
Trust policy "Principal": {"Service": "ec2.amazonaws.com"}, "Action": "sts:AssumeRole"; wrong trust → AssumeRoleUnauthorizedAccess in IMDS EC2 must be trusted to wear the role
Attach / swap live associate-iam-instance-profile (running or stopped, none attached); replace-iam-instance-profile-association (running, needs iip-assoc-… ID); no reboot Replace the envelope, not the letter
Role swapped inside profile Up to 1 h before the instance sees it → avoid on live instances
Credentials IMDS /latest/meta-data/iam/security-credentials/<role>; temporary ASIA… key + token; new set ≥ 5 min before expiry; SDKs auto-refresh; ignores role MaxSessionDuration Keys rotate themselves
Who am I? aws sts get-caller-identity (no permission needed, even with explicit deny) → assumed-role/<role>/<instance-id> Always allowed, run it first
Decode errors aws sts decode-authorization-message --encoded-message … needs sts:DecodeAuthorizationMessage
Launch with a role ec2:RunInstances (+ Associate/ReplaceIamInstanceProfileAssociation) + iam:PassRole on the role ARN; console + iam:ListInstanceProfiles; no PassRole → UnauthorizedOperation (decode the message); empty profile → launch fails too (AccessDenied in the IAM docs) No pass, no launch
Consistency IAM is eventually consistent; keep IAM changes out of hot paths
Credentials outside AWS ⚠️ Temporary credentials: aws login (AWS CLI 2.32.0+, 15-minute credentials refreshed for up to 12 h), IAM Identity Center (aws configure sso), IAM Roles Anywhere for servers; long-term keys only where roles are impossible Borrow credentials, don't own them
Tier AWS CLI v2 (⚠️ 10 sources, first match wins) SDK for Java 2.x ⚠️ Memory hook
Explicit 1 command-line options (--profile, --region) Java system properties aws.accessKeyId / aws.secretAccessKey / aws.sessionToken Closest to the code wins
Environment 2 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN Same env vars Env beats files
Federated profiles 3 assume-role profile → 4 web identity → 5 IAM Identity Center Web identity token (AWS_WEB_IDENTITY_TOKEN_FILE + AWS_ROLE_ARN)
Files 6 ~/.aws/credentials → 7 credential_process → 8 ~/.aws/config Shared credentials/config files
Container 9 ECS task role (169.254.170.2) ECS container credentials Task before host (still block IMDS for tasks)
Instance 10 EC2 instance profile via IMDS EC2 instance profile Instance role = last resort

IMDSv2

Item Current value Memory hook
Endpoint 169.254.169.254; IPv6 [fd00:ec2::254] (Nitro + IPv6 subnet, opt-in); free Link-local = inside the instance only
Get token PUT /latest/api/token + X-aws-ec2-metadata-token-ttl-seconds: 1–21600 (max 6 h) PUT to get…
Use token GET + X-aws-ec2-metadata-token: <token>; token bound to the instance …GET to use
HttpTokens optional (v1 + v2) / required (v2 only); ⚠️ required by default with AL2023 AMIs and console Quick Start launches; nothing set at launch, account or AMI level → optional (no instance-type default in current docs) Check MetadataOptions, don't assume
Hop limit HttpPutResponseHopLimit 1–64; default 1; ⚠️ 2 with ImdsSupport v2.0 AMIs (AL2023); use 2 on container hosts 1 = host only, 2 = containers
Status codes 401 missing/expired token (v2 required) · 403 IMDS off / not allowed · 400 bad PUT · 404 no item · 503 retry 401 = token, 403 = turned off
Refused PUT with X-Forwarded-For; tokens from another instance Anti-SSRF / anti-proxy
Metrics (AWS/EC2) MetadataNoToken = v1 calls while optional; MetadataNoTokenRejected = v1 calls after required NoToken before, Rejected after
Throttling IMDS queries throttled per instance; link-local traffic capped at 1,024 packets/s per network interface; cache credentials, back off
SDK minimums CLI 1.16.289 · boto3 1.12.6 · Java 2.x 2.10.21 · JS v2 2.722.0; v1 fallback off with AWS_EC2_METADATA_V1_DISABLED=true
Where to require v2 How Note
Running instance modify-instance-metadata-options --http-tokens required --http-endpoint enabled Immediate, no restart; check MetadataNoToken = 0 first
New instance / ASG run-instances --metadata-options "HttpTokens=required,…" or launch template MetadataOptions Existing ASG instances unchanged → instance refresh
AMI register-image / modify-image-attribute --imds-support v2.0 Irreversible; sets hop limit 2
Account default, per Region modify-instance-metadata-defaults --http-tokens required (⚠️ March 2024) New launches only; an explicit launch value still wins
Account enforcement, per Region modify-instance-metadata-defaults --http-tokens-enforced enabled (⚠️ February 2026) Launch fails unless launch, account or AMI resolves required; --http-tokens optional on an instance → UnsupportedOperation; instances already allowing v1 untouched; restrict ec2:ModifyInstanceMetadataDefaults
Organization Declarative policy for IMDS defaults Accounts can't change it locally
IAM / SCP ec2:MetadataHttpTokens, ec2:MetadataHttpPutResponseHopLimit, ec2:MetadataHttpEndpoint on RunInstances / ModifyInstanceMetadataOptions (scope denies to instance/*); deny ec2:RoleDelivery NumericLessThan 2.0 RoleDelivery = kill v1-fetched creds

User data and bootstrapping

Fact Current value Memory hook
When / as whom First boot of each instance only, as root; cloud-init (Linux), EC2Launch v2 (Windows) Once, as root
Formats #!/bin/bash script, #cloud-config YAML, MIME multipart (both), #cloud-boothook (every boot, earliest) #! = script, #cloud-config = directives
Run every boot Script in /var/lib/cloud/scripts/per-boot/ or scripts-user module frequency always (cloud_final_modules: [[scripts-user, always]]); Windows <persist>true</persist> / frequency: always Per-boot is opt-in
Size 16 KB raw (before base64); encoded = ceil(n/3) × 4 16 raw
Who base64-encodes You don't: console, CLI run-instances, boto3 run_instances. You do: raw API, modify-instance-attribute, launch template UserData, CloudFormation Fn::Base64 Double-encoding breaks it
Logs /var/log/cloud-init-output.log (your script), /var/log/cloud-init.log; cloud-init status --long; aws ec2 get-console-output; Windows C:\ProgramData\Amazon\EC2Launch\log\agent.log output.log = your stdout
Modify Stop (EBS root) → modify-instance-attribute (base64) → start; the new script does not run by itself Stop, swap, start, no rerun
Read IMDS /latest/user-data (decoded), describe-instance-attribute (base64) Readable by anyone on the box → no secrets
Secrets Secrets Manager GetSecretValue / Parameter Store SecureString via instance role (+ kms:Decrypt only when a customer managed key is used; the AWS managed key aws/secretsmanager already allows use through Secrets Manager in its key policy) Fetch, don't embed
AMI User data not copied into AMIs; cloud-init copy in /var/lib/cloud/instances/<id>/ is → clean up first
AL2023 cloud-init ⚠️ No launch-time security updates by default; an unreachable remote include fails cloud-init (fail closed); package manager DNF (dnf install -y) AL2023 fails closed
Approach Best for Trade-off
User data script Light, per-launch config; fetching config/secrets Adds boot time; versions drift from a changing AMI (latest-AMI SSM parameter), --releasever=latest or unpinned pip/npm/third-party sources (⚠️ AL2023 locks dnf repo installs to the AMI's release)
Golden AMI (EC2 Image Builder) Fast Auto Scaling scale-out, identical builds Rebuild pipeline for patches; Image Builder free (pay for resources used)
SSM Run Command / State Manager Post-launch changes, drift correction, no SSH SSM Agent + AmazonSSMManagedInstanceCore (or Default Host Management, IMDSv2 only)
cfn-init + cfn-signal + CreationPolicy Stack waits until the app is ready; rollback on failure Count 1 / Timeout PT5M by default, max 12 h

Security groups and connectivity

Aspect Security group Network ACL (awareness)
Attached to ENI (instance, ALB, RDS, Lambda in VPC, endpoints) Subnet (one NACL per subnet)
State Stateful: replies allowed automatically Stateless: allow return traffic on ephemeral ports 1024–65535
Rules Allow only; source = CIDR, prefix list or SG ID Allow and deny; numbered 1–32766, lowest first, first match wins
Defaults New SG: no inbound, all outbound; VPC default SG: inbound from itself Default NACL: allow all; new custom NACL: deny all
Several attached Rules unioned (5 SGs per ENI, max 16) Only one per subnet
Change effect Immediate, no restart (tracked connections drain naturally) Immediate, cuts existing flows
Quotas 60 inbound + 60 outbound rules per SG; 2,500 SGs per Region 20 rules per direction (max 40)
Scope Region; ⚠️ can be associated with other VPCs in the same Region and shared within an AWS Organization VPC
Port Service Memory hook
21 FTP Turned 21 and still talks in plain text
22 SSH, SFTP, EC2 Instance Connect SSH has two S's → 22
80 / 443 HTTP / HTTPS (443 also for SSM Agent and AWS APIs) 80 = postcard, 443 = sealed envelope
3389 RDP (Windows) 3389 = desktop; 3306 = data
3306 MySQL, MariaDB, Aurora MySQL The "My" first database port
5432 PostgreSQL, Aurora PostgreSQL Countdown 5-4-3-2 → Postgres
1433 / 1521 SQL Server / Oracle Alphabetical: Microsoft (14) before Oracle (15)
6379 / 11211 Redis OSS–Valkey / Memcached (ElastiCache) 6379 spells MERZ on a phone keypad; Memcached is all 1s and 2s
2049 NFS (Amazon EFS) A file system from the year 2049
You see / you need It means / use Check or configure Memory hook
Timeout, request hangs Network path dropped it SG inbound rule, NACL, route to IGW/NAT, public IP Timeout = Tunnel blocked
Connection refused (instant) Host reached, nothing listening Process up? Right port? Bound to 0.0.0.0? Refused = Reached, nobody home
Permission denied (publickey) SSH auth, not network Username (ec2-user/ubuntu), key, chmod 400 Lock works, wrong key
HTTP 403 from site/ALB HTTP layer refused (app, AWS WAF, S3 policy) App auth, WAF rule, resource policy Front desk said no
AccessDenied / UnauthorizedOperation (403) IAM denied the API call sts get-caller-identity, sts decode-authorization-message Denied = Doorman (IAM)
Unable to locate credentials Empty credential chain Instance profile? IMDS enabled? Container hop limit No badge at all
Connect timeout on endpoint URL (hangs) Packets to the AWS API dropped NAT gateway or VPC endpoint? SG/NACL egress 443? Endpoint SG inbound 443? Private DNS on the endpoint? Road to AWS missing
Could not connect to the endpoint URL (fast) Name resolution or connection setup failed Region or --endpoint-url spelling, VPC DNS settings, local endpoint (DynamoDB Local) running? Wrong address on the envelope
Shell, no inbound ports, audited Session Manager SSM Agent + AmazonSSMManagedInstanceCore (or Default Host Management Configuration) + outbound 443 to ssm/ssmmessages/ec2messages (NAT or VPC endpoints); CloudTrail + S3/CW Logs Agent dials out
Browser SSH with IAM control EC2 Instance Connect 22 from the EIC prefix list (com.amazonaws.<region>.ec2-instance-connect; IPv6: com.amazonaws.<region>.ipv6.ec2-instance-connect); key lives 60 s; public IPv4 or IPv6 (⚠️ since Sep 2024) address Still SSH, still 22
SSH/RDP to private instance, no bastion EIC Endpoint ⚠️ 22/3389 from endpoint SG; IAM OpenTunnel; ≤ 1 h per connection, 20 concurrent, 1 per VPC and per subnet, 5 per Region Private tunnel door
IP must survive stop/start Elastic IP (5 per Region) Public IPv4 changes on stop/start, not on reboot; ⚠️ every public IPv4 incl. EIPs $0.005/h since 1 Feb 2024 Pay for every public IPv4
DB reachable only from app tier SG reference DB SG inbound 3306/5432 with source = app SG ID (same VPC or same-Region peer; inter-Region peer needs its CIDR) Trust the badge, not the address

Purchasing options and Spot

Option Commitment Max discount vs On-Demand Capacity guaranteed? Pick it when Memory hook
On-Demand None; ⚠️ per second (60 s min) for Linux, Windows, RHEL, Ubuntu Pro; SLES hourly 0% No Short, spiky, unpredictable, must not be interrupted Walk-in price
Standard RI 1 or 3 yr, fixed configuration 72% Only if zonal Steady, known instance type; resellable on RI Marketplace Lease one specific car
Convertible RI 1 or 3 yr, exchangeable (same Region only) 66% Only if zonal Steady, but family/OS may change; cannot be sold Lease with trade-in
Compute Savings Plan 1 or 3 yr, $/hour; no cancel (⚠️ any SP: return only if ≤ $100/h, within 7 days, same month) 66% No Steady spend across families, Regions, Fargate, Lambda Commit dollars, not machines
EC2 Instance Savings Plan 1 or 3 yr, $/hour, one family + Region 72% No Steady usage in one family in one Region Dollars, but one family
SageMaker AI / Database Savings Plans ⚠️ 1 or 3 yr, $/hour 64% / 35% No Steady SageMaker AI usage / steady spend across RDS, Aurora, DynamoDB, ElastiCache Four Savings Plans types now
Spot None; reclaimable with 2-min notice 90% No Fault-tolerant batch, CI, rendering, containers; LOWEST cost Standby ticket
Dedicated Host On-Demand or reservation (≤ 70% off) — Whole host BYOL per socket/core/VM, host affinity, compliance Rent the whole building
Dedicated Instance Per instance + $2/h per Region — No Single-tenant hardware without host control Own room, landlord picks the building
On-Demand Capacity Reservation None (⚠️ future-dated: requested 5–120 days ahead, commitment ≥ 14 days, ≥ 32 vCPUs) 0% alone; add SP or regional RI Yes, one AZ Event or DR capacity in a specific AZ Paid table booking, even if you don't show
Capacity Blocks for ML Future window ≤ 8 weeks ahead; 1–14 d or up to 182 d; prepaid, no cancel — Yes (GPU/Trainium, ≤ 64 instances) Short ML training runs Book the GPU studio
Spot item Where / value Remember
Interruption notice IMDS latest/meta-data/spot/instance-action (404 until set); EventBridge EC2 Spot Instance Interruption Warning 2 minutes before stop/terminate; poll every 5 s; hibernate starts immediately
Rebalance recommendation IMDS latest/meta-data/events/recommendations/rebalance; EventBridge EC2 Instance Rebalance Recommendation Earlier, best effort; may coincide with the notice
Interruption behaviour terminate (default), stop, hibernate stop/hibernate need persistent request or maintain fleet
Max price Default = On-Demand price Leave unset; you always pay the current Spot price; ⚠️ no bidding
Request type One-time (default) or persistent Persistent: cancel request first, then terminate instances
Allocation strategy ⚠️ price-capacity-optimized recommended lowest-price = API default (CLI/API only in ASGs) but most interruptions
Launch API ASG or EC2 Fleet (instant/request/maintain, default maintain) ⚠️ RequestSpotInstances / Spot Fleet = legacy; Spot blocks deprecated
Billing EC2 interrupts in first hour = free You stop/terminate = pay per second
Protection Termination/stop protection not allowed on Spot Design for interruption
ASG mixed instances setting Default Meaning
OnDemandBaseCapacity 0 First N units always On-Demand
OnDemandPercentageAboveBaseCapacity 100 On-Demand % above the base; 100 = no Spot at all
SpotAllocationStrategy lowest-price (API); console preselects price-capacity-optimized Set price-capacity-optimized
OnDemandAllocationStrategy prioritized (manual types) / lowest-price (attribute-based) Prioritized = override order (e.g. to hit RIs)
SpotInstancePools 2 (range 1–20) Only with lowest-price
SpotMaxPrice Unset (= On-Demand price) Setting it increases interruptions
CapacityRebalance Must be enabled (--capacity-rebalance) Replace at-risk Spot first; may exceed max by ≤ 10% of desired

EBS volumes, snapshots, encryption and AMIs

Type Size Max IOPS (ratio) Max throughput Boot Multi-Attach Pick when Memory hook
gp3 1 GiB–64 TiB ⚠️ 80,000 ⚠️ (≤ 500 per GiB); 3,000 included 2,000 MiB/s ⚠️ (≤ 0.25 per IOPS); 125 included ✓ ✗ Default for boot, apps and most DBs "3k + 125 free at any size; 80k / 2k / 64T max"
gp2 1 GiB–16 TiB 16,000 (3 per GiB, min 100; < 1 TiB bursts to 3,000) 250 MiB/s ✓ ✗ Legacy; migrate to gp3 (~20% cheaper per GiB) "3 per GiB, capped at 5,334 GiB"
io2 Block Express 4 GiB–64 TiB 256,000 (1,000 per GiB) 4,000 MiB/s ✓ ✓ > 80k IOPS, > 2,000 MiB/s, sub-ms latency, 99.999%, shared block "1000:1, five nines"
io1 4 GiB–16 TiB 64,000 Nitro / 32,000 other (50 per GiB) 1,000 MiB/s ✓ ✓ (Linux) Legacy Provisioned IOPS; prefer io2 "50:1"
st1 125 GiB–16 TiB 500 500 MiB/s ✗ ✗ Big sequential: logs, ETL "HDD can't boot"
sc1 125 GiB–16 TiB 250 250 MiB/s ✗ ✗ Coldest, cheapest "sc = sleepy & cheap"
Feature High-yield facts CLI Memory hook
Scope Volume = 1 AZ; snapshot and AMI = 1 Region create-volume --availability-zone "Volume lives in a zone, images live in a Region"
Multi-Attach io1/io2, ≤ 16 Nitro instances, same AZ, cluster-aware FS, not boot create-volume --multi-attach-enabled "16 in one zone"
DeleteOnTermination Root at launch = true; attached later = false; launch-mapping data volumes: console No, CLI Yes modify-instance-attribute --block-device-mappings "Root dies with the instance"
Elastic Volumes Size up only; modifying → optimizing → completed; ⚠️ up to 4 changes per rolling 24 h (2026) modify-volume, describe-volumes-modifications "Grow the disk, then grow the FS"
Snapshots Incremental, async, stored in S3; copy in destination Region; first cross-Region copy full; ≤ 20 concurrent copies per destination create-snapshot, copy-snapshot --source-region "Copy from the place you're going"
Snapshots Archive Up to 75% cheaper; full snapshot; 90-day minimum; restore ≤ 72 h (temporary 1–180 days) modify-snapshot-tier, restore-snapshot-tier "75 off, 90 in, 72 out"
Recycle Bin Snapshots and AMIs 1–365 days; ⚠️ volumes 1–7 days (2025); rule must exist before deletion aws rbin create-rule "Bin before you delete"
Fast Snapshot Restore Fully initialized volumes; per snapshot per AZ; ≤ 5 per Region; billed per AZ-minute (1 h minimum) enable-fast-snapshot-restores "Pre-warmed, paid per AZ"
Volume initialization rate ⚠️ 100–300 MiB/s, predictable warm-up (2025) create-volume --volume-initialization-rate
Time-based copy 15 min–48 h target, 15-min steps, extra charge; for an AMI the target applies to each of its snapshots copy-snapshot --completion-duration-minutes; copy-image --snapshot-copy-completion-duration-minutes
Default volume type Console: gp3; CreateVolume and CopyVolumes API/CLI: gp2 --volume-type gp3 "The API says gp2 unless told"
Volume copy ⚠️ Same AZ, instant, crash-consistent, can encrypt/re-key (2025); background initialization at the lowest of 3,000 IOPS / 125 MiB/s and both volumes' provisioned levels; 1 copy per source at a time, ≤ 5 in progress per Region copy-volumes --volume-type gp3 "Copy in place, name the type"
Volume sharing ⚠️ AWS RAM share; the other account can only view and copy (same AZ), never attach; unencrypted or customer managed key only aws ram create-resource-share "Share to copy, not to mount"
Root volume replacement Running instance, automatic reboot, same ID and IPs; from launch state, snapshot, AMI or ⚠️ an existing detached same-AZ volume (2026); that swap doesn't inherit DeleteOnTermination; no encrypted → unencrypted create-replace-root-volume-task --volume-id "Swap the root, keep the ID"
Data Lifecycle Manager Tag-based schedules, retention, cross-Region/account copy, FSR, archive, AMI deprecate/deregister; no extra cost aws dlm create-lifecycle-policy "Set-and-forget backups"
Scenario Do this Memory hook
Encrypt an existing unencrypted volume Snapshot → create-volume --encrypted --volume-type gp3 (or copy-snapshot --encrypted) → swap; ⚠️ same-AZ shortcut copy-volumes --encrypted --volume-type gp3 (otherwise gp2) "No in-place encryption"
Change the KMS key Copy the snapshot/AMI with a new --kms-key-id (full copy) "New key = new copy"
Share an encrypted snapshot/AMI cross-account Customer managed key + key policy (and grants) + createVolumePermission / --launch-permission; impossible with aws/ebs "aws/ebs never leaves the account"
Copy an encrypted AMI/snapshot to another Region Run in the destination Region; key must exist there "Keys are Regional"
ASG launch with a customer managed key Key policy for AWSServiceRoleForAutoScaling; cross-account: unconditioned kms:CreateGrant for the ASG account, which runs aws kms create-grant for its role "Client.InternalError on launch = KMS"
Encrypt every new volume enable-ebs-encryption-by-default per Region (+ modify-ebs-default-kms-key-id) "New only, never retroactive"
Latest Amazon Linux AMI resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64; CFN AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>; ⚠️ AL2 ended 2026-06-30 "Resolve, don't hard-code"
Retire an AMI Deprecate (still launchable by ID) → disable → deregister-image --delete-associated-snapshots ⚠️ (default keeps snapshots) "Hide, block, delete"
Faster scale-out Golden AMI (built by EC2 Image Builder) instead of long user data "Bake, don't fry"

Storage choice: instance store vs EBS vs EFS

Instance store EBS EFS
What Local NVMe/SSD/HDD on the host Network block volume Managed NFS v4.0/4.1 file system
Sharing One instance One instance (io1/io2 Multi-Attach ≤ 16 Nitro, same AZ) Thousands of clients: EC2, ECS, EKS, Fargate, Lambda, on-prem
Scope That instance One AZ Regional (≥ 3 AZs) or One Zone
Attach Launch only; NVMe types attached automatically, old non-NVMe types (C3, M3, R3, D2, H1, I2, X1…) need ephemeralN mappings Any time, same AZ Mount through the mount target in each AZ
Persistence Survives reboot; lost on stop (also an OS shutdown), hibernate, terminate, type change, retirement, recovery, disk failure Independent of the instance Independent of the instance
Performance Highest (e.g. i3.16xlarge ≈ 3.3 M random-read IOPS) Up to 256,000 IOPS per volume (io2 Block Express) Elastic: 20–60 GiB/s read, 1–5 GiB/s write per FS ⚠️
Backup Do it yourself (copy to S3/EBS/EFS); no snapshots, not in AMIs Snapshots, DLM, AWS Backup AWS Backup, replication
OS Any Any Linux only (Windows → FSx for Windows)
Price Included in the instance Provisioned GiB (+ IOPS/throughput) Stored GB by class (+ throughput mode)
Memory hook "Reboot-safe, stop-sorry" "One AZ, one owner" "NFS 2049, one mount target per AZ"
EFS setting Options Current guidance Memory hook
File system type Regional / One Zone Regional for production (⚠️ older material calls it "Standard"); One Zone is cheaper, backups on by default, no Max I/O "One Zone = one basket"
Performance mode (fixed at creation) General Purpose / Max I/O General Purpose for everything ⚠️ Max I/O is previous-gen, not with Elastic or One Zone "GP forever"
Throughput mode (switchable) Elastic / Provisioned / Bursting Elastic for spiky or unknown; Provisioned for steady known (24 h lock after any change: no switching away, no decrease); Bursting = 50 MiB/s per TiB, burst 100 MiB/s per TiB "Elastic = pay per byte moved"
Defaults trap Console: Elastic + GP + encrypted API/CLI: bursting, unencrypted unless flags are set ⚠️ "Console is kind, CLI is literal"
Storage classes Standard / Infrequent Access / Archive Lifecycle (console default): IA after 30 days, Archive after 90; Archive needs Elastic, 90-day minimum; 128 KiB minimum billed per file "S → IA → A"
Encryption At rest (creation only) / in transit (-o tls) Enforce with elasticfilesystem:Encrypted and a aws:SecureTransport deny "At birth or never"
Access control SG TCP 2049, IAM (-o tls,iam), access points ClientMount / ClientWrite / ClientRootAccess; no policy = open to anyone who reaches a mount target
Mount errors Hang + Connection timed out / Failed to resolve server / access denied by server Timeout = SG (or NACL) blocks 2049, or wrong IP; resolve failure = no mount target in the AZ, other VPC, VPC DNS off, or target < 90 s old; denied = IAM or file system policy "Hang = port, name = target, denied = policy"
Lambda Access point + VPC + /mnt/... path Execution role needs ClientMount (+ ClientWrite) and VPC permissions "Lambda enters through the access point"
Per-client throughput 1,500 MiB/s with efs-utils ≥ 2.0 (Elastic), else 500 MiB/s Keep amazon-efs-utils current
If you need Choose Memory hook
Shared POSIX files across AZs (CMS, uploads folder used as files, home dirs) EFS Regional + mount target per AZ + SG 2049 "Many readers, many AZs = EFS"
Highest-IOPS scratch or cache that can be lost Instance store "Fast and forgetful"
Persistent single-instance DB or boot volume EBS gp3 (io2 Block Express above 80k IOPS) "One server, one volume"
Shared block device, cluster-aware app, one AZ io2 Multi-Attach "16 in one zone"
Windows SMB / Active Directory share FSx for Windows File Server "Windows talks SMB"
HPC/ML parallel FS over S3 data FSx for Lustre "Lustre for lots of cores"
Objects (incl. user uploads via the SDK or presigned URLs), static assets, backups, data lake S3 "Keys, not paths"

Elastic Load Balancing: ALB, NLB, GWLB

Type Layer and protocols Targets Signature features Memory hook
ALB L7: HTTP, HTTPS, HTTP/2, WebSockets, gRPC instance, ip (private), lambda (1 fn/TG, 1 MB req/resp) Rules on host, path, header, method, query string, source IP; ⚠️ regex (RegexValues) on host-header, path-pattern, http-header; redirect, fixed response, Cognito/OIDC auth, JWT validation; weighted TGs (≤ 5, weight 0–999); X-Forwarded-For/-Proto/-Port; no Elastic IPs (⚠️ public IPv4 can come from an IPAM pool: allow-list a CIDR, not fixed per-AZ IPs) Reads the letter
NLB ⚠️ L4: TCP, UDP, TLS, TCP_UDP, QUIC, TCP_QUIC instance, ip, alb (no Lambda) 1 static IP per AZ + optional Elastic IP; millions of req/s; client IP preserved (instance targets); ⚠️ SGs only if set at creation, and QUIC/TCP_QUIC need an ipv4 NLB with no SGs (QUIC: draining fixed 300 s, no Proxy Protocol v2); ⚠️ TCP idle 350 s (60–6000) Reads only the envelope
GWLB L3: all IP packets, all ports instance, ip (appliances) Transparent bump-in-the-wire via GWLB endpoint + route tables; GENEVE port 6081; 5-tuple flow stickiness; MTU 8,500 X-rays the parcel
CLB L4/L7: TCP, SSL, HTTP, HTTPS Instances (no TGs) Legacy; 1 cert per listener (no SNI); connection draining 1–3600 s Retired grandpa
Code or metric Generated by Usual cause Memory hook
403 ALB AWS WAF blocked the request Bouncer
460 ALB Client closed the connection before the LB answered Client gave up
463 ALB X-Forwarded-For with more than 30 IPs Too many hops
500 ALB AWS WAF execution error; IdP token/user-info or JWKS endpoint unreachable or slower than 5 s; IdP claims over 11 KB Helper broke
502 ALB Target reset/closed the connection (keep-alive < idle timeout), malformed response, target TLS error, Lambda error/timeout/invalid or > 1 MB response Bad answer
503 ALB No registered (or usable) targets in the target group Nobody home
504 ALB No connection within 10 s (SG/NACL) or no response before the idle timeout No answer in time
HTTPCode_ELB_5XX_Count vs HTTPCode_Target_5XX_Count LB vs your app Separate the load balancer's errors from your code's errors ELB = infra, Target = code
TargetResponseTime / RequestCountPerTarget ALB Target latency (Avg/pNN) / requests per target (statistic Sum)
Access logs ALB → S3 Off by default; every 5 min; same-Region bucket, SSE-S3; ⚠️ bucket-policy principal logdelivery.elasticloadbalancing.amazonaws.com (not a Regional ELB account ID); also CloudWatch vended logs Opt-in diary
Setting Default Range / note
ALB health check HTTP /, 30 s interval, 5 s timeout, 5 healthy / 2 unhealthy, code 200 Interval 5–300 s, timeout 2–120 s, codes 200–499; healthy threshold = unhealthy → healthy, a new target needs only 1 passing check; all unhealthy → fail open
NLB health check TCP, 30 s, 10 s (HTTP 6 s), 5 / 2, HTTP codes 200-399 HTTP/HTTPS optional
ALB idle timeout 60 s 1–4000 s
Deregistration delay 300 s 0–3600 s (0 = off); state draining for the full delay, then unused; ALB: upper bound for in-flight requests (none in flight, no active connections → deregistered at once, still shown draining); lower it for faster deployments; NLB QUIC fixed 300 s
Slow start 0 (off) 30–900 s; not with least outstanding requests / weighted random
Cross-zone ALB on (free), NLB/GWLB off (charged when on), ⚠️ CLB off via API/CLI, on via console (free) ALB can turn it off per target group
ALB to target connect timeout 10 s Exceeded → 504

Sticky sessions, TLS and SNI

Stickiness Mechanism Cookie / key Duration Memory hook
ALB duration-based Load balancer cookie (lb_cookie) AWSALB + AWSALBCORS (SameSite=None; Secure), both on every response; AWSALBCORS wins if both arrive 1 s – 7 days, default 1 day LB bakes the cookie
ALB application-based Your cookie (name set per target group) + LB cookie (app_cookie); client must return both custom name + AWSALBAPP-0 (-1…-3 when over 4 KB, max 16 KB) 1 s – 7 days, default 1 day App bakes, LB stamps
ALB weighted target groups Target-group stickiness on the forward action AWSALBTG + AWSALBTGCORS 1 s – 7 days Sticks to blue or green
CLB LB-generated or application-controlled (follows your cookie's lifetime) AWSELB + AWSELBCORS optional expiry (none = browser session) ELB = old name
NLB Source IP hash (source_ip) none n/a; not on TLS or QUIC listeners No cookies at layer 4
Reserved / limits Prefixes AWSALB, AWSALBAPP, AWSALBTG are reserved; ALB stickiness needs cross-zone on; uneven load and lost sessions on failure Stateless + ElastiCache/DynamoDB beats sticky
TLS / ACM fact Current value Memory hook
ACM public certificate cost Free with integrated services (ELB, CloudFront, API Gateway); ⚠️ exportable public certificates (since June 2025, key exported too) cost $7 per FQDN / $79 per wildcard at issuance and each renewal Free if it stays in AWS
ACM validity / renewal ⚠️ 198 days (was 395); DNS-validated certs auto-renew from 45 days before expiry; email needs approval; HTTP validation only via CloudFront distribution tenants; imported never. CA/B Forum max: 100 days from 15 Mar 2027, 47 days from 15 Mar 2029 198, renew at 45
Region Same Region as the ALB/NLB; CloudFront viewer certs in us-east-1 CloudFront certs live in Virginia
Listener certificates 1 default + certificate list for SNI; 25 per ALB excluding default; CLI/CloudFormation/CDK listeners start with an empty list (console adds the default); match but client-incompatible → handshake fails Default = fallback only when no SNI or no match
Default security policy ⚠️ Console: ELBSecurityPolicy-TLS13-1-2-Res-PQ-2025-09; CLI/CloudFormation/CDK: ELBSecurityPolicy-2016-08 API default is old: set it explicitly
Wildcard *.example.com One level only; not the apex Add the apex as a SAN
Capability ALB NLB CLB CloudFront
SNI (many certificates on one listener) Yes Yes (TLS listener) No Yes
TLS passthrough to targets No (always terminates, can re-encrypt) Yes (TCP listener on 443) Yes (TCP listener) see CloudFront module
Validates target certificates No (self-signed OK) No (TLS target groups) Optional back-end server authentication Yes: origin cert from a trusted CA with a matching name, else 502
Mutual TLS at the load balancer Yes: passthrough (X-Amzn-Mtls-Clientcert) or verify (trust store from S3) No (use TCP passthrough) No (use TCP passthrough) see CloudFront module

Auto Scaling

Policy Use when Key facts Memory hook
Target tracking Keep a per-instance metric at a value (CPU 50%, 500 req/target) ASG creates and owns the alarms; ASGAverageCPUUtilization, ASGAverageNetworkIn/Out, ALBRequestCountPerTarget (+ ResourceLabel); custom + metric math; high-res down to 10 s; out if any policy, in only if all Thermostat
Step React harder to bigger breaches You own the alarm; ChangeInCapacity / ExactCapacity / PercentChangeInCapacity; uses warmup, not cooldown Staircase
Simple Legacy only One adjustment, then waits for the cooldown (default 300 s) Sleepy
Scheduled Known calendar peaks Cron + time zone (UTC default); sets min/max/desired; ≤ 125 per ASG Calendar
Predictive Recurring daily/weekly pattern, slow boot ≥ 24 h data, up to 14 days analysed, 48 h hourly forecast, refreshed every 6 h; ForecastOnly first; scales out only Weather forecast
SQS workers Queue-driven processing Target tracking on backlog per instance = visible messages ÷ GroupInServiceInstances (⚠️ metric math, no custom metric needed; enable group metrics first or the alarms sit in INSUFFICIENT_DATA); target = acceptable latency ÷ processing time Messages per worker
Setting Default Notes
Health check type EC2 (always on) Add ELB, ⚠️ VPC_LATTICE, EBS explicitly; custom: set-instance-health
⚠️ EC2 application status checks Off (create in EC2) HTTP/HTTPS port + path every 60 s (fixed), thresholds 2/2, timeout 6 s, matcher 200, init grace 300 s; associate by tag aws:autoscaling:groupName → impaired instances replaced even with type EC2; no redirects followed; $0.01 per managed ENI-hour per AZ
Health check grace period 300 s console / 0 s CLI-SDK Delays health replacement after InService
Default instance warmup Not set Recommended; used by target tracking, step, instance refresh
Default cooldown 300 s ⚠️ Gates simple scaling; may delay scale-in; never delays unhealthy-instance replacement
Lifecycle hook heartbeat 3600 s (30–7200) Global max 48 h or 100 × heartbeat; DefaultResult = ABANDON
Lifecycle notification targets EventBridge (console) SNS / SQS (role ARN, no FIFO) or ⚠️ Lambda (resource policy for AWSServiceRoleForAutoScaling); CLI, CloudFormation or SDK
⚠️ Instance lifecycle policy Off Retain on TerminateHookAbandon → Terminating:Retained (billed, outside desired capacity); terminate with terminate-instance-in-auto-scaling-group
Instance refresh healthy % Min 90% (0–100), Max 100% (100–200) ⚠️ Min 100% = launch before terminate; max − min ≤ 100
Refresh extras Checkpoint delay 3600 s; bake time 0; ≤ 10 alarms; 14-day limit Event per checkpoint except 100%; skip matching: CLI off / console on; auto rollback needs a desired configuration and a numbered LT version; listed alarms must be OK at start (INSUFFICIENT_DATA or ALARM → error)
Launch configurations ⚠️ None for accounts created since 1 Oct 2024 No new instance types since 1 Jan 2023; use launch templates
Group metrics Off Free, 1-minute; enable-metrics-collection
Symptom or need Do this Memory hook
ALB says unhealthy, ASG keeps the instance --health-check-type ELB ASG trusts only EC2 by default
App hangs on a running instance, no load balancer in front ⚠️ EC2 application status check on an unauthenticated 200 path, associated by tag aws:autoscaling:groupName EC2 check, now app-aware
New instances replaced in a loop Grace period ≥ boot time or launch lifecycle hook; check /health and SGs; suspend ReplaceUnhealthy to debug Grace before judging
Roll out a new AMI / template version Instance refresh (+ checkpoints, skip matching, auto rollback with alarms) Refresh, don't rebuild
Run code before traffic / before termination Pending:Wait / Terminating:Wait hook + complete-lifecycle-action Set up, clean up
Inspect a sick instance undisturbed enter-standby (deregistered, no health checks, still billed) Bench the player
Fast scale-out for slow-booting apps Warm pool (Stopped = pay only EBS volumes and Elastic IPs) Pre-heated oven
Spot instance at risk Capacity Rebalancing + price-capacity-optimized Move before the eviction
Keep a busy worker on scale-in Scale-in protection (not against health or Spot) Shield only for scale-in

CloudWatch for EC2

Data Source / namespace Frequency Memory hook
CPUUtilization, NetworkIn/Out, EBS* (Nitro) EC2, AWS/EC2 5 min basic (free) / 1 min detailed (paid) Seen from outside the guest
DiskReadOps/WriteOps/ReadBytes/WriteBytes EC2, AWS/EC2 Same Disk* = instance store only
CPUCredit* (T instances), NetworkPackets* EC2, AWS/EC2 5 min only
StatusCheckFailed, _Instance, _System, _AttachedEBS EC2, AWS/EC2 1 min, free 0 = pass, 1 = fail
Memory, disk space, swap, processes (procstat), logs Unified CloudWatch agent, CWAgent + CloudWatch Logs 60 s default; < 60 s = high-resolution Inside the guest = agent + role
App metrics PutMetricData (or agent StatsD :8125 / collectd) StorageResolution 60 (default) or 1 Your namespace, never AWS/
Status check Means Fix Memory hook
System AWS host, power or network fault Recover (alarm or simplified automatic recovery) or stop/start (new host, new public IP) AWS's box → move it
Instance Your OS/config: bad network/boot config, memory exhausted, corrupted FS, kernel Reboot or fix the OS Your box → reboot/fix
Attached EBS ⚠️ EBS volumes unreachable or I/O stalled (Nitro) Wait, replace volume, stop/start; ASG replaces Storage link broken
Application (opt-in) ⚠️ HTTP/HTTPS probe of path/port every 60 s fails Fix app; ASG replaces impaired instances Health page says no
Item Value
Agent IAM Instance role with CloudWatchAgentServerPolicy; Parameter Store config named AmazonCloudWatch-*; CloudWatchAgentAdminPolicy only to write configs
Logs agent ⚠️ The old CloudWatch Logs agent (awslogs) is deprecated and fails on IMDSv2-only instances: use the unified CloudWatch agent
PutMetricData limits ⚠️ ≤ 1,000 metrics and 1 MB per call; 150 values per array; 30 dimensions per metric; timestamps 2 weeks back to 2 hours ahead; 500 TPS
Retention < 60 s: 3 h; 1 min: 15 days; 5 min: 63 days; 1 h: 455 days (15 months)
High-resolution read periods 1, 5, 10, 30 s or multiples of 60 s
Alarm periods ⚠️ 10, 20, 30 s (high-resolution, extra cost; only useful on StorageResolution 1 data) or multiples of 60 s
Monitoring change in launch template New instances only; running ones keep their type until instance refresh or monitor-instances
Alarm logic States OK / ALARM / INSUFFICIENT_DATA; M of N = DatapointsToAlarm of EvaluationPeriods; missing data default missing; ≤ 5 actions per state
Evaluation window Period × EvaluationPeriods ≤ 1 day (periods < 1 h) or ≤ 7 days
EC2 actions arn:aws:automate:<region>:ec2:<action> (stop, terminate, reboot, recover); recover only on StatusCheckFailed_System; recover 2 × 1 min, reboot 3 × 1 min
Recovery keeps Instance ID, private/public/Elastic IPs, metadata, placement group, EBS volumes, AZ (loses RAM)
Simplified automatic recovery ⚠️ On by default for supported types; not for metal, instance store, Dedicated Hosts, EFA, ASG members; modify-instance-maintenance-options --auto-recovery
Testing set-alarm-state runs the new state's actions; composite alarms cannot do EC2/Auto Scaling actions
Free tier 10 metrics (custom + detailed monitoring combined), 10 alarm metrics, 1 million API requests, 5 GB logs

Numbers to know

Item Value Note
Roles per instance profile 1 (hard limit, not adjustable) Also 1 role (1 profile) per instance at a time; one role can sit in many profiles
Delay after swapping the role inside an instance profile Up to 1 hour Replace the instance-profile association instead (or disassociate/associate, stop/start)
Instance role credential refresh New set at least 5 min before expiry SDKs/CLI refresh automatically; if you cache them yourself, refresh hourly or ≥ 15 min before Expiration
AWS CLI v2 credential sources 10 ⚠️ options → env → assume role → web identity → Identity Center → credentials file → credential_process → config file → container → instance profile
aws login console credentials 15-minute credentials, auto-refreshed up to 12 h ⚠️ Needs AWS CLI 2.32.0+; the session also works in current SDKs
AWS SDK for Java 1.x end of support 2025-12-31 Use SDK for Java 2.x (system property aws.secretAccessKey)
IMDS endpoints 169.254.169.254 / [fd00:ec2::254] IPv6 only on Nitro in IPv6-capable subnets, off by default
IMDSv2 token TTL 1–21,600 s (max 6 h) Header X-aws-ec2-metadata-token-ttl-seconds on PUT /latest/api/token
HttpPutResponseHopLimit 1–64; default 1 (2 with ImdsSupport v2.0 AMIs such as AL2023 ⚠️) Set 2 on container hosts when IMDSv2 is required
IMDS HTTP errors 401 / 403 / 400 / 404 / 503 401 = missing or expired token with v2 required; 403 = IMDS off or not allowed; 400 bad PUT; 404 no such item; 503 retry
Link-local packet limit 1,024 packets/s per network interface Shared by IMDS, Route 53 Resolver DNS, NTP and Windows licensing; drops show in ENA linklocal_allowance_exceeded
AWS CLI IMDS timeout / attempts 1 s / 1 attempt AWS_METADATA_SERVICE_TIMEOUT, AWS_METADATA_SERVICE_NUM_ATTEMPTS
Minimum versions using IMDSv2 automatically CLI 1.16.289; boto3 1.12.6; Java 2.x 2.10.21; JS v2 2.722.0 All current SDKs support IMDSv2
IMDSv2 released 2019-11-19 Session-oriented IMDS
Account-level IMDS defaults Since 2024-03-25 ⚠️ modify-instance-metadata-defaults, per Region, new launches only
Account-level IMDSv2 enforcement Since 2026-02-24 ⚠️ --http-tokens-enforced enabled: launches that allow IMDSv1 fail
User data size 16 KB raw (before base64) Encoded size = ceil(n/3) × 4
CloudFormation CreationPolicy ResourceSignal Count 1, Timeout PT5M (defaults); max 12 h cfn-signal -e $? reports success or failure
Public IPv4 address charge $0.005 per IP-hour ⚠️ Since 1 Feb 2024; in-use and idle addresses alike, including Elastic IPs on running instances; BYOIP addresses are not charged
Security groups per network interface 5 (adjustable to 16) Rules per SG × SGs per ENI must stay ≤ 1,000
Rules per security group 60 inbound + 60 outbound Counted separately for IPv4 and IPv6; a rule that references an SG counts as one rule
VPC security groups per Region 2,500 Default quota, adjustable
Elastic IP addresses per Region 5 Default quota, adjustable
Network ACL rules 20 per direction (max 40); rule numbers 1–32766 Lowest number evaluated first, first match wins; default NACL allows all, new custom NACL denies all
Ephemeral port range to allow in NACLs 1024–65535 Stateless NACLs need explicit return-traffic rules; SGs do not
EC2 Instance Connect pushed key lifetime 60 seconds SendSSHPublicKey; still SSH on TCP 22
EC2 Instance Connect Endpoint limits 1 per VPC and per subnet, 5 per Region, 20 concurrent connections, 1 hour max per connection ⚠️ No extra charge; cross-AZ data transfer applies
Classic ports 22 SSH/SFTP, 21 FTP, 80 HTTP, 443 HTTPS, 3389 RDP 443 is also the outbound port for SSM Agent and SDK calls to AWS APIs
Database, cache and NFS ports 3306 MySQL/MariaDB/Aurora MySQL, 5432 PostgreSQL, 1433 SQL Server, 1521 Oracle, 6379 Redis OSS/Valkey, 11211 Memcached, 2049 NFS (EFS) Allow on the DB, cache or EFS mount-target SG with source = app SG ID
Session Manager connectivity Outbound TCP 443 to ssm, ssmmessages, ec2messages No inbound rules; via NAT/IGW or interface VPC endpoints whose SG allows inbound 443 from the instances
On-Demand billing granularity Per second, 60-second minimum ⚠️ Linux, Windows (incl. SQL Server editions), RHEL, Ubuntu Pro; SLES is billed per full hour
Reserved Instance max discount Standard 72%, Convertible 66% 1 or 3 years; All/Partial/No Upfront; only Standard can be sold on the RI Marketplace
Savings Plans max discount Compute 66%, EC2 Instance 72%, SageMaker AI 64%, Database 35% ⚠️ 1 or 3 years, $/hour commitment; no capacity reservation; never applies to Spot
Savings Plan return window Within 7 days of purchase, same calendar month, hourly commitment ≤ $100 ⚠️ Up to 10 returns per calendar year per management account; upfront refunded in full (ReturnSavingsPlan)
Spot max discount Up to 90% vs On-Demand No bidding ⚠️; default max price = On-Demand price; AWS recommends not setting one
Spot interruption notice 2 minutes IMDS spot/instance-action + EventBridge warning; poll every 5 s; no 2-minute grace with the hibernate behaviour
Dedicated Host Reservation discount Up to 70% Versus On-Demand Dedicated Host pricing
Dedicated Instances regional fee $2 per hour per Region Charged in each Region where at least one Dedicated Instance runs; not discounted by Savings Plans
Future-dated Capacity Reservations ≥ 32 vCPUs per request; requested 5–120 days ahead; commitment ≥ 14 days (12 weeks for U and X) ⚠️ Cancellation charge may apply; immediate-use ODCRs have no commitment
Capacity Blocks for ML Up to 8 weeks ahead; 1–14 days (1-day steps) or up to 182 days (7-day steps); ≤ 64 instances per block, 256 across blocks Prepaid, cannot be cancelled
ASG OnDemandBaseCapacity default 0 First N capacity units are always On-Demand
ASG OnDemandPercentageAboveBaseCapacity default 100 100 means no Spot at all until lowered
ASG SpotInstancePools default 2 (range 1–20) Only used with the lowest-price strategy
ASG Capacity Rebalancing overshoot Up to 10% of desired capacity above max size Temporary, while replacements launch before at-risk Spot Instances terminate
Spot diversification best practice ≥ 10 instance types Plus all AZs; Spot placement score 1–10
gp3 included baseline 3,000 IOPS + 125 MiB/s at any size No burst credits; ~20% cheaper per GiB than gp2
gp3 maximums 80,000 IOPS / 2,000 MiB/s / 64 TiB ⚠️ Since 2025-09-26; older material: 16,000 IOPS / 1,000 MiB/s / 16 TiB
gp3 provisioning ratios 500 IOPS per GiB; 0.25 MiB/s per provisioned IOPS Full 80,000 IOPS from 160 GiB; 2,000 MiB/s needs ≥ 8,000 IOPS
gp2 IOPS 3 IOPS/GiB, min 100, max 16,000 (at 5,334 GiB) Volumes < 1 TiB burst to 3,000 IOPS (5.4 M credit bucket, BurstBalance)
gp2 throughput 128–250 MiB/s 250 MiB/s from 334 GiB
io2 Block Express 256,000 IOPS, 4,000 MiB/s, 4 GiB–64 TiB, 1,000 IOPS/GiB, 99.999% ⚠️ All io2 volumes are Block Express since 2025-04-30; non-Nitro instances reach 32,000 IOPS
io1 64,000 IOPS (Nitro) / 32,000 (other), 50 IOPS/GiB, 1,000 MiB/s, 4 GiB–16 TiB AWS recommends io2 instead
st1 / sc1 500 / 250 MiB/s; 500 / 250 IOPS; 125 GiB–16 TiB HDD types cannot be boot volumes
EBS Multi-Attach Up to 16 Nitro instances, same AZ io1/io2 only; cluster-aware file system; not boot; Windows: io2 only
Elastic Volumes frequency Up to 4 modifications per volume per rolling 24 h ⚠️ Since 2026-01-15; each one after the previous completes (older material: wait ≥ 6 h)
copy-volumes concurrency 1 copy per source volume at a time; ≤ 5 in progress per Region ⚠️ Same AZ only; VolumeType defaults to gp2; CopyVolumesLimitExceeded beyond that
Concurrent snapshot copies 20 per destination ResourceLimitExceeded beyond that
Time-based snapshot/AMI copy 15 min–48 h completion target, 15-minute increments Extra per-GiB charge
EBS Snapshots Archive Up to 75% cheaper; 90-day minimum; restore up to 72 h; temporary restore 1–180 days An archived snapshot is a full snapshot; restore it before use, copy or share
Recycle Bin retention Snapshots and AMIs 1–365 days; EBS volumes 1–7 days ⚠️ Volumes supported since 2025-11-20; the rule must exist before the deletion
Recycle Bin rule lock unlock delay 7–30 days Region-level rules without exclusion tags
Fast Snapshot Restore ≤ 5 snapshots per Region; billed per snapshot per AZ per minute (1-hour minimum) Enabled per snapshot per AZ
Provisioned Rate for Volume Initialization 100–300 MiB/s per volume ⚠️ Since 2025-05-06; 5,000 MiB/s cumulative per Region
AMI deprecation Public AMIs: 2 years after creation by default; max 10 years (private) Deprecated AMIs remain launchable by ID
AMI deregistration protection cooldown 24 h (optional) Protection blocks deregistration regardless of IAM
AL2023 AMI deprecation 90 days after each release Resolve the SSM public parameter instead of hard-coding IDs
Amazon Linux 2 end of support 2026-06-30 ⚠️ Use the al2023-ami-kernel-default-x86_64 / -arm64 parameters
EFS mount targets 1 per AZ (one subnet per AZ); One Zone file system: 1 in total Mount targets in one VPC at a time; mount-target SG allows TCP 2049 from the client SG
EFS mount target DNS record Up to 90 s after the mount target is created Scripted mounts should wait before mounting
EFS Elastic throughput 20–60 GiB/s read, 1–5 GiB/s write per file system ⚠️ Region-dependent; older material: 3 GiB/s read / 1 GiB/s write
EFS per-client throughput 1,500 MiB/s (Elastic + amazon-efs-utils ≥ 2.0), else 500 MiB/s Keep amazon-efs-utils current
EFS Bursting throughput Baseline 50 KiB/s per GiB (50 MiB/s per TiB); burst 100 MiB/s per TiB (min 100 MiB/s) BurstCreditBalance metric
EFS Provisioned throughput change lock 24 h After switching to Provisioned or changing the amount: no switch away and no decrease for 24 h
EFS lifecycle console defaults IA after 30 days, Archive after 90 days, no move back TransitionToPrimaryStorageClass AFTER_1_ACCESS is optional
EFS IA/Archive billing minimums 128 KiB per file; Archive 90-day minimum storage Archive requires Elastic throughput (Regional file systems)
Instance store example i3.16xlarge: 8 × 1,900 GB NVMe, ~3.3 M random-read / 1.44 M write IOPS Included in the instance price; survives reboot only
Lambda EFS mount path /mnt/<name> (pattern /mnt/[a-zA-Z0-9-_.]+) Access point + VPC configuration required
ALB health check defaults HTTP /, 30 s interval, 5 s timeout, 5 healthy / 2 unhealthy, success code 200 Ranges: interval 5–300 s, timeout 2–120 s, thresholds 2–10, codes 200–499; Lambda target groups: off by default (35 s / 30 s when on)
NLB health check defaults TCP, 30 s interval, 10 s timeout (6 s for HTTP), 5 / 2, HTTP codes 200–399 HTTP/HTTPS health checks optional; matcher range 200–599
ALB connection idle timeout 60 s (1–4000 s) Target slower than this → 504; app keep-alive shorter than this → 502
ALB connect timeout to a target 10 s No TCP connection in time (SG, NACL, overload) → 504
Deregistration delay (connection draining) 300 s default, 0–3600 s 0 disables; target state draining; CLB connection draining 1–3600 s
Slow start 30–900 s (default 0 = off) Not with least_outstanding_requests or weighted_random
Weighted target groups Up to 5 per forward action, weight 0–999 Blue/green or canary at the ALB; no automatic failover between groups
Lambda target payload 1 MB request body, 1 MB response JSON Request too big → 413, response too big → 502; one function per target group, same account and Region
X-Forwarded-For limit 30 IP addresses More → HTTP 463
ALB HTTP header limits 16 KB request line, 16 KB single header, 64 KB all request headers Hard limits (400 or 413 when exceeded)
ALB access logs Off by default; delivered every 5 minutes Same-Region S3 bucket, SSE-S3 only, best effort, pay S3 storage only
ELB CloudWatch metric granularity 60 s Reported only while traffic flows; RequestCountPerTarget statistic Sum = per-target average
GWLB GENEVE on port 6081, MTU 8,500 bytes Targets instance/ip; 5-tuple flow stickiness by default
NLB TCP idle timeout 350 s default (60–6000 s) ⚠️ Configurable since September 2024; TLS listeners stay at a fixed 350 s
ALB quotas 100 rules, 50 listeners, 1,000 targets, 25 certificates (excluding the default) Per ALB; subnets in at least 2 AZs required
ALB stickiness duration 1 s – 7 days (default 1 day = 86,400 s for lb_cookie and app_cookie) lb_cookie (AWSALB), app_cookie (AWSALBAPP), target-group stickiness (AWSALBTG; no default, set the duration when enabling it)
ACM public certificate validity 198 days ⚠️ CA/B Forum maximum: 100 days from 15 March 2027, 47 days from 15 March 2029
ACM managed renewal start (DNS validated) 45 days before expiry ⚠️ Older 395-day certificates renew 60 days before expiry; imported certificates never auto-renew
ACM exportable public certificate price $7 per FQDN, $79 per wildcard name ⚠️ Charged at issuance and at each renewal; standard ACM certificates are free with integrated services
ASG health check grace period 300 s (console) / 0 s (CLI, SDK) Delays health-check replacement after InService
Default scaling cooldown 300 s Applies only to simple scaling policies ⚠️
Default instance warmup Not set by default; start around 300 s Used by target tracking, step scaling, instance refresh; instance refresh falls back to the grace period
Instance refresh healthy percentages Min 90% (0–100), Max 100% (100–200) Max − min ≤ 100; Min 100% = launch before terminate ⚠️
Instance refresh extras CheckpointDelay 3600 s, BakeTime 0, up to 10 alarms, 14-day limit Retries a blocking problem for 1 hour before failing; skip matching: CLI off / console on
Lifecycle hook heartbeat timeout 3600 s default (30–7200 s) Global max 48 h or 100 × heartbeat; DefaultResult ABANDON
Predictive scaling ≥ 24 h data, up to 14 days analysed, 48 h hourly forecast, refreshed every 6 h Starts in ForecastOnly; ForecastAndScale only scales out
Target tracking high-resolution period 10 s minimum The metric must be published at that resolution or finer
Scheduled actions 125 per ASG Cron in UTC unless a time zone is set; may start up to 2 minutes late
Unhealthy instance replacement batch Up to 10% of desired capacity at a time Instances that are no longer running are replaced immediately
Launch configuration cut-offs No new instance types since 1 Jan 2023; accounts created on or after 1 Oct 2024 cannot create any ⚠️ Accounts created on or after 1 Jun 2023 cannot create them in the console
EC2 monitoring periods Basic 5 min (free); detailed 1 min (charged per metric) Status check metrics are 1 min and free even with basic monitoring
CPU credit and NetworkPackets* metrics 5-minute frequency only CPU credit metrics exist only for burstable T instances
CloudWatch metric retention < 60 s: 3 h; 1 min: 15 days; 5 min: 63 days; 1 h: 455 days (15 months) High-resolution data points are kept 3 hours at full resolution
PutMetricData request limits 1,000 metrics, 1 MB (gzip allowed), 150 values per Values array ⚠️ Default 500 requests per second
Dimensions per metric 30 Each distinct dimension combination is a separate metric
PutMetricData timestamp window 2 weeks in the past to 2 hours in the future Keep instance clocks synced
StorageResolution 60 (default, standard) or 1 (high-resolution) High-resolution data readable at 1, 5, 10, 30 s or multiples of 60 s
Alarm period values 10, 20, 30 s or any multiple of 60 s ⚠️ Sub-minute periods = high-resolution alarms (extra cost) and need StorageResolution 1 metrics
Alarm evaluation window max 1 day for periods < 1 h; 7 days otherwise Period × EvaluationPeriods
Alarm actions per state 5 AlarmActions / OKActions / InsufficientDataActions
Recover vs reboot alarm guidance Recover 2 × 1-minute periods; reboot 3 × 1-minute periods Avoids a race between the two actions
CloudWatch alarm history 30 days aws cloudwatch describe-alarm-history
CloudWatch free tier 10 metrics (custom + detailed monitoring combined), 10 alarm metrics, 1 million API requests, 5 GB logs Basic monitoring metrics are free
CloudWatch agent StatsD listener :8125 (default service_address) StatsD on Linux and Windows; collectd on Linux only
EC2 application status checks (opt-in) Probe every 60 s; failure and success thresholds 2; 6 s timeout; 300 s initialization grace ⚠️ Metric StatusCheckFailed_Application; Auto Scaling replaces impaired instances; $0.01 per managed ENI-hour per AZ

Decision rules

IAM roles, IMDS and user data (§1–§3)

Connectivity and access (§4)

Purchasing options and Spot (§5)

EBS, AMIs and storage choice (§6–§7)

Load balancing, TLS and Auto Scaling (§8–§10)

CloudWatch for EC2 (§11)

Memory hooks

IAM roles, IMDS and user data (§1–§3)

Connectivity and access (§4)

Purchasing options and Spot (§5)

EBS, AMIs and storage choice (§6–§7)

Load balancing, TLS and Auto Scaling (§8–§10)

CloudWatch for EC2 (§11)