Clients request derivatives by query string; CloudFront caches per object and S3 holds the originals. This is the demo that works until the cache key explodes.
A CloudFront Function on viewer-request sorts and clamps the allowlisted params and strips junk, so utm and session noise never mint new cache objects. Runs in ~1 ms on every request.
03
Transform on miss, with coalescing
flowchart TD
Client([Client]) --> CFF[CloudFront Function\nnormalize key]
CFF --> CF[CloudFront edge cache]
CF -->|hit| Client
CF -->|miss| Shield[Origin Shield\ncoalesce misses]
Shield --> LE[Lambda at edge\ntransform origin-request]
LE --> S3[(S3 Originals)]
S3 --> LE
LE --> Shield --> CF
Origin Shield collapses concurrent misses for the same key into one fetch; Lambda at edge on origin-request transforms the original only on a miss. Hits never touch compute.
04
Multi-region origins and failover
flowchart TD
Client([Client]) --> CFF[CloudFront Function]
CFF --> CF[CloudFront edge cache]
CF -->|hit| Client
CF -->|miss| Shield[Origin Shield]
Shield --> LE[Lambda at edge transform]
subgraph Origins[Origin Group - failover on 5xx]
S3a[(S3 us-east-1)]
S3b[(S3 eu-west-1)]
S3c[(S3 ap-northeast-1)]
end
LE --> S3a
S3a -.CRR.-> S3b
S3a -.CRR.-> S3c
LE -.failover.-> S3b
S3 originals replicate to three regions via CRR; CloudFront Origin Groups fail the source fetch over to the next replica on 5xx, per request, with no DNS-TTL lag.
05
Pre-compute path and invalidation control
flowchart TD
Upload([Upload]) --> S3a[(S3 Originals)]
S3a -->|S3 event| SF[Step Functions\nrender variants and invalidate]
SF --> S3v[(S3 Pre-computed variants)]
SF -->|batched| INV[CloudFront Invalidation]
Client([Client]) --> CFF[CloudFront Function]
CFF --> CF[CloudFront edge cache]
CF -->|hit| Client
CF -->|miss| Shield[Origin Shield]
Shield --> LE[Lambda at edge transform\nfallback only]
LE --> S3v
LE --> S3a
On upload, an S3 event drives Step Functions to render the standard variants to S3, turning most requests into plain GETs. Step Functions also batches takedown invalidations within CloudFront quotas.
06
Security and tenant isolation layer
flowchart TD
Client([Client]) --> WAF[AWS WAF\nhotlink and rate limit]
WAF --> CFF[CloudFront Function\nsigned URL and key normalize]
KG[Trusted Key Groups\nper tenant] -.validates.-> CFF
CFF --> CF[CloudFront edge cache]
CF -->|hit| Client
CF -->|miss| Shield[Origin Shield]
Shield --> LE[Lambda at edge transform]
LE --> S3v[(S3 variants)]
LE --> S3a[(S3 Originals)]
IAM[IAM prefix scoping] -.scopes.-> LE
Per-tenant Trusted Key Groups validate signed URLs in the viewer Function; AWS WAF enforces hotlink and rate rules; IAM prefix-scoping isolates tenants. SSRF is removed by construction.
07
The complete system
flowchart TD
Upload([Upload]) --> S3a[(S3 Originals)]
S3a -->|event| SF[Step Functions render]
SF --> S3v[(S3 variants)]
SF --> INV[CloudFront Invalidation]
Client([Client]) --> R53[Route 53]
R53 --> WAF[AWS WAF]
WAF --> CFF[CloudFront Function\nsign and normalize]
KG[Trusted Key Groups] -.validates.-> CFF
CFF --> CF[CloudFront edge cache]
CF -->|hit| Client
CF -->|miss| Shield[Origin Shield coalesce]
Shield --> LE[Lambda at edge transform]
subgraph Origins[Origin Group failover]
S3a
S3v
S3b[(S3 replica)]
end
LE --> S3v
LE --> S3a
LE -.failover.-> S3b
CT[(CloudTrail audit)] -.logs.-> S3a
Full path: WAF and signing at the edge, key normalization, hit-or-miss with coalescing, multi-region failover, pre-compute on upload, batched invalidation, and CloudTrail audit - all AWS-native.