CloudFront — 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/cloudfront-guide.md#changed-vs-older-material) · ⚠️ unverified = AWS pages disagree, don't rely on the number · explanations and examples: notes/cloudfront-guide.md.
Origins behaviors and origin failover
| Topic | Current facts | Memory hook |
|---|---|---|
| Cache behaviors | Path patterns checked in list order, first match wins; * = 0+ chars, ? = 1 char, case-sensitive; default * behavior always last |
First match wins, default last |
| Behavior target | Each behavior routes to exactly one origin or one origin group (primary + secondary) | One behavior, one target |
| URI rewrite in a function | Does not change the chosen behavior or origin | Routing is decided first |
| S3 website endpoint origin | Custom origin: HTTP only on port 80, public bucket, no OAC or OAI | Website = public |
| VPC origins | Internal ALB, NLB (with SG, no TLS listener) or EC2 in private subnets; no gRPC, no Lambda@Edge origin request/response triggers | Private all the way |
| CloudFront vs S3 CRR | CloudFront: cached copies at every edge for a TTL (static, worldwide); CRR: async copies into chosen Regions (changing content, few Regions) | Cache everywhere vs copy somewhere |
| Allowed methods | GET, HEAD · GET, HEAD, OPTIONS · all seven; only GET/HEAD (optionally OPTIONS) responses are cached |
Writes pass, reads cache |
| Viewer protocol policy | allow-all; redirect-to-https (GET/HEAD → 301, other methods → 307); https-only (HTTP → 403) |
|
| Origin protocol policy | Custom origins: http-only, https-only, match-viewer |
|
| Origin timeouts | Connection 10 s × 3 attempts by default; response timeout 30 s (1–120 s ⚠️); optional response completion timeout; keep-alive 5 s | 3 × 10 = 30 |
| Origin failover | Primary + secondary; only GET, HEAD, OPTIONS; on chosen codes 400, 403, 404, 416, 429 ⚠️, 500, 502, 503, 504; a failed connection fails over only with 503 selected, a response timeout only with 504 (without failover, viewers get 504 from an unreachable or slow origin) |
Reads fail over, writes don't |
502 from CloudFront |
Origin TLS failure (self-signed, expired, wrong name, missing chain), NonS3OriginDnsError, invalid edge function output |
Bad handshake |
504 from CloudFront |
Origin unreachable (security group, firewall, not public) or slower than the response timeout | No answer |
503 from CloudFront |
Origin out of capacity, Lambda@Edge throttled or failed | Overloaded |
| Stacked distributions | Documented 403 cause; AWS advises against one distribution in front of another (⚠️ unverified whether a chain of 2 is allowed) |
Never stack distributions |
| Update a distribution | get-distribution-config → edit → update-distribution --if-match <ETag>; the full config is replaced, not merged |
No ETag, no update |
| Pricing | Price classes PriceClass_All (default), PriceClass_200, PriceClass_100; ⚠️ flat-rate plans (Free, Pro, Business, Premium, no overages) since 2025-11-18 |
Fewer edges, lower bill |
| Continuous deployment | Staging distribution gets ≤ 15% of traffic or requests with an aws-cf-cd- header; promote with UpdateDistributionWithStagingConfig; no HTTP/3 |
Test on a slice |
Cache keys policies TTLs and invalidations
| Topic | Current facts | Memory hook |
|---|---|---|
| Default cache key | Distribution domain name + URL path only; no query strings, headers or cookies | |
| Cache policy | Cache key contents + TTLs; every key value is also forwarded; API values none/whitelist/allExcept/all (headers: none/whitelist) |
Key it if it changes the response |
| Origin request policy | Forwards extra values to the origin without adding them to the cache key; ⚠️ "all except" block lists since 2023-02-22 | Forward it if only the origin cares |
| Response headers policy | Adds or removes response headers: CORS, security headers, Server-Timing; managed SimpleCORS, CORS-With-Preflight, SecurityHeadersPolicy |
|
CachingOptimized |
Min 1 s, default 86,400 s, max 31,536,000 s; key = path + normalized Accept-Encoding |
|
CachingDisabled |
All TTLs 0; for APIs and per-user responses | |
AllViewerExceptHostHeader |
Forwards all viewer values except Host; for API Gateway and Lambda function URL origins |
Keep your own Host |
| TTL precedence | s-maxage > max-age > Expires, clamped between min and max TTL; no header → default TTL |
s for shared |
no-cache / no-store / private |
Honoured only when min TTL = 0; viewer Cache-Control is ignored (viewers can't force a refresh) |
Min TTL wins |
| Compression | Compress = true + Gzip/Brotli enabled in the cache policy; 1,000–10,000,000 bytes; Brotli preferred |
|
| Invalidation paths | Start with / in API/CLI (/* = everything ⚠️), case-sensitive, * only as the last character, quote in the CLI |
Stars at the end only |
| Invalidation variants | One path clears all header/cookie variants; query-string variants need the query string or a trailing * |
|
| Invalidation cost | First 1,000 paths per month per account free; a wildcard path or a tag counts as 1 path | /* is one path |
| Cache tag invalidation ⚠️ | CacheTagConfig.HeaderName on the distribution; origin sends ≤ 50 tags per object; invalidate with --paths "#tag" |
Tag once, purge by name |
| Versioned file names | Preferred for frequent updates: reach browsers and proxies, no invalidation needed | Rename, don't purge |
| Hit ratio visibility | Additional metrics CacheHitRate, OriginLatency (extra cost); log field x-edge-result-type = Hit/RefreshHit/Miss/Error |
|
| Raising the hit ratio | Fewer key values, consistent query string order and case, device headers instead of User-Agent, Origin Shield |
Securing origins and content
| Topic | Current facts | Memory hook |
|---|---|---|
| OAC | CloudFront signs origin requests with SigV4; types s3, lambda, mediastore, mediapackagev2; signing always, never, no-override |
CloudFront signs, origin checks |
| OAC bucket policy | s3:GetObject for cloudfront.amazonaws.com with AWS:SourceArn = distribution ARN; Object Ownership "Bucket owner enforced" |
|
| SSE-KMS behind OAC | KMS key policy must allow kms:Decrypt for cloudfront.amazonaws.com with the same AWS:SourceArn, else 403 |
KMS needs its own yes |
| OAI | Legacy ⚠️ (use OAC): doesn't support, or needs workarounds for, SSE-KMS, PUT/DELETE and opt-in or newer Regions |
|
| OAI → OAC migration | Allow both principals in the bucket policy, switch the origin, then delete the OAI statement | |
| Lambda function URL + OAC | AuthType AWS_IAM; grant lambda:InvokeFunctionUrl + lambda:InvokeFunction; PUT/POST clients send x-amz-content-sha256 |
|
| Internet-facing ALB | Secret custom origin header + listener rule (default fixed 403) + security group from com.amazonaws.global.cloudfront.origin-facing ⚠️ |
Secret plus prefix list |
| Geo restriction | Country allow or block list for the whole distribution; blocked → 403; about 99.8% accurate; unknown location served; finer rules → AWS WAF or a function |
All or nothing |
| Field-level encryption | ≤ 10 named form-encoded fields encrypted at the edge with an RSA 2048 public key; HTTPS on both legs; legacy per AWS ⚠️ | Ten fields, one key |
| AWS WAF and certificates | Web ACL scope CLOUDFRONT via us-east-1 (blocked → 403); viewer ACM certificate in us-east-1 |
Virginia again |
| AWS Shield Standard | Automatic and free for every distribution; network and transport layer DDoS protection | Shield is always on |
| Viewer mTLS ⚠️ | Since 2025-11-24: client certificates checked against a trust store (required, optional or passthrough mode) |
Signed URLs signed cookies and key groups
| Topic | Current facts | Memory hook |
|---|---|---|
| Signed URL | One file, or clients without cookies; wins when a request also has signed cookies | URL for one |
| Signed cookies | Many files (HLS/DASH segments, members area) and unchanged URLs | Cookie for many |
| Sign-in layout | /login* behavior → app origin without signers (sets the cookies); default * → S3 with the key group |
Log in open, content locked |
| Canned policy | Expiry only; URL parameters Expires, Signature, Key-Pair-Id |
Canned = when it ends |
| Custom policy | Expiry + optional start (DateGreaterThan) + one IPv4 CIDR (AWS:SourceIp) + wildcard resource; Policy parameter |
Custom = when, where, what |
| Signed cookie names | CloudFront-Expires or CloudFront-Policy, CloudFront-Signature, CloudFront-Key-Pair-Id (+ optional CloudFront-Hash-Algorithm) |
|
| Keys and hashing ⚠️ | RSA 2048 or ECDSA 256 (PEM); SHA-1 default, Hash-Algorithm=SHA256 optional |
|
| Trusted key groups ⚠️ | Recommended signer: keys uploaded with the API, governed by IAM; 5 keys per group, 4 groups per behavior | Key groups, not root keys |
| Legacy CloudFront key pairs | Root user only, console only, ≤ 2 active per account | |
| Key rotation | Add new key → switch signing → wait for the longest URL lifetime → remove old key | Add, switch, wait, remove |
| Expiry check | Checked when the request starts; a running download finishes | |
403 with signing |
Expired or altered signature, query string added after signing, key not in the behavior's key groups | |
OPTIONS requests |
Not signature-checked (CORS preflight); allow only GET, HEAD when CORS is unused |
|
| SDK helper | @aws-sdk/cloudfront-signer: getSignedUrl({ url, keyPairId, privateKey, dateLessThan }), getSignedCookies |
|
| S3 presigned URL | Goes straight to S3 with the signer's IAM permissions (see notes/s3-guide.md §9) |
Edge functions and real time logs
| Capability | CloudFront Functions | Lambda@Edge |
|---|---|---|
| Runtime | JavaScript cloudfront-js-1.0 or cloudfront-js-2.0 (2.0 ⚠️ adds const/let, async/await, Buffer, KeyValueStore) |
Node.js or Python |
| Events | Viewer request, viewer response | Viewer request/response + origin request/response |
| Run time | Sub-millisecond (compute utilization 0–100) | Origin 30 s; viewer ⚠️ unverified (30 s vs 5 s) |
| Memory | 2 MB | 128 MB viewer; up to 10,240 MB origin |
| Code size | 10 KB | 50 MB compressed ⚠️ |
| Network, file system, body | No | Yes |
| Geolocation and device headers | Yes | Origin events only |
| Scale | Millions of requests per second | 10,000 requests per second per Region |
| Topic | Current facts | Memory hook |
|---|---|---|
| Lambda@Edge deployment | Created in us-east-1; numbered version ARN (no $LATEST, no alias); execution role trusts lambda.amazonaws.com and edgelambda.amazonaws.com |
Born in Virginia, shipped by number |
| Lambda@Edge unsupported | Environment variables, layers, VPC, DLQ, provisioned concurrency, container images, arm64, X-Ray | |
| Lambda@Edge logs | CloudWatch Logs in the Region where it ran; default group /aws/lambda/us-east-1.<function-name> |
Logs live where it ran |
| Deleting Lambda@Edge | Only after CloudFront removes the replicas, a few hours after the last association goes | |
| Mixing functions | One function per event type; no CloudFront Function + Lambda@Edge on viewer events of one behavior | |
| Viewer response skip | Viewer response functions don't run when the origin returns 400 or higher | |
| KeyValueStore | Runtime 2.0 only; store ≤ 5 MB, key ≤ 512 bytes, value ≤ 1 KB, 1 store per function | |
| Origin switch in a function ⚠️ | cf.updateRequestOrigin() / cf.selectRequestOriginById() in a viewer request function (runtime 2.0); runs on every request |
|
| CloudFront Functions lifecycle | create-function → test-function --stage DEVELOPMENT → publish-function (LIVE); --if-match ETag |
Test, then publish |
| CloudFront Functions logs | console.log() → CloudWatch Logs us-east-1, /aws/cloudfront/function/<name>, LIVE stage only |
|
| Edge function errors | Invalid output or read-only header change → 502; throttle or execution error → 503 |
|
| Real-time logs | Kinesis Data Streams only; delivered in seconds; sampling 1–100 %; chosen fields and behaviors | Real time rides Kinesis |
| Real-time logs role | Trusts cloudfront.amazonaws.com; kinesis:PutRecord(s), kinesis:DescribeStream(Summary) (+ kms:GenerateDataKey) |
|
| Standard logging v2 ⚠️ | CloudWatch Logs, Amazon Data Firehose or S3 (legacy S3-only logging still exists) | |
| Metrics | CloudFront and edge function metrics are read in CloudWatch us-east-1 | Everything global sits in Virginia |
Numbers to know
| Item | Value | Note |
|---|---|---|
| Cache behaviors per distribution | 75 ⚠️ | adjustable; older material: 25 |
| Origins per distribution | 100 ⚠️ | adjustable; older material: 25 |
| Origin connection timeout | 1–10 s, default 10 s | |
| Origin connection attempts | 1–3, default 3 | 3 × 10 s = 30 s worst case |
| Origin response timeout | default 30 s, 1–120 s ⚠️ | older material: 1–60 s |
| Default TTL | 86,400 s (24 h) | used when the origin sends no caching header |
| Maximum TTL default | 31,536,000 s (1 year) | longer values allowed ⚠️ |
| Minimum TTL | required in a cache policy; 0 lets no-cache work |
CachingOptimized uses 1 s |
| Error response caching | 10 s by default | custom error responses |
| Headers, cookies, query strings per cache policy | 10 each | adjustable |
| Custom cache policies per account | 20 | adjustable |
| Compressible object size | 1,000–10,000,000 bytes | needs Content-Length |
Largest cacheable GET response |
50 GB ⚠️ | older material: 30 GB |
| Free invalidation paths | 1,000 per month per account | then billed per path |
| Invalidation throughput | ⚠️ unverified | 150 paths/s and 1 wildcard/s (quota page) vs 3,000 files and 15 wildcards in progress (General Reference) |
| Continuous deployment traffic share | ≤ 15% | staging distribution |
| Geo-IP accuracy | about 99.8% | unknown location is served |
| Field-level encryption fields | 10 | body ≤ 1 MB, field ≤ 16 KB |
| Key groups per cache behavior | 4 | 5 public keys per group, 10 groups per account |
| CloudFront Functions code size | 10 KB | not adjustable |
| CloudFront Functions memory | 2 MB | |
| Lambda@Edge memory | 128 MB viewer / 10,240 MB origin | |
| Lambda@Edge package size | 50 MB compressed ⚠️ | older material: 1 MB on viewer events |
| Lambda@Edge timeout | 30 s origin events | viewer events ⚠️ unverified (30 s vs 5 s) |
| Lambda@Edge request rate | 10,000 per second per Region | plus that Region's Lambda concurrency (1,000 default) |
| Lambda@Edge request body exposed | 40 KB viewer / 1 MB origin | base64-encoded |
| Real-time log sampling rate | 1–100 % | whole numbers |
| Real-time log configurations | 150 per account |
Decision rules
- If you see "serve
/api/*from an ALB and everything else from S3", think two cache behaviors with S3 on the default*behavior. - If you see "static files read worldwide" vs "copies of changing objects in a few Regions", think CloudFront vs S3 Cross-Region Replication.
- If you see
502withX-Cache: Error from cloudfrontafter enabling HTTPS to the origin, think origin certificate problem. - If you see
504from CloudFront, think origin unreachable from CloudFront (security group, firewall) or too slow. - If you see
403after chaining one distribution behind another, think stacked distributions. - If you see "fail over faster to the secondary origin", think fewer connection attempts and a shorter connection timeout.
- If you see "test a CDN change on a small share of traffic", think continuous deployment with a staging distribution.
- If you see "the response depends on a header, cookie or query string", think add exactly that value to the cache policy.
- If you see "the origin needs a value that does not change the response", think origin request policy.
- If you see an API Gateway or Lambda function URL origin broken by the forwarded
Host, thinkAllViewerExceptHostHeader. - If you see "users still run old JavaScript after a release", think versioned file names plus invalidating
/index.html. - If you see "purge every object of one product regardless of URL", think cache tag invalidation.
- If you see origin
no-cachebeing ignored, think a minimum TTL above 0. - If you see "S3 content reachable only through CloudFront", think OAC + bucket policy with
AWS:SourceArn. - If you see
403on SSE-KMS objects behind OAC, think KMS key policy missingcloudfront.amazonaws.com. - If you see "ALB must accept only CloudFront traffic", think secret header + listener rule + managed prefix list, or a VPC origin.
- If you see "block whole countries", think geo restriction; per path or city, think AWS WAF or a function.
- If you see "encrypt card numbers at the edge for one backend service", think field-level encryption.
- If you see "one private file", think signed URL; "many files or unchanged URLs", think signed cookies.
- If you see "no root user and automated key rotation", think trusted key groups.
- If you see "rewrite URLs or headers on every request at the lowest cost", think CloudFront Function on viewer request.
- If you see "call an AWS service, read the body or run for seconds", think Lambda@Edge.
- If you see a rejected Lambda@Edge association, think us-east-1 and a numbered version.
- If you see "per-request logs within seconds", think real-time logs to Kinesis Data Streams.
Memory hooks
- Default behavior is the safety net: always
*, always last. - CloudFront caches everywhere; CRR copies somewhere.
- 3 × 10 = 30 seconds before CloudFront gives up on an origin.
- 502 = bad handshake, 503 = overloaded, 504 = no answer.
- Key it if it changes the response; forward it if only the origin cares.
- Min TTL above 0 beats
no-cache. - Wildcards only at the end of an invalidation path;
/*costs one path. - Rename the file, don't purge the world.
- OAC: CloudFront signs, the bucket checks the distribution ARN.
- KMS needs its own yes, even when the bucket says yes.
- Website endpoint = custom origin = public bucket.
- URL for one, cookie for many.
- Key groups, not root keys; rotate by add, switch, wait, remove.
- CloudFront Functions: tiny, fast, viewer-only, offline.
- Lambda@Edge is born in Virginia and ships by version number.
- Lambda@Edge logs live where it ran; CloudFront Functions logs live in Virginia.
- Everything global about CloudFront sits in us-east-1: certificates, WAF web ACLs, metrics, Lambda@Edge source.