skip to content

Your CloudFront distribution uses an internet-facing Application Load Balancer as its origin, so anyone who discovers the ALB's DNS name can call it directly and bypass the CDN. How do you make the ALB accept traffic only from your distribution?

level: seniorimportance: should knowfreq 40%

answer

  1. the edge controls only what passes the edge
  2. narrow the security group to CloudFront ranges
  3. the ranges include other people's distributions
  4. a secret header the viewer cannot set
  5. or give the origin no public address at all

basics

~20 s

Combine two controls: restrict the ALB's security group to the AWS-managed CloudFront origin-facing prefix list, and have CloudFront inject a secret custom origin header that an ALB listener rule requires, with the default rule returning 403. Alternatively make the ALB private and use a CloudFront VPC origin.

solid answer

~50 s

Two layers, because neither is sufficient alone. **Network layer:** replace `0.0.0.0/0` in the ALB's security group with the AWS-managed prefix list `com.amazonaws.global.cloudfront.origin-facing`, so only CloudFront edge ranges can connect. That still admits *anybody's* distribution, which is why you add the **application layer:** configure a custom origin header on the origin — a secret value such as `X-Origin-Verify: <random>` — and an ALB listener rule that forwards to the target group only when that header matches, with the listener's default action returning a fixed 403. Since the header is added by CloudFront and viewers cannot influence it, a direct caller cannot forge it without knowing the secret, and you rotate it by adding the new value as a second rule condition, updating the distribution, then removing the old one. The cleaner modern option is to stop exposing the ALB at all: make it internal and attach it as a CloudFront **VPC origin**, so there is no public endpoint to bypass.

code

bash · 5 lines
bash
aws elbv2 create-rule \
  --listener-arn arn:aws:elasticloadbalancing:eu-west-1:111122223333:listener/app/prod-alb/50dc/f2f7 \
  --priority 10 \
  --conditions '[{"Field":"http-header","HttpHeaderConfig":{"HttpHeaderName":"X-Origin-Verify","Values":["REPLACE_WITH_SECRET"]}}]' \
  --actions '[{"Type":"forward","TargetGroupArn":"arn:aws:elasticloadbalancing:eu-west-1:111122223333:targetgroup/app-tg/9f1c"}]'

go deeper

for a junior

Understand that an internet-facing load balancer stays reachable on its own DNS name even after CloudFront is added, so something must reject requests that did not come through the CDN.

for a middle

Describe both controls concretely: the managed CloudFront origin-facing prefix list on the security group, and a secret custom origin header enforced by an ALB listener rule with a 403 default action.

for a senior

Explain why one layer alone is insufficient, run the rotation without downtime, verify the bypass path is actually closed as part of deployment, and know that a private VPC origin removes the problem rather than mitigating it.

for a principal

Set this as a non-negotiable estate-wide control — every CDN-fronted origin proves its caller — and decide how it is detected, enforced and evidenced across accounts rather than left to each team.

## Why this matters Everything you enforce at the edge — WAF rules, geo restrictions, signed URLs, TLS policy, rate controls, logging — is enforced only for traffic that actually goes through the edge. An internet-facing ALB whose DNS name is one `dig` away turns all of it into a suggestion. Interviewers ask this because it is a real, common gap in otherwise sensible architectures. ## Layer 1 — the security group and the managed prefix list AWS publishes a managed prefix list, `com.amazonaws.global.cloudfront.origin-facing`, containing the CloudFront IP ranges used for origin fetches. Referencing it in the ALB's security group inbound rule instead of `0.0.0.0/0` means only CloudFront can open a connection, and AWS maintains the list as ranges change — far better than a cron job that rewrites CIDRs from the published IP-ranges document. Its weakness is that it is not *your* CloudFront. Any AWS customer can create a distribution pointing at your ALB's DNS name, and their requests arrive from the same ranges. So this layer stops the internet, not an attacker who knows your origin's hostname. (Note the prefix list consumes entries against the security group's rule limit, which occasionally forces a quota increase.) ## Layer 2 — the shared secret header Each CloudFront origin can carry **custom headers** that CloudFront adds to every origin request. Viewers cannot set or override them — if a viewer sends the same header name, CloudFront replaces it — so the value is a shared secret between your distribution and your origin. On the ALB, add a listener rule whose condition is `http-header` with that name and value, forwarding to the target group, and set the listener's **default action** to a fixed-response 403. Now a direct request lands on the default action and is refused at the load balancer, before any target is involved: ``` listener rule 10: if http-header X-Origin-Verify = <secret> -> forward to app-tg listener default: fixed-response 403 ``` Store the secret in Secrets Manager, and rotate by making the rule accept both the old and new values, updating the distribution's origin custom header, waiting for the change to propagate, then dropping the old value. Rotating in one step guarantees an outage. One caveat: the header travels in the request. Use HTTPS between CloudFront and the origin (origin protocol policy `https-only`) so it is not exposed on the wire, and keep it out of access logs. ## Layer 3 — remove the public endpoint entirely The strongest answer is that the origin should not be on the internet at all. CloudFront **VPC origins** let a distribution reach a private ALB, NLB or EC2 instance inside your VPC, so the load balancer has no public DNS name to discover and the whole bypass question disappears. Where that fits the architecture it is preferable to defending a public endpoint; the prefix list and header approach remains the answer for origins that must stay public or live outside AWS. ## What weak answers look like - *"Put WAF on the ALB too."* Better than nothing, but it duplicates rules, doubles cost, and still lets direct callers reach the application path. - *"Hide the ALB's DNS name."* It appears in certificate transparency logs, DNS history and misconfigured error pages. Obscurity is not the control. - *"Hard-code the CloudFront CIDR ranges."* They change; the managed prefix list exists precisely so you do not do this. - *"Check `X-Forwarded-For` at the application."* The header is client-controllable on a direct request, and matching against edge IPs re-creates the same "any distribution" hole. ## Verifying it The test is simple and should be part of the deployment: request the ALB's DNS name directly and expect 403; request the distribution's domain and expect 200. Run it after every change to the origin configuration, because a rotated secret or a re-created listener rule breaks it silently in the safe direction — everything looks fine until the day you check.

  • Why is the CloudFront managed prefix list on the security group not sufficient on its own?
    It admits every CloudFront distribution, not just yours. Anyone who learns your ALB's DNS name can create their own distribution pointing at it, and their origin fetches arrive from the same AWS-published ranges. The prefix list keeps the open internet out; distinguishing your distribution from a stranger's needs the secret custom header or a private VPC origin.
  • How do you rotate the secret origin header without downtime?
    Make the ALB accept both values first: add a second listener rule (or a second value on the existing condition) for the new secret. Then update the distribution's origin custom header and wait for the configuration to deploy. Only once traffic is arriving with the new value do you remove the old rule. Swapping both sides at once guarantees 403s.
  • Could you validate the caller by inspecting `X-Forwarded-For` in the application instead?
    No. On a direct request the client controls that header entirely, so it can be forged. Even validating the connecting IP against CloudFront's ranges only proves some distribution sent it, which is the same weakness as the prefix list alone. Origin authenticity needs a secret the viewer cannot influence, or an origin with no public endpoint.

saying these in an interview costs you the question

  • Relies on the ALB's DNS name being hard to guess
  • Thinks the CloudFront prefix list alone proves it is your distribution
  • Trusts a client-supplied X-Forwarded-For header
  • Hard-codes CloudFront CIDR blocks and never updates them
  • Assumes attaching WAF to CloudFront protects the ALB too

context