[Fixed] Node.js: Express set the "trust proxy" for CloudFront


I have a Express backend behind AWS Cloudfront. How properly set trust proxy for AWS Cloud Front:

app.set('trust proxy', function (ip) {
  if ( ???????????? ) return true; // trusted IPs
  else return false;

AWS Cloudfront use tons of ip address and is insecure validate all AWS ip address because anyone with an AWS EC2 instance have a valid IP.


The Problem

As you mentioned AWS CloudFront uses a long list of IP Address ranges. It’s mentioned in their documenation. You can see them via this one liner (source, requires jq which you can get from brew in MacOs.):

curl 'https://ip-ranges.amazonaws.com/ip-ranges.json' | jq -r '.prefixes[] | select(.service=="CLOUDFRONT") | .ip_prefix'

(Update: or directly from http://d7uri8nf7uskq.cloudfront.net/tools/list-cloudfront-ips as mentioned in their doc.)

Right now, April 2021, it is giving me 122 ranges.

The Solution

You can make an AJAX call to this file in Node, parse the JSON file, get the list as an array of string (cloudFrontIps), and pass that to app.set('trust proxy', ['loopback', ...cloudFrontIps]).

Good news!

The good news is someone else has already done it! Check https://github.com/nhammond101/cloudfront-ip-ranges out.

Final Notes

  1. It’s obvious, but worth mentioning that getting this list in asynchronous! So, you might want to delay (e.g. await) your app start until this list is available. It’s not a must though — calling app.set after the HTTP server is up should work, thought for that short duration you will be recording CloudFront’s IP.
  2. You might want to call this file and get the new list periodically. The package is suggesting every 12 hours, using setTimeout.
  3. My understanding is calling app.set on a running server will make the new list applicable on future calls immediately, without needing to restart. I am getting this impression by how X-Forward-For is examined on every request, and how app.set is calling compileTrust function on it’s invocation. So, TL;DR: You shouldn’t be needing to restart the server every 12 hours for this!
  4. I look at express’s code and it seems like app.set overrides (and not appends) the list every time you call it. So if you have some IPs of your own (e.g. your VPC's CIDR in AWS ELB), you have to manually add it to the list every time you call this app.set in your setTimeout.

Leave a Reply

(*) Required, Your email will not be published