dashford.dev

SRE living in Dublin, Ireland

Restricting Origin Access for Cloudflare

February 2024

Cloudflare is a well known and powerful proxy you can run in front of your website. You may already be familiar with the little orange cloud meaning your site is behind their proxy. Essentially what this means is DNS queries return Cloudflare IPs so connections from users go to Cloudflare before being passed to your origin.

If you've invested a lot of time creating and customising WAF rules, redirects, request transformations, etc. then it can be essential that you're enforcing all traffic through Cloudflare. Often times in business scenarios Cloudflare sits in front of a managed load balancer or even another CDN like CloudFront. These load balancers are often public leaving your origin accessible without going past Cloudflare first, thereby bypassing any rules or security gates you have in the way.

In this post we'll discuss some ways you can protect your origins, allowing only access from Cloudflare.

Authenticated Origin Pulls

You may have already seen Cloudflare offer a solution to this issue in the form of Authenticated Origin Pulls. This is a powerful way of ensuring connections only come through Cloudflare but oftentimes isn't a practical way forward when using managed services (e.g. CloudFront, ELBs, etc.) as your origin.

An alternative approach and one adopted at our workplace has been to use HTTP header validation which gives us enough reassurance while being relatively easy to implement in our managed services.

Implementing HTTP Header Validation

For cost and legacy reasons our stack consists of Cloudflare > CloudFront > ELB. Both the CloudFront and ELB stages need to have some form of validation in order to ensure the entire chain is secure.

To secure CloudFront we make use of Cloudflare's transform rules, specifically modifying request headers. Here, we can add a header that will be used further downstream:

Set static: cloudflare-origin-token = C7SyZgjZwiSOFyomcm3wyxVJz5vLljqOfk7eNcuWbsbWHX1gvNY7ro5Z1cKgvu2

We can set this token to be used for specific hostnames or set for everything giving us some flexibility in handling different tokens values or scenarios.

CloudFront

Now that we're setting a token to be used we can look in CloudFront and see how we can use this token to block non Cloudflare traffic.

CloudFront has a useful feature in the form of CloudFront Functions. These functions live at the edge of the CloudFront network and are ideal for small validation tasks like ours. Importantly they allow manipulation of the headers.

These functions are written in JavaScript but can be pretty basic for our needs. An example below:

function handler(event) {
    var headers = event.request.headers;
    var token = 'C7SyZgjZwiSOFyomcm3wyxVJz5vLljqOfk7eNcuWbsbWHX1gvNY7ro5Z1cKgvu2';

    if (headers['cloudflare-origin-token']) {
        if (headers['cloudflare-origin-token'].value === token) {
            return event.request;
        }
    }

    return {
        statusCode: 401,
        statusDescription: 'Unauthorized'
    };
}

In our example here we're inspecting the headers and checking for the existence of the cloudflare-origin-token header. If we find it, we compare it to our expected token value. If they match we return the request as normal otherwise we return a 401.

ELB

At this stage, we have secured the chain as far as CloudFront but in our example the ELB behind CloudFront is still publicly addressable. To get around this we can make use of AWS security groups and managed prefix lists.

Managed prefix lists are managed by AWS so the maintenance burden of using them is very small. One of these lists contains the IP address range of all of CloudFront's origin facing servers. Using this list we can apply a security group to our ELB only allowing access from this list. Now, any requests directly to the ELB not coming through CloudFront will timeout.

Wrap Up

Hopefully this post has been informative in detailing the steps you can take to protect your managed origin services from non-Cloudflare traffic. In this particular example it works well from a maintenance point of view. Rotating the header token is about the only routine step that needs to be taken periodically.

If your situation is different this might offer some inspiration too. If Cloudflare is talking directly to an ELB or ALB you can still replicate the functionality albeit with a slightly higher maintenance burden. Cloudflare publish a list of their IP addresses which could be used in place of CloudFront's. Alternatively, an ALB can inspect the header directly which offers a nice simplification.