The Cloud Computing domain covers what a CDN is and does, generically. This is what actually configuring one on AWS looks like — a distribution, one or more origins, and the cache-behavior rules that decide which requests get cached and which get forwarded straight through.
3 min read
A CloudFront distribution is the top-level object tying everything together. It has one or more origins (where content actually comes from — an S3 bucket, an ALB, any HTTP server) and one or more cache behaviors (rules mapping URL path patterns to which origin handles them, and how caching should work for that pattern).
This is the practical shape of the CDN concept from the Cloud Computing domain's CDN lesson: static assets (images, JS bundles) served from an S3 origin with long cache times, API calls forwarded to a dynamic origin with caching mostly or entirely disabled, all through the same distribution and the same custom domain.
resource "aws_cloudfront_distribution" "main" {
enabled = true
origin {
domain_name = aws_s3_bucket.static.bucket_regional_domain_name
origin_id = "s3-static"
s3_origin_config {
origin_access_identity = aws_cloudfront_origin_access_identity.main.cloudfront_access_identity_path
}
}
origin {
domain_name = aws_lb.api.dns_name
origin_id = "alb-api"
custom_origin_config {
http_port = 80
https_port = 443
origin_protocol_policy = "https-only"
origin_ssl_protocols = ["TLSv1.2"]
}
}
default_cache_behavior {
target_origin_id = "s3-static"
viewer_protocol_policy = "redirect-to-https"
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
forwarded_values {
query_string = false
cookies { forward = "none" }
}
min_ttl = 0
default_ttl = 86400
max_ttl = 31536000
}
ordered_cache_behavior {
path_pattern = "/api/*"
target_origin_id = "alb-api"
viewer_protocol_policy = "https-only"
allowed_methods = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"]
cached_methods = ["GET", "HEAD"]
forwarded_values {
query_string = true
headers = ["Authorization"]
cookies { forward = "all" }
}
min_ttl = 0
default_ttl = 0 # effectively uncached — the API sets its own Cache-Control
max_ttl = 0
}
}Origin Access Identity (or its newer replacement, Origin Access Control) is a CloudFront-managed identity that's granted read access to a private S3 bucket, so the bucket never needs to be made public — users only ever reach the content through CloudFront, and direct requests to the bucket's own S3 URL are denied. This is the correct pattern for static-asset origins: keep the S3 bucket private (per the S3 lesson's default-private guidance), and let OAI/OAC be the only thing with read access to it.
resource "aws_cloudfront_origin_access_identity" "main" {}
resource "aws_s3_bucket_policy" "static" {
bucket = aws_s3_bucket.static.id
policy = jsonencode({
Statement = [{
Effect = "Allow"
Principal = { AWS = aws_cloudfront_origin_access_identity.main.iam_arn }
Action = "s3:GetObject"
Resource = "${aws_s3_bucket.static.arn}/*"
}]
})
}Exactly like the Cloud Computing domain's CDN lesson warns generically — a header, cookie, or query string that changes the response but isn't included in what CloudFront varies on will cause the wrong cached response to be served to the wrong user. The forwarded_values block above is where that's controlled: query_string = true includes query strings in the cache key (so ?page=1 and ?page=2 cache separately), headers = ["Authorization"] means CloudFront will vary its cache by that header specifically rather than caching one response for everyone regardless of who's authenticated — critical for a per-user API response, and exactly the kind of misconfiguration that leaks one user's data to another if it's left off.
An invalidation manually purges cached content from CloudFront's edge locations before its TTL naturally expires — needed when content at a fixed URL changes and can't wait for the cache to expire on its own (as opposed to the versioned-URL strategy covered generically in the Cloud Computing domain, which avoids needing invalidation at all for assets that can have a new filename per deploy).
aws cloudfront create-invalidation \
--distribution-id E1A2B3C4D5E6F7 \
--paths "/index.html" "/api/config.json"Invalidations aren't instant (can take minutes to propagate to all edge locations globally) and, beyond a monthly free allowance, cost money per path — exactly why the versioned-URL approach is preferred for anything that can use it, with invalidation reserved for the smaller set of fixed-URL content that genuinely needs it.
Check your understanding
A quick comprehension check — not tracked, not graded, just for you.
1. What does an Origin Access Identity/Control (OAI/OAC) enable?
2. Why must an Authorization header be explicitly included in CloudFront's forwarded values for a per-user API?
3. What does a CloudFront cache behavior actually determine?
4. Why is the versioned-URL strategy generally preferred over CloudFront invalidation?
AWS