CloudFront — DVA-C02 Mastery Guide
- Sources: course chapter 08 (CloudFront). The course serves as the syllabus only; all wording, examples and questions here are original. CloudFront Functions and Lambda@Edge are taught here because
notes/lambda-guide.mddefers them to this module.- Written 2026-10-12; values checked against AWS docs on 2026-10-12 (CloudFront Developer Guide, CloudFront API Reference, AWS CLI reference, AWS General Reference quotas). The marker
⚠️ Changed: <current>. Older material may say <old>.flags a value or behaviour that differs from the course or older practice tests: learn the current value.⚠️ unverifiedmarks a value that could not be confirmed or on which AWS pages disagree: never build an answer on it. (volatile) marks a value AWS changes often. Every change is listed in Changed vs older material; rows you confirm are added tonotes/current-facts.md.- Tier 4 (skim: developer-facing features only), bank target 15 questions. Domains: Troubleshooting and Optimization (primary), Security.
- How to use it:
/explain <topic>teaches from these sections (concept → exam facts → developer angle → traps → 3 check questions);/quiz cloudfrontasks bank questions whosesource_notelinks point at the## N.headings below;/drill cloudfrontfires short recall prompts fromnotes/cloudfront-cheat-sheet.md. Suggested loop: read a section and answer its practice questions before opening the answers →/explainwhat is still unclear →/quiz cloudfront→/drill cloudfront.
How CloudFront appears on DVA-C02
DVA-C02 treats CloudFront as the caching and security layer a developer puts in front of an application, not as a CDN architecture topic. Questions ask what you configure and why a request behaves the way it does:
- Caching correctness and hit ratio: which request values belong in the cache key, which policy forwards a value without splitting the cache, why users still see an old file, and how to refresh it (TTL, invalidation, versioned names).
- Locking down origins: an S3 bucket readable only through one distribution (OAC + bucket policy, plus the KMS key policy for SSE-KMS), an ALB that rejects direct traffic, a Lambda function URL behind OAC.
- Private content: signed URLs vs signed cookies, canned vs custom policies, key groups and safe key rotation.
- Code at the edge: CloudFront Functions vs Lambda@Edge under a latency, cost or capability constraint, and the deployment rules that make a Lambda@Edge association fail.
- Troubleshooting: reading
403,502,503and504responses, real-time and standard logs, edge function logs and metrics.
Typical question shapes: one scenario with one deciding constraint (LOWEST latency, LEAST operational overhead, MOST secure, MOST cost-effective); a status code or log symptom to diagnose; "Which TWO…" with five options; the exact setting, header, policy or CLI command that does the job.
Domain map: Troubleshooting and Optimization → §1 (origin errors, timeouts, failover), §2 (hit ratio, TTLs, invalidations), §5 (edge function errors, logs) · Security → §3 (origin protection, geo restriction, field-level encryption), §4 (signed URLs and cookies).
Out of scope here (owned by other modules): ACM certificates, SNI and TLS policies → notes/ec2-mastery-guide.md §9 (CloudFront viewer certificates live in us-east-1); S3 bucket policies, Cross-Region Replication, static website hosting, CORS and presigned URLs → notes/s3-guide.md §2, §5 and §9; KMS key policies → notes/security-encryption-guide.md §2; Route 53 alias records to a distribution → notes/route53-guide.md §2; security groups and prefix lists → notes/vpc-guide.md §2 and notes/ec2-mastery-guide.md §4; Lambda execution roles, versions and function URLs → notes/lambda-guide.md §4, §7 and §11; Kinesis Data Streams and Firehose → notes/sqs-sns-kinesis-guide.md §10 and §13; CloudWatch alarms → notes/monitoring-guide.md §5; API Gateway edge-optimized endpoints → notes/api-gateway-guide.md §2. Network design features (Anycast static IPs, BYOIP, multi-tenant distributions) are skipped.
| # | Topic | Why it is on the exam |
|---|---|---|
| 1 | Origins behaviors and origin failover | Route each path to the right origin; decode 502/503/504; timeouts and failover settings |
| 2 | Cache keys policies TTLs and invalidations | Correct content with the highest hit ratio; stale content and how to refresh it |
| 3 | Securing origins and content | OAC and KMS key policies, ALB protection, geo restriction, field-level encryption |
| 4 | Signed URLs signed cookies and key groups | Paid or per-user content; canned vs custom policy; key rotation without the root user |
| 5 | Edge functions and real time logs | CloudFront Functions vs Lambda@Edge; Lambda@Edge deployment rules; logs and metrics |
1. Origins behaviors and origin failover
Concept
- A distribution holds one or more origins (where the original content lives) and an ordered list of cache behaviors. Each behavior maps a URL path pattern to one origin or one origin group (a primary plus a secondary that receives the request again when the primary fails), together with its cache and origin policies, allowed methods, protocol rules, signers and edge functions.
- Origins a developer meets: an S3 bucket REST endpoint (kept private with OAC, §3); an S3 static website endpoint (a custom HTTP origin, so the bucket must be public); custom HTTP origins such as an internet-facing ALB, an EC2 instance, API Gateway or a Lambda function URL; and VPC origins, which let CloudFront reach an internal ALB, NLB or EC2 instance in a private subnet.
- CloudFront compares the request path with the behaviors in list order and applies the first match; the default behavior (
*) always comes last. A typical split:/api/*→ ALB with caching disabled,/assets/*→ S3 with long TTLs, default → the web application. Separate static and dynamic behaviors keep session cookies and headers out of the static cache key. - CloudFront vs S3 Cross-Region Replication: CloudFront keeps cached copies at edge locations everywhere for their TTL (static content read worldwide); CRR asynchronously copies objects into a bucket in each Region you configure (changing content that a few Regions need close by; see
notes/s3-guide.md§5).
Exam facts
- Path patterns:
*matches zero or more characters and?exactly one; patterns are case-sensitive, up to 255 characters, and the leading/is optional. Query strings and cookies play no part in the match, and an edge function that rewrites the URI does not change the selected behavior or origin. - Allowed methods come in three sets:
GET, HEAD;GET, HEAD, OPTIONS; or all seven (addsPUT, POST, PATCH, DELETE). OnlyGETandHEADresponses (optionallyOPTIONS) are cached; uploads also need the origin to allow the write (an OAC bucket policy withs3:PutObject, §3). Viewer protocol policy:allow-all,redirect-to-https(GET/HEADover HTTP get a301to the HTTPS URL, other methods a307) orhttps-only(HTTP gets403); origin protocol policy (custom origins):http-only,https-onlyormatch-viewer; S3 website endpoints accept only HTTP on port 80. - With HTTPS to a custom origin, the origin certificate must come from a trusted CA, present the full chain in the right order, be unexpired and match the origin domain name (or the forwarded
Host); otherwise CloudFront answers502withX-Cache: Error from cloudfront. - Origin timeouts: connection timeout 1–10 s (default 10) × connection attempts 1–3 (default 3) = up to 30 s before failover or an error. ⚠️ Changed: the response (read) timeout defaults to 30 s and can be set from 1 to 120 s, higher through a quota request. Older material may say 1–60 s. An optional response completion timeout (2025-07-30) caps the total wait; keep-alive defaults to 5 s.
- Origin failover covers only
GET,HEADandOPTIONS. It fires on the status codes you select (400, 403, 404, 416, 429, 500, 502, 503, 504), on a failed connection (when 503 is selected) or on a response timeout (when 504 is selected), so select both 503 and 504 to cover an unreachable or slow primary; each new request still goes to the primary first. ⚠️ Changed: 429 is now a selectable failover code. Older material may say the list ends without 429. - Errors CloudFront generates:
504= the origin is unreachable from CloudFront (security group, firewall, not on the internet) or slower than the response timeout; it is the code viewers get when the connection attempts run out on an origin outside a group or on the secondary, while the failover criteria above count a failed connection under 503;502= TLS handshake failure, DNS failure (NonS3OriginDnsError) or invalid edge function output;503= origin out of capacity or a Lambda@Edge throttle or execution error (§5). Stacking distributions (one as another's origin) is a documented403cause that AWS advises against; ⚠️ unverified: the troubleshooting page fails chains of two or more, while the quota page allows a chain of 2. - ⚠️ Changed: up to 75 cache behaviors and 100 origins per distribution (adjustable), and cacheable
GETresponses up to 50 GB. Older material may say 25 behaviors, 25 origins and 30 GB. - Price classes (
PriceClass_Alldefault,PriceClass_200,PriceClass_100) trade edge coverage for a lower bill; viewers far from the included locations see more latency. ⚠️ Changed: flat-rate pricing plans (Free, Pro, Business, Premium; AWS WAF bundled, no overage charges) exist since 2025-11-18 (volatile). Older material may say pay-as-you-go with price classes is the only pricing model. - Continuous deployment tests a configuration change on a staging distribution that receives up to 15% of traffic (weight-based, optional session stickiness) or only requests carrying an
aws-cf-cd-prefixed header; promote it withUpdateDistributionWithStagingConfig. Not available with HTTP/3.
Developer angle
UpdateDistribution replaces the whole configuration and requires the current ETag:
aws cloudfront get-distribution-config --id E1A2B3C4D5E6F7 > current.json
ETAG=$(jq -r '.ETag' current.json)
jq '.DistributionConfig' current.json > config.json # edit behaviors, origins, timeouts here
aws cloudfront update-distribution --id E1A2B3C4D5E6F7 \
--if-match "$ETAG" --distribution-config file://config.json
aws cloudfront wait distribution-deployed --id E1A2B3C4D5E6F7 # polls every 60 s
- Errors: a missing or invalid
If-Matchvalue →InvalidIfMatchVersion(400); a staleETag(someone changed the configuration after your read, so theIf-Matchprecondition evaluates to false) →PreconditionFailed(412): read the configuration again, redo the edit and resend; too many behaviors →TooManyCacheBehaviors(400). IAM actions:cloudfront:GetDistributionConfigandcloudfront:UpdateDistribution.
Traps
- Trap: "Move the default behavior to the top so it is checked first." → Reality:
*is always evaluated last; order matters among the other behaviors, and a broad pattern listed above a narrow one shadows it. - Trap: "Use OAC with the S3 static website endpoint." → Reality: website endpoints are custom origins: no OAC or OAI, and the bucket must allow public reads.
- Trap: "Origin failover also protects uploads." → Reality: only
GET,HEADandOPTIONSfail over; a failedPOSTorPUTreturns the error to the viewer. - Trap: "Raise the response timeout to fix every
504." → Reality: first check that CloudFront can reach the origin (security group, firewall), then fix the slow origin.
Practice questions
-
A developer changes the origin protocol policy of an internet-facing ALB origin from HTTP only to HTTPS only. Viewers immediately receive HTTP
502responses with the headerX-Cache: Error from cloudfront, although the targets behind the ALB are healthy. What is the MOST likely cause?- A. The ALB's HTTPS listener presents a self-signed certificate that does not match the origin domain name.
- B. The ALB security group does not allow inbound HTTPS from the CloudFront origin-facing managed prefix list.
- C. The 30-second origin response timeout is shorter than the time the application needs to build its responses.
- D. The cache behavior's viewer protocol policy still allows both HTTP and HTTPS.
-
A video platform uses an origin group with a primary and a secondary origin. When the primary is unreachable, viewers wait about 30 seconds before CloudFront serves segments from the secondary. Which TWO changes shorten this delay? (Select TWO.)
- A. Increase the origin response timeout of the primary origin to 120 seconds.
- B. Reduce the connection attempts of the primary origin to 1.
- C. Reduce the connection timeout of the primary origin to 2 seconds.
- D. Turn on Origin Shield for the primary origin.
- E. Change the price class of the distribution to
PriceClass_All.
Answers
- A. A failed TLS handshake with a custom origin (untrusted, expired or mismatched certificate) produces
502withError from cloudfront. B would show up as504timeouts, C causes504on slow responses, and D only concerns the viewer-to-CloudFront leg. - B, C. The default wait is 3 attempts × 10 s; fewer attempts and a shorter connection timeout make CloudFront give up on the primary sooner. A only lengthens waits on slow responses, D adds a caching layer without changing how long CloudFront waits for an unreachable primary, and E changes edge coverage, not origin timing.
2. Cache keys policies TTLs and invalidations
Concept
- The cache key identifies an object in an edge cache. By default it holds only the distribution's domain name and the URL path; query strings, headers and cookies stay out. Each value you add creates more copies of the same object and lowers the hit ratio, so add a value only when the origin's response really changes with it.
- A behavior combines three policy types: a cache policy (cache key contents and TTLs; every value in the key is also forwarded to the origin), an origin request policy (extra values the origin needs that must not split the cache, such as an analytics header) and a response headers policy (headers CloudFront adds to or removes from responses: CORS, security headers,
Server-Timing). - Freshness comes from the TTL settings combined with the origin's
Cache-ControlorExpiresheaders; an expired object is revalidated with a conditional request (304 Not Modifiedor a new copy). Early removal: an invalidation (by path, wildcard or cache tag) or, for frequent releases, versioned file names (app.4f2c9e.js), which AWS recommends.
Exam facts
- Cache policy options: headers none or a list; cookies and query strings none, a list, all except a list, or all (API values
none,whitelist,allExcept,all; the console says "Include specified …"). Up to 10 headers, 10 cookies and 10 query strings per policy and 20 custom cache policies per account (all adjustable). ⚠️ Changed: origin request policies also offer block lists ("All viewer headers except", "All cookies except", "All query strings except", since 2023-02-22). Older material may say only none, whitelist and all. - Managed policies to recognise: cache
CachingOptimized(min 1 s, default 86,400 s, max 31,536,000 s; only the normalizedAccept-Encodingin the key),CachingDisabled(all TTLs 0),UseOriginCacheControlHeaders(the origin's headers decide); origin requestAllViewerExceptHostHeader(for API Gateway and Lambda function URL origins, which expect their ownHost) andCORS-S3Origin; response headersSimpleCORS,CORS-With-Preflight,SecurityHeadersPolicy. - TTL precedence:
s-maxagebeatsmax-agefor CloudFront (browsers keep usingmax-age),max-agebeatsExpires, the result is clamped between the minimum and maximum TTL, and with no caching header the default TTL applies. ⚠️ Changed:MinTTLis required (0 is allowed),DefaultTTLdefaults to 86,400 s (24 h),MaxTTLdefaults to 31,536,000 s (1 year), and longer values are allowed (max-ageup to 100 years). Older material may say TTLs range from 0 s to 1 year. Cache-Control: no-cache,no-storeorprivatefrom the origin is honoured only when the minimum TTL is 0; with a minimum above 0 (such asCachingOptimized) CloudFront still caches for that minimum; all three TTLs at 0 disables caching. Viewers cannot force a refresh (CloudFront ignoresCache-ControlandPragmain viewer requests), error responses are cached for 10 s by default, andstale-while-revalidate/stale-if-errorare honoured.- Compression (Gzip or Brotli; Brotli when the viewer accepts both) needs
Compress= true on the behavior andEnableAcceptEncodingGzip/EnableAcceptEncodingBrotliin the cache policy, plus an object of 1,000–10,000,000 bytes withContent-Length, a compressible content type and status 200, 403 or 404. - Invalidation paths are case-sensitive, must start with
/in the API and CLI (only the console accepts paths without the slash), and allow*only as the last character. ⚠️ Changed: everything is/*in the API and CLI. Older material may say*. One path clears every header and cookie variant of the object; query-string variants need the query string in the path or a trailing*. The first 1,000 paths per month per account are free, then each path is charged; a wildcard path or a tag counts as one path however many objects it clears. Invalidations clear edge caches only, never browser or proxy caches; new file names reach both. - ⚠️ Changed: cache tag invalidation — set
CacheTagConfig.HeaderNameon the distribution (for S3, object metadata such asx-amz-meta-cache-tag), let the origin return comma-separated tags (≤ 50 per object, ≤ 256 characters, case-insensitive), then--paths "#tag"clears every object carrying the tag. Older material may say invalidation works by path only. ⚠️ unverified: invalidation throughput — the CloudFront quota page lists 150 paths or tags per second and 1 wildcard invalidation per second, while the General Reference still lists 3,000 file paths and 15 wildcard invalidations in progress; exceeding the limit returnsTooManyInvalidationsInProgress(400). - Measuring: additional distribution metrics (
CacheHitRate,OriginLatency, per-code error rates; extra cost;create-monitoring-subscription) and thex-edge-result-typelog field (Hit,RefreshHit,Miss,Error, …). Raise the hit ratio by keying on fewer values, keeping query string order and case consistent, usingCloudFront-Is-Mobile-Viewer-style headers instead ofUser-Agent, and enabling Origin Shield.
Developer angle
A cache policy that varies only by the page query string (policy.json), then a batch invalidation (IAM: cloudfront:CreateInvalidation on arn:aws:cloudfront::<account-id>:distribution/<id>; in a pipeline, upload the hashed asset names first, then invalidate only /index.html):
{ "Name": "catalog-page-key", "MinTTL": 0, "DefaultTTL": 300, "MaxTTL": 3600,
"ParametersInCacheKeyAndForwardedToOrigin": { "EnableAcceptEncodingGzip": true, "EnableAcceptEncodingBrotli": true,
"HeadersConfig": { "HeaderBehavior": "none" }, "CookiesConfig": { "CookieBehavior": "none" },
"QueryStringsConfig": { "QueryStringBehavior": "whitelist", "QueryStrings": { "Quantity": 1, "Items": ["page"] } } } }
aws cloudfront create-cache-policy --cache-policy-config file://policy.json
aws cloudfront create-invalidation --distribution-id E1A2B3C4D5E6F7 \
--paths "/index.html" "/images/*" "#catalog:shoes" # quote wildcards; "#tag" items need a CacheTagConfig
Traps
- Trap: "Put
Accept-Languagein the origin request policy because the origin needs it." → Reality: a value that changes the response must be in the cache key; otherwise the first cached variant is served to everyone. - Trap: "The origin sends
no-cache, so CloudFront never caches the object." → Reality: a minimum TTL above 0 wins. - Trap: "Invalidate
/images/*/thumb.jpg." → Reality: a*that is not the last character is matched literally. - Trap: "An invalidation also refreshes users' browsers." → Reality: only edge caches; versioned names reach browsers too.
Practice questions
-
A product catalog origin chooses the page to render only from the
pagequery string parameter. Marketing links addutm_sourceandutm_campaignparameters with many different values. Which cache policy setting returns correct pages with the highest cache hit ratio?- A. Query strings: All.
- B. Query strings: include only
page. - C. Query strings: None.
- D. Query strings: all except
page.
-
A team deploys a single-page application to an S3 origin that uses the
CachingOptimizedcache policy. After each release, some users keep running the previous JavaScript bundle for up to a day. Which TWO actions deliver new releases quickly at the LOWEST ongoing cost? (Select TWO.)- A. Schedule an invalidation of
/*every five minutes with an EventBridge rule. - B. Attach the
CachingDisabledcache policy to the default behavior. - C. Add a content hash to the JavaScript and CSS file names and reference them from
index.html. - D. Create an invalidation for
/index.htmlas the last step of each deployment. - E. Change the price class of the distribution to
PriceClass_100.
- A. Schedule an invalidation of
Answers
- B. Only
pagechanges the response, so onlypagebelongs in the key. A splits the cache on tracking values, C serves the same page for everypagevalue, and D keys on the tracking parameters while dropping the one that matters. - C, D. New file names bypass every cache, and invalidating the small entry document makes users load the new names. A invalidates constantly and triggers cache-miss storms, B sends every request to S3 (cost and latency), and E only reduces edge coverage.
3. Securing origins and content
Concept
- The aim is that viewers reach content only through CloudFront, so caching, AWS WAF, geo restriction and signed URLs always apply and nobody bypasses them at the origin.
- Origin access control (OAC) makes CloudFront sign each origin request with SigV4 as the service principal
cloudfront.amazonaws.com; the S3 bucket policy (or the Lambda resource policy) allows that principal only for your distribution's ARN. Origin access identity (OAI) is the legacy predecessor. Custom origins: an internet-facing ALB can require a secret header that only CloudFront adds and accept traffic only from CloudFront's managed prefix list; a VPC origin removes the public exposure entirely. - Viewer-side controls: geo restriction; an AWS WAF web ACL (scope
CLOUDFRONT, created through the us-east-1 endpoint; a blocked request gets403); AWS Shield Standard (automatic, no charge, network and transport layer DDoS protection); HTTPS with an ACM certificate from us-east-1 (notes/ec2-mastery-guide.md§9); field-level encryption for sensitive form fields; and ⚠️ Changed: viewer mutual TLS since 2025-11-24 (client certificates checked against a trust store; required, optional or passthrough mode). Older material may say CloudFront cannot authenticate viewers with certificates.
Exam facts
- ⚠️ Changed: OAC is the recommended access method (OAI is legacy) and also covers Lambda function URLs since 2024-04-11. Older material may say use an origin access identity. OAC supports S3 buckets in all Regions (opt-in Regions included), SSE-KMS objects and
PUT/DELETEto S3; OAI lacks these or needs workarounds. OAC settings: origin types3,lambda,mediastoreormediapackagev2; signing behavioralways(recommended),neverorno-override; signing protocolsigv4. With S3, OAC needs Object Ownership "Bucket owner enforced" (the default for new buckets; "Bucket owner preferred" if you still need ACLs). - The bucket policy grants
s3:GetObject(pluss3:PutObjectfor uploads) to"Service": "cloudfront.amazonaws.com"with"AWS:SourceArn": "arn:aws:cloudfront::<account-id>:distribution/<id>". SSE-KMS objects also need a KMS key policy statement for the same principal and condition withkms:Decrypt(pluskms:Encryptandkms:GenerateDataKey*for uploads); without it viewers get403. To move from OAI to OAC, allow both principals, switch the origin, then delete the OAI statement; an S3 website endpoint can use neither (custom origin, public bucket). - Lambda function URL behind OAC: the URL's
AuthTypemust beAWS_IAM; grantlambda:InvokeFunctionUrlandlambda:InvokeFunctiontocloudfront.amazonaws.comwith the distribution as source ARN; clients sendingPUTorPOSTmust addx-amz-content-sha256with the SHA-256 of the body. Pair it withAllViewerExceptHostHeader. - Internet-facing ALB: CloudFront adds a secret custom origin header, an ALB listener rule forwards only requests that carry it (default action: fixed
403), HTTPS protects the value, and rotation adds the new header before removing the old one. ⚠️ Changed: limit the ALB security group to the AWS-managed prefix listcom.amazonaws.global.cloudfront.origin-facing(IPv6:com.amazonaws.global.ipv6.cloudfront.origin-facing), or use a VPC origin. Older material may say allow-list the published CloudFront edge IP addresses yourself. - VPC origins: an internal ALB, an NLB (with a security group and no TLS listener) or an EC2 instance in a private subnet; the VPC needs an internet gateway (not used for routing); no gRPC and no Lambda@Edge origin request or origin response triggers; shareable with other accounts through AWS RAM.
- Geo restriction (
DistributionConfig.Restrictions.GeoRestriction:RestrictionTypewhitelist,blacklistornone, ISO 3166-1 alpha-2 codes) covers the whole distribution; blocked viewers get403(a custom error page is possible, cached 10 s by default). A third-party GeoIP database (about 99.8% accurate) decides, and viewers whose location is unknown are served. Per-path or city-level rules need an AWS WAF geo match rule, a function readingCloudFront-Viewer-Country, or a geolocation service plus signed URLs. - Field-level encryption encrypts up to 10 named fields of
application/x-www-form-urlencodedPOST/PUTbodies at the edge with your RSA 2048 public key; only the component that holds the private key decrypts them (AWS Encryption SDK). It needs HTTPS on both legs and all HTTP methods allowed; body ≤ 1 MB, field ≤ 16 KB. ⚠️ Changed: AWS lists it among legacy features (not offered on flat-rate plans). Older material may present it as a current feature.
Developer angle
Bucket policy for an OAC-protected origin, then the OAC itself and the Lambda function URL grant (run add-permission again with --action lambda:InvokeFunction and a new statement ID). Attach the OAC with update-distribution by setting OriginAccessControlId on the origin and clearing OriginAccessIdentity:
{ "Version": "2012-10-17", "Statement": [{ "Sid": "ReadThroughOneDistribution", "Effect": "Allow",
"Principal": { "Service": "cloudfront.amazonaws.com" }, "Action": "s3:GetObject",
"Resource": "arn:aws:s3:::media-assets-prod/*",
"Condition": { "StringEquals": { "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/E1A2B3C4D5E6F7" } } }] }
aws cloudfront create-origin-access-control --origin-access-control-config Name=media-oac,SigningProtocol=sigv4,SigningBehavior=always,OriginAccessControlOriginType=s3
aws lambda add-permission --function-name thumbs-api --statement-id cf-oac-url \
--action lambda:InvokeFunctionUrl --principal cloudfront.amazonaws.com \
--source-arn arn:aws:cloudfront::111122223333:distribution/E1A2B3C4D5E6F7
Traps
- Trap: "Grant the bucket to the OAC ID, or to
*with aReferercondition." → Reality: the principal is the CloudFront service with anAWS:SourceArncondition naming the distribution. - Trap: "
403on SSE-KMS objects means the bucket policy is wrong." → Reality: the KMS key policy is often missing the CloudFront principal. - Trap: "Geo restriction can block one path only." → Reality: it covers the whole distribution; use WAF or a function for finer rules.
- Trap: "OAC also protects an ALB origin." → Reality: OAC serves S3, Lambda function URLs and Elemental origins; protect an ALB with a secret header plus the prefix list, or a VPC origin.
Practice questions
-
A developer switches the objects in an S3 bucket origin to SSE-KMS with a customer managed key. The distribution uses OAC, and the bucket policy already allows
cloudfront.amazonaws.comwith the distribution's ARN asAWS:SourceArn. Every object now returns HTTP403through CloudFront. What should the developer do?- A. Replace the OAC with an origin access identity and grant that identity read access in the bucket policy.
- B. Disable S3 Block Public Access on the bucket and add a statement that makes every object publicly readable.
- C. Allow
cloudfront.amazonaws.comto usekms:Decryptin the KMS key policy, scoped byAWS:SourceArn. - D. Change the signing behavior of the OAC to
no-overrideso that the credentials sent by viewers reach S3.
-
A company serves an application through CloudFront from an internet-facing ALB. Security requires that the ALB accept requests only when they come through this distribution, without application code changes and with the LEAST operational overhead. Which TWO actions meet these requirements? (Select TWO.)
- A. Configure CloudFront to add a secret custom origin header, and add an ALB listener rule that forwards only requests carrying it, with a fixed
403default action. - B. Enable geo restriction on the distribution with an allow list of the company's countries.
- C. Create an origin access control of type
s3and attach it to the ALB origin. - D. Allow inbound HTTPS on the ALB security group only from the
com.amazonaws.global.cloudfront.origin-facingmanaged prefix list. - E. Schedule a Lambda function that rewrites the ALB security group from the published
ip-ranges.jsonfile.
- A. Configure CloudFront to add a secret custom origin header, and add an ALB listener rule that forwards only requests carrying it, with a fixed
Answers
- C. With SSE-KMS, CloudFront needs permission on the key as well as on the bucket. A fails because OAI does not support SSE-KMS, B weakens security and still leaves the key unusable for anonymous reads, and D only changes when CloudFront signs: viewers send no SigV4 credentials, and the key policy still denies CloudFront.
- A, D. The secret header proves a request came from CloudFront, and the managed prefix list blocks non-CloudFront sources with no maintenance. B filters CloudFront viewers by country and does nothing against requests sent straight to the ALB, C applies only to S3, Lambda URL and Elemental origins, and E rebuilds what the managed prefix list already does, adding operational overhead.
4. Signed URLs signed cookies and key groups
Concept
- For paid or per-user content (rentals, premium downloads, subscriber areas), your application authenticates the user and then hands out a signed URL (one file) or sets signed cookies (many files). The signature is made with a private key; CloudFront checks it with the matching public key in a trusted key group attached to the cache behavior, then checks the policy: expiry and, optionally, a start time and a viewer IP range.
- Signing protects only the CloudFront path: block direct origin access too (OAC, §3), or users can fetch the objects straight from S3. Behaviors set the scope: attach the key group only to the behaviors that serve private paths, and order them so that no unrestricted behavior matches those paths first. A common layout: a
/login*behavior to the application origin without signers (it authenticates the user and sets the cookies) and the default*behavior to S3 with the key group.
Exam facts
- Signed URL: individual files, or clients that cannot store cookies. Signed cookies: many files (HLS or DASH segments, a members area) or URLs that must stay unchanged. When a request carries both, the signed URL decides.
- Canned policy: expiry only, short URL with
Expires,SignatureandKey-Pair-Id. Custom policy: expiry plus an optional start (DateGreaterThan), one IPv4 address or CIDR (AWS:SourceIp; IPv6 is not supported, so keep IPv6 disabled on that distribution) and wildcards inResource; the URL carries the base64Policy. Times are Unix epoch seconds (UTC). Signed cookies useCloudFront-Expires(canned) orCloudFront-Policy(custom), plusCloudFront-SignatureandCloudFront-Key-Pair-Id, set withSecureandHttpOnlybefore the first protected request. - ⚠️ Changed: keys can be RSA 2048 or ECDSA 256 (PEM), and the signature can use SHA-256 with
Hash-Algorithm=SHA256(cookieCloudFront-Hash-Algorithm); SHA-1 remains the default. Older material may say RSA 2048 with SHA-1 only. - ⚠️ Changed: sign with trusted key groups — public keys uploaded through the API, governed by IAM and rotatable by automation; up to 5 public keys per group, 4 key groups per cache behavior (some AWS pages say per distribution) and 10 per account (adjustable). The account-wide CloudFront key pair shown in the course is the legacy signer: root user only, console only, at most 2 active per account. Older material may say only the root user can create the signing key pair.
- CloudFront checks the expiry when a request starts: a download that began before the deadline completes, while later range
GETs fail; lifetimes range from minutes (rentals) to years (internal documents for known users). Rejections return403: missing, expired or altered signature, a query string added after signing, or a key outside the trusted key groups of the matched behavior.OPTIONSrequests are not signature-checked (CORS preflight), so limit allowed methods toGET, HEADwhen CORS is not needed; URLs that already useExpires,Policy,Signature,Key-Pair-IdorHash-Algorithmas their own query parameters cannot be protected. - CloudFront signed URL vs S3 presigned URL: the CloudFront one passes through the edge cache, works for any origin, uses key-group keys and supports start-time and IP conditions; an S3 presigned URL goes straight to S3 and carries the permissions of the IAM principal whose credentials signed it (details:
notes/s3-guide.md§9).
Developer angle
Create the key pair and the key group (pubkey-config.json holds CallerReference, Name and EncodedKey, the PEM text; then put the key group ID into the behavior's TrustedKeyGroups with update-distribution), and sign in the application with the AWS SDK for JavaScript v3 (getSignedCookies from the same package returns the cookie values):
openssl genrsa -out private_key.pem 2048
openssl rsa -pubout -in private_key.pem -out public_key.pem
aws cloudfront create-public-key --public-key-config file://pubkey-config.json # returns PublicKey.Id
aws cloudfront create-key-group --key-group-config Name=premium-signers,Items=K2JCJMDEHXQW5F
import { getSignedUrl } from "@aws-sdk/cloudfront-signer";
const signedUrl = getSignedUrl({ url: "https://d111111abcdef8.cloudfront.net/premium/ep01.mp4",
keyPairId: "K2JCJMDEHXQW5F", // public key ID from the trusted key group
privateKey: process.env.CLOUDFRONT_PRIVATE_KEY, // injected from Secrets Manager at startup; never commit it
dateLessThan: new Date(Date.now() + 15 * 60 * 1000).toISOString() });
Traps
- Trap: "Use the root user's CloudFront key pair." → Reality: that is the legacy signer; trusted key groups avoid the root user and allow API-driven rotation.
- Trap: "Email a signed cookie to give one customer a download link." → Reality: cookies need a browser session on your domain; send a signed URL.
- Trap: "Rotate by replacing the public key in one step." → Reality: add the new key, switch signing, and remove the old key only after the longest URL lifetime has passed.
- Trap: "Signed URLs alone keep the S3 objects private." → Reality: the bucket must also be restricted to the distribution's OAC.
Practice questions
-
A streaming service delivers HLS video to subscribers through CloudFront. Each title consists of a manifest and hundreds of segment files whose URLs the player builds from the manifest, so the application cannot change them. Which approach restricts the videos to signed-in subscribers with the LEAST development effort?
- A. Generate a CloudFront signed URL for every segment file and rewrite each manifest on every request.
- B. Generate S3 presigned URLs for every segment file by using the IAM role of the application servers.
- C. Enable geo restriction with an allow list of the countries where the service is sold.
- D. Issue signed cookies with a custom policy whose resource is a wildcard for the title's path.
-
A team signs CloudFront URLs with a CloudFront key pair that the root user created years ago. A new policy forbids root user activity and requires key rotation every 90 days without breaking URLs that are still valid. Which TWO actions should the developer take? (Select TWO.)
- A. Replace the CloudFront signed URLs with S3 presigned URLs created with an IAM user's access keys.
- B. Upload a new public key with
create-public-key, add it to a trusted key group on the cache behavior, and sign with its private key. - C. Delete the old public key from the key group as soon as the new key is uploaded.
- D. Store the private key as an object in the origin bucket so that every application server can read it.
- E. At each rotation, add the new public key to the key group, switch signing to it, and remove the old key after the longest URL lifetime.
Answers
- D. One set of signed cookies with a wildcard resource covers every file of the title without touching URLs. A needs per-segment signing and manifest rewriting, B bypasses CloudFront and still changes every URL, and C restricts by country, not by subscription.
- B, E. Key groups are managed through the API and IAM without the root user, and the add–switch–wait–remove order keeps outstanding URLs valid. A uses long-term IAM user keys and skips the edge cache, C breaks URLs that are still valid, and D exposes the private key.
5. Edge functions and real time logs
Concept
- CloudFront Functions run small JavaScript functions at CloudFront edge locations on the viewer request and viewer response events, in well under a millisecond and at very high scale. Lambda@Edge runs Node.js or Python Lambda functions, created in us-east-1 and replicated by CloudFront, on all four events (viewer request, origin request, origin response, viewer response), with network access, more memory and access to the request body.
- Viewer events run on every request (before the cache lookup, or on the way back to the viewer); origin events run only on cache misses, between CloudFront and the origin. For visibility, standard (access) logs arrive in delayed batches, real-time logs reach Kinesis Data Streams within seconds, and edge functions write their own logs to CloudWatch Logs.
Exam facts
| Capability | CloudFront Functions | Lambda@Edge |
|---|---|---|
| Runtime and events | JavaScript: cloudfront-js-1.0 (ES 5.1 base) or cloudfront-js-2.0 (adds const/let, async/await, Buffer and KeyValueStore; ⚠️ Changed: since 2023-11-21. Older material may say ES 5.1 only, no data store); viewer request and viewer response only |
Node.js or Python; viewer request, viewer response, origin request, origin response |
| Run time and scale | Sub-millisecond, reported as compute utilization 0–100; millions of requests per second | Origin events up to 30 s; viewer events ⚠️ unverified: up to 30 s per the CloudFront Developer Guide, 5 s per the General Reference quota table (older material: 5 s); 10,000 requests per second per Region, sharing that Region's Lambda concurrency (1,000 by default) |
| Memory and code size | 2 MB; 10 KB of code, not adjustable (keep data in KeyValueStore) | 128 MB on viewer events, up to 10,240 MB on origin events; ⚠️ Changed: 50 MB compressed on every event. Older material may say 1 MB on viewer events. |
| Network, file system, request body | None | Yes (Include body: base64, truncated at 40 KB on viewer and 1 MB on origin events) |
| Data and viewer headers | KeyValueStore (runtime 2.0; store ≤ 5 MB, key ≤ 512 bytes, value ≤ 1 KB, 1 store per function); geolocation and device headers available | Any AWS service through the SDK; CloudFront geolocation and device headers only on origin events |
- Lambda@Edge rules: the function lives in us-east-1; the association uses a numbered version ARN (not
$LATEST, not an alias); the execution role trusts bothlambda.amazonaws.comandedgelambda.amazonaws.com. Not supported: environment variables, layers, VPC access, DLQs, provisioned concurrency, container images, arm64, more than 512 MB of ephemeral storage, X-Ray. Associating a trigger needslambda:GetFunction,lambda:EnableReplication*,iam:CreateServiceLinkedRole(first time) andcloudfront:UpdateDistribution; replicas disappear a few hours after the last association is removed, and only then can the function or version be deleted. - Per cache behavior: one function per event type, and no mixing of CloudFront Functions and Lambda@Edge on the viewer events (a CloudFront Function on viewer request plus Lambda@Edge on origin request is allowed); viewer response functions do not run when the origin returns 400 or higher. ⚠️ Changed: CloudFront Functions (runtime 2.0, viewer request) can switch the origin with
cf.updateRequestOrigin()(2024-11-21) orcf.selectRequestOriginById()(2025-04-02), running on every request; Lambda@Edge origin request does it only on cache misses and can look up data first. Older material may say only Lambda@Edge can change the origin. - Errors: invalid function output or a change to a read-only or disallowed header →
502; Lambda@Edge throttling or timeout (LambdaLimitExceeded) and function execution errors →503. Logs and metrics: Lambda@Edge logs land in CloudWatch Logs of the Region where the replica ran, default group/aws/lambda/us-east-1.<function-name>; CloudFront Functionsconsole.log()output goes to us-east-1, group/aws/cloudfront/function/<name>, for theLIVEstage only. All CloudFront and edge function metrics (FunctionInvocations,FunctionComputeUtilization,FunctionThrottles,FunctionExecutionErrors,FunctionValidationErrors) are read in us-east-1. - Real-time logs: delivered only to Kinesis Data Streams (
StreamTypeKinesis) within seconds, best effort; you choose a sampling rate of 1–100 % (whole numbers), the fields and the cache behaviors (RealtimeLogConfigArn). The IAM role trustscloudfront.amazonaws.comand allowskinesis:PutRecord,kinesis:PutRecords,kinesis:DescribeStreamandkinesis:DescribeStreamSummary(pluskms:GenerateDataKeyfor an encrypted stream). Missing records → check that role and the shard count (throttling); 150 configurations per account; extra charge. - ⚠️ Changed: standard logging v2 (2024-11-20) delivers access logs to CloudWatch Logs, Amazon Data Firehose or S3 (JSON, plain, W3C, raw or Parquet), configured through the CloudWatch Logs delivery APIs in us-east-1. Older material may say standard logs go only to an S3 bucket (that legacy option still exists) and may call the service Kinesis Data Firehose.
Developer angle
The lifecycle of a viewer request function (runtime 2.0) that maps directory URLs to index.html on an S3 REST origin, and the numbered version that a Lambda@Edge association needs:
aws cloudfront create-function --name dir-index --function-config Comment="Append index.html",Runtime=cloudfront-js-2.0 --function-code fileb://dir-index.js
ETAG=$(aws cloudfront describe-function --name dir-index --query ETag --output text)
aws cloudfront test-function --name dir-index --if-match "$ETAG" --stage DEVELOPMENT --event-object fileb://event.json
aws cloudfront publish-function --name dir-index --if-match "$ETAG" # DEVELOPMENT -> LIVE
aws lambda publish-version --function-name origin-router --region us-east-1 # put the returned FunctionArn (...:origin-router:7) in LambdaFunctionAssociations
Traps
- Trap: "Call DynamoDB from a CloudFront Function." → Reality: CloudFront Functions have no network access; use Lambda@Edge, or KeyValueStore for small read-only data.
- Trap: "Associate
$LATESTor thelivealias." → Reality: Lambda@Edge needs a numbered version ARN from us-east-1. - Trap: "Read Lambda@Edge logs in us-east-1." → Reality: each replica logs in the Region where it ran.
- Trap: "Send real-time logs straight to S3 or Firehose." → Reality: the only destination is Kinesis Data Streams; Amazon Data Firehose (formerly Kinesis Data Firehose) can read from the stream.
Practice questions
-
An e-commerce site receives product URLs whose query parameters arrive in random order and mixed case, which lowers the cache hit ratio. A developer wants to sort and lowercase the parameters before CloudFront looks up the cache, at the LOWEST latency and cost. What should the developer do?
- A. Associate a CloudFront Function with the viewer request event.
- B. Associate a Lambda@Edge function with the origin request event.
- C. Associate a Lambda@Edge function with the viewer request event.
- D. Change the cache policy to include all query strings in the cache key.
-
A developer wrote a Node.js function in eu-west-1 and tries to associate
arn:aws:lambda:eu-west-1:111122223333:function:origin-router:$LATESTwith the origin request event of a cache behavior. CloudFront rejects the association. Which TWO actions are required? (Select TWO.)- A. Configure reserved concurrency on the function so that CloudFront can scale it.
- B. Re-create the function in the US East (N. Virginia) Region.
- C. Create an alias named
liveand associate the alias ARN instead. - D. Publish a version of the function and associate the numbered version ARN.
- E. Attach the function to a VPC in each Region where it will run.
Answers
- A. Normalisation must happen before the cache lookup, and a CloudFront Function on viewer request is the cheapest, fastest place for header and query string rewrites. B runs after the lookup and only on misses, C works but costs more and adds latency, and D lowers the hit ratio further.
- B, D. Lambda@Edge functions must live in us-east-1 and be referenced by a numbered version. A does not affect the association, C fails because aliases are not accepted, and E is impossible because Lambda@Edge does not support VPC access.
Quick 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, which is evaluated last. - If you see "static files read worldwide" vs "a copy of changing objects kept in two more Regions", think CloudFront vs S3 Cross-Region Replication.
- If you see
502withX-Cache: Error from cloudfrontafter enabling HTTPS to a custom origin, think origin certificate problem (self-signed, expired, wrong name, missing chain). - If you see
504from CloudFront, think the origin is unreachable from CloudFront (security group, firewall) or slower than the response timeout. - If you see
403after putting one distribution in front of another, think stacked distributions: remove the extra hop. - If you see "fail over to the secondary origin faster", think fewer connection attempts and a shorter connection timeout.
- If you see "test a CDN change on a small share of live traffic", think continuous deployment with a staging distribution (up to 15%).
- 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 but the response does not change with it", think origin request policy.
- If you see an API Gateway or Lambda function URL origin failing because of the forwarded
Host, thinkAllViewerExceptHostHeader. - If you see "users still run old JavaScript after a release", think versioned file names plus an invalidation of
/index.html. - If you see "remove every cached object of one product, whatever its URL", think cache tag invalidation (
#tagpaths). - If you see origin
Cache-Control: no-cachebeing ignored, think a minimum TTL above 0. - If you see "add CORS or security headers without touching the origin", think a response headers policy.
- If you see "S3 content reachable only through CloudFront", think OAC plus a bucket policy for
cloudfront.amazonaws.comwithAWS:SourceArn. - If you see
403on SSE-KMS objects behind OAC, think the KMS key policy lackskms:Decryptforcloudfront.amazonaws.com. - If you see an S3 static website endpoint as origin, think custom origin, public bucket, no OAC.
- If you see "the ALB must accept only CloudFront traffic", think secret custom header + listener rule + managed prefix list, or a VPC origin.
- If you see "block whole countries for licensing reasons", think geo restriction; for one path or one city, think AWS WAF or a function.
- If you see "encrypt card numbers at the edge so only the payment service can read them", think field-level encryption.
- If you see "one private file per user", think signed URL; "many files or URLs that must not change", think signed cookies.
- If you see "sign without the root user and rotate keys automatically", think trusted key groups.
- If you see "limit a signed link to an IP range or a future start time", think custom policy.
Edge code and logs (§5)
- If you see "rewrite URLs, set headers or normalise the cache key on every request at the lowest cost", think CloudFront Function on viewer request.
- If you see "call DynamoDB or an external API, read the body, or run for seconds", think Lambda@Edge (origin events to run only on cache misses).
- If you see a rejected Lambda@Edge association, think us-east-1, numbered version,
edgelambda.amazonaws.comin the trust policy. - If you see "per-request logs within seconds for a live dashboard", think real-time logs to Kinesis Data Streams.
- If you see "access logs in CloudWatch Logs", think standard logging v2.
Changed vs older material
Learn the Current column; older practice material may still show the Course / older material value. Rows you confirm during /ingest are added to notes/current-facts.md.
| Topic | Course / older material | Current (verified 2026-10-12) | Source |
|---|---|---|---|
| §1 · Cache behaviors and origins per distribution | 25 behaviors, 25 origins | 75 behaviors and 100 origins per distribution (adjustable) | AWS docs |
| §1 · Origin response timeout | 1–60 s, default 30 s | 1–120 s, default 30 s, higher through a quota request; optional response completion timeout (2025-07-30) | AWS docs |
| §1 · Largest cacheable object | 30 GB (earlier 20 GB) | 50 GB per GET response |
AWS docs |
| §1 · Origin failover status codes | 400, 403, 404, 416, 500, 502, 503, 504 | Adds 429 | AWS docs |
| §1 · Pricing model | Pay-as-you-go with three price classes | Price classes unchanged (PriceClass_All, PriceClass_200, PriceClass_100); flat-rate plans Free, Pro, Business, Premium since 2025-11-18 |
AWS docs |
| §2 · Policy options and naming | Cache policy headers None–Whitelist; origin request policy None–Whitelist–All | Console "Include specified/following"; API still whitelist; origin request policies add "all except" block lists (2023-02-22) |
AWS docs |
| §2 · TTL range | 0 s to 1 year | MinTTL required (0 allowed); DefaultTTL defaults to 86,400 s and MaxTTL to 31,536,000 s; longer values allowed (max-age up to 100 years) |
AWS docs |
| §2 · Invalidating everything | * |
/*: API and CLI invalidation paths must start with / (only the console accepts them without) |
AWS docs |
| §2 · Invalidation methods | Paths and wildcards (/*, /images/*) |
Also cache tags: CacheTagConfig + #tag items in CreateInvalidation |
AWS docs |
| §2 · Invalidation quotas | 3,000 file paths and 15 wildcard paths in progress | ⚠️ unverified: quota page says 150 paths or tags per second and 1 wildcard per second; General Reference still says 3,000 / 15 | AWS docs |
| §3 · S3 origin access | Origin access identity (OAI) | OAC recommended (SSE-KMS, PUT/DELETE, all Regions); OAI legacy; OAC also for Lambda function URLs (2024-04-11) |
AWS docs |
| §3 · Restricting an ALB or EC2 origin | Allow the published edge IP ranges in the security group | Managed prefix list com.amazonaws.global.cloudfront.origin-facing (2022-02-07) plus a secret header, or VPC origins (2024-11-20) |
AWS docs |
| §3 · Field-level encryption status | Presented as a current feature, up to 10 fields | Still up to 10 fields; AWS lists it among legacy features not supported on flat-rate plans | AWS docs |
| §3 · Client certificates from viewers | CloudFront cannot authenticate viewers with certificates | Viewer mutual TLS since 2025-11-24 (trust stores; required, optional or passthrough mode) | AWS docs |
| §4 · Signers | Account-wide CloudFront key pair managed by the root user | Trusted key groups (API and IAM, recommended); root key pairs legacy, at most 2 active | AWS docs |
| §4 · Keys and hash algorithm | RSA 2048 with SHA-1 | RSA 2048 or ECDSA 256; optional SHA-256 via Hash-Algorithm (default SHA-1) |
AWS docs |
| §5 · Lambda@Edge package size on viewer events | 1 MB | 50 MB compressed on every event | AWS docs |
| §5 · Lambda@Edge timeout on viewer events | 5 s | ⚠️ unverified: Developer Guide says up to 30 s; General Reference quota table still says 5 s | AWS docs |
| §5 · CloudFront Functions runtime and data | ES 5.1 only, no data store | Runtime 2.0 (selected ES6–ES12 features, async/await) and KeyValueStore (2023-11-21) |
AWS docs |
| §5 · Changing the origin per request | Only a Lambda@Edge origin request function | Also CloudFront Functions helpers cf.updateRequestOrigin() (2024-11-21) and cf.selectRequestOriginById() (2025-04-02) |
AWS docs |
| §5 · Standard log destinations | An S3 bucket only; Firehose called Kinesis Data Firehose | Standard logging v2 (2024-11-20): CloudWatch Logs, Amazon Data Firehose or S3; legacy S3 logging still available | AWS docs |