Authenticating CloudFront Requests to an NGINX EC2 Origin for Free

Use case: A small free-tier instance in AWS is serving content to a CloudFront distribution. You want to protect against people hammering the instance's public-facing web service directly in order to avoid paying for non-CloudFront bandwidth and risking a DoS on the small origin server.

The most effective way of doing this would be to put the instance behind an application load balancer (ALB) and assign a web application firewall (WAF) to the ALB that filters incoming requests for something specific, e.g. custom headers from CloudFront edge servers. Unfortunately that requires paying for both the ALB and WAF, a non-negligible fee even for light usage.

Without paying for a WAF and ALB, this means that the instance needs to have a web service publicly accessible so that you can point CloudFront at your origin's domain name (you can't add CloudFront distributions to security groups like other AWS resources, since they are all over the world).

So how do we protect our origin without paying for a WAF and ALB?

We role our own (kinda) with a few custom lines in our NGINX config:

# Inside a server block.

    if ($http_from != "SECRET" ) {
      return 301 $scheme://YOURDOMAIN.com$request_uri;
    }

# Followed by location blocks (give the above rule precedence).

Now, our little origin instance only needs to serve up permanent redirects to our CloudFront-enabled domain. The origin no longer has to handle the bandwidth of static content, HTML, and other things that may end up being served - unless it's from an authenticated CloudFront server, which caches aggressively and rarely needs to fetch content.

To authenticate your distribution, simply open the distribution in your AWS Console, Edit the origin in the Origins tab, and add the following under Origin Custom Headers:

From SECRET

(Replace SECRET with a randomly-generated string of your choosing in both the above Custom Header field and your NGINX config. Make sure it's base64-encoded for HTTP compatibility.)

In theory our origin's web service is still vulnerable to DoS, but it would be much harder to saturate an NGINX server giving you nothing but 301 Permanent Redirects - and the origin's bandwidth costs during the attack will be much smaller. The secret custom header value is also tough to get - you would need to intercept traffic between CloudFront and the origin in EC2, and crack through any TLS that's present.

p.s. This blog is hosted with such a configuration. See a gap? Let me know via the email address in the About section and I'll make it worth your while :)

About Joey Rideout

I am an Application Security professional and UW CS grad currently based in Ottawa. Committing the crime of curiosity since 2008. Submit questions or ideas for the blog to: joey.rideout@owasp.org

Comments