Skip to main content

Amazon CloudFront

Core concept: CloudFront is a global CDN โ€” caches content at 400+ edge locations worldwide, reducing latency and origin load.


Key Conceptsโ€‹

TermDescription
DistributionA CloudFront deployment with origins + behaviors
OriginWhere CloudFront fetches content from (S3, ALB, EC2, API Gateway, custom HTTP)
Edge LocationCache server close to end users (400+ worldwide)
Cache BehaviorURL path pattern โ†’ cache settings (e.g., /api/* = no cache, /static/* = 1 day)
TTLHow long content stays cached (default 24h, min 0s, max 1 year)
InvalidationForce-purge cached content (/* or /path/file.js)

Originsโ€‹

Distribution
โ”œโ”€โ”€ Origin 1: S3 Bucket (static assets)
โ”œโ”€โ”€ Origin 2: ALB (dynamic API)
โ””โ”€โ”€ Origin 3: Custom HTTP (on-premises)

Cache Behaviors:
/api/* โ†’ Origin 2 (ALB), cache TTL = 0
/static/* โ†’ Origin 1 (S3), cache TTL = 86400
/* โ†’ Origin 1 (S3) [default]

S3 + CloudFront โ€” Origin Access Control (OAC)โ€‹

Keep S3 bucket private โ€” only CloudFront can access it:

// S3 Bucket Policy โ€” allow only CloudFront OAC
{
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/EDFDVBD6EXAMPLE"
}
}
}
OAC vs OAI

OAC (Origin Access Control) is the newer, recommended replacement for OAI (Origin Access Identity). OAC supports SSE-KMS encrypted S3 buckets; OAI does not.


Signed URLs vs Signed Cookiesโ€‹

FeatureSigned URLSigned Cookie
ScopeSingle fileMultiple files / entire distribution
Use casePresigned download linkPremium video streaming, gated content
ImplementationPer URLSet once in browser cookie
// Generate CloudFront Signed URL (Java SDK)
CloudFrontUtilities cloudFrontUtilities = CloudFrontUtilities.create();

SignedUrl signedUrl = cloudFrontUtilities.getSignedUrlWithCannedPolicy(
SignUrlRequest.builder()
.resourceUrl("https://d111111abcdef8.cloudfront.net/private/video.mp4")
.keyPairId("APKAEIBAERJR2EXAMPLE")
.privateKey(Path.of("/path/to/private-key.pem"))
.expirationDate(Instant.now().plus(Duration.ofHours(2)))
.build());

Cache Invalidationโ€‹

# Invalidate specific path
aws cloudfront create-invalidation \
--distribution-id EDFDVBD6EXAMPLE \
--paths "/index.html" "/css/*"

# Invalidate everything (first 1000 paths/month free, then $0.005/path)
aws cloudfront create-invalidation \
--distribution-id EDFDVBD6EXAMPLE \
--paths "/*"
Version files instead of invalidating

Use cache-busting filenames (app.v2.js, style.abc123.css) instead of invalidations โ€” faster, cheaper, no propagation delay.


Lambda@Edge vs CloudFront Functionsโ€‹

CloudFront FunctionsLambda@Edge
RuntimeJavaScript (ES5.1)Node.js, Python
TriggersViewer request/response onlyViewer + Origin request/response
Execution location400+ edge locationsRegional edge (13 locations)
Max execution time1 ms5 seconds (viewer), 30s (origin)
Max memory2 MB128 MB โ€“ 10 GB
Use caseURL rewrites, header manipulation, A/B routing, simple authComplex auth, body modification, DB lookups
Cost~6ร— cheaperMore expensive

CloudFront Functions โ€” URL Rewrite Exampleโ€‹

// CloudFront Function โ€” rewrite /blog/post-1 โ†’ /blog/index.html
function handler(event) {
var request = event.request;
var uri = request.uri;

// Add index.html to paths without extension
if (uri.endsWith('/')) {
request.uri += 'index.html';
} else if (!uri.includes('.')) {
request.uri += '/index.html';
}

return request;
}

HTTPS Enforcementโ€‹

// Force HTTPS redirect at CloudFront level
{
"ViewerProtocolPolicy": "redirect-to-https",
// Options: allow-all, https-only, redirect-to-https
}

Cache Key Customizationโ€‹

// Cache based on query string, headers, cookies
{
"CachePolicyConfig": {
"ParametersInCacheKeyAndForwardedToOrigin": {
"EnableAcceptEncodingGzip": true,
"QueryStringsConfig": {
"QueryStringBehavior": "whitelist",
"QueryStrings": { "Items": ["version", "locale"] }
},
"HeadersConfig": {
"HeaderBehavior": "none" // Don't cache per-header (unless needed)
}
}
}
}

๐Ÿงช Practice Questionsโ€‹

Q1. A developer hosts a React SPA in S3, served via CloudFront. The S3 bucket must remain private. How should they configure this?

A) Make the S3 bucket public
B) Use a signed URL for every request
C) Configure Origin Access Control (OAC) on the distribution and a bucket policy allowing only CloudFront
D) Enable S3 static website hosting

โœ… Answer & Explanation

C โ€” OAC (or legacy OAI) makes CloudFront the only allowed origin for the private S3 bucket. The bucket policy allows s3:GetObject only from the specific CloudFront distribution's service principal.


Q2. Users need time-limited access to a private video (single file) stored behind CloudFront. What feature should the developer use?

A) S3 Presigned URL
B) CloudFront Signed URL with an expiration
C) CloudFront Signed Cookie
D) S3 Bucket Policy with IP restriction

โœ… Answer & Explanation

B โ€” CloudFront Signed URL grants time-limited access to a single resource (specific file). Signed Cookies are better for multiple files (e.g., an entire video library). S3 Presigned URL bypasses CloudFront, losing CDN benefits.


Q3. A team needs to perform a simple URL rewrite (add /index.html to directory paths) at the CloudFront edge. Which is the MOST cost-effective option?

A) Lambda@Edge
B) API Gateway with redirect
C) CloudFront Functions
D) S3 Static Website Hosting redirect rules

โœ… Answer & Explanation

C โ€” CloudFront Functions execute at 400+ edge locations with sub-millisecond latency and are ~6ร— cheaper than Lambda@Edge. They're perfect for simple URL manipulations, header rewrites, and lightweight auth checks.


๐Ÿ”— Resourcesโ€‹