Issue
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.
Solution
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
- 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 — callingapp.set
after the HTTP server is up should work, thought for that short duration you will be recording CloudFront’s IP. - You might want to call this file and get the new list periodically. The package is suggesting every 12 hours, using
setTimeout
. - 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 howX-Forward-For
is examined on every request, and howapp.set
is callingcompileTrust
function on it’s invocation. So, TL;DR: You shouldn’t be needing to restart the server every 12 hours for this! - 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. yourVPC's CIDR
in AWS ELB), you have to manually add it to the list every time you call thisapp.set
in yoursetTimeout
.