1

I'm using CloudFront as a proxy for my EC2 instance, so all traffic is routed through CloudFront first.

The issue is that I also need the original client's IP address for each request to my EC2 instance, so I need to examine the X-Forwarded-For to find out the original IP address (as the default IP my EC2 receives is just the CloudFront server's)

I found this article which discusses how to find the original client IP when using a middle-man proxy such as CloudFront.

Their proposed solution is to list of all CloudFront's Edge Server IP ranges in your NGINX configuration, and then read X-Forwarded-For IP's from right-to-left, and forward the first one that isn't a trusted IP address (one listed in the NGINX config)

This all sounds well and good, but what if a CloudFront edge server IP range changes, such that I would have to update the NGINX configuration? I really don't want to have to write some sort of custom script that constantly downloads their ip ranges JSON file, parses it, updates my NGINX configuration file, and restarts NGINX if it has changed. That seems like a lot of work and potential failure points.

I suppose it wouldn't be much of an issue if I am relatively guaranteed that these CloudFront ip ranges are rarely going to change (as in, perhaps only once every 5 years or so), but I can't find whether or not there is some sort of guarantee like that, or any individuals reporting their experience with such.

How should this situation be handled?

Ryan Peschel
  • 153
  • 4

2 Answers2

1

CloudFront IPs change regularly as new edge locations are added, so you can't rely on it being static.

The key here I think is to block everything except CloudFront hitting the server, which can be done with headers as described here. Basically CloudFront adds a header, if the header isn't present Nginx doesn't serve the request. You should make an exception for your home / work IP addresses.

Given everything reaching your server is via CloudFront, using the following is likely to work reliability.

set_real_ip_from 0.0.0.0/0;

CloudFront adds the header X-Forwarded-For.

Tim
  • 31,888
  • 7
  • 52
  • 78
  • 1
    The OP is talking about CloudFront, not CloudFlare ;) – MLu Jul 31 '20 at 10:19
  • Oops. I've updated it to address CloudFront rather than CloudFlare. All these services have very similar names! – Tim Jul 31 '20 at 18:36
  • Do you use that in conjunction with `real_ip_header X-Forwarded-For;` and `real_ip_recursive on;`? Also, could you clarify exactly what is happening here? My intuition is that this sets the `X-Real-Ip` header to the left-most IP found in `X-Forwarded-For` by scanning from right-to-left and then rejecting all of them (except the last one). Is this accurate? If so, doesn't this fall victim to the issue described in [this answer](https://stackoverflow.com/a/51411935) where it may forward a spoofed IP instead of the real one? – Ryan Peschel Aug 01 '20 at 00:31
  • Answer updated slightly. I haven't looked at this in detail as I've never needed to do it myself, I've really just given you the a direction to work through the details. It shouldn't take a lot of time to get CloudFront set up, see what it does, and play with the Nginx config. – Tim Aug 01 '20 at 01:28
0

I ran into the issue of determining the remote IP based on X-Forwarded-For headers in a Rails app that was using Cloudfront and an Elastic load balancer. The X-Forwarded-For header received looked like A,B,C where A was the client IP, B the Cloudfront ip and C the ELB ip. To my surprise Rails returned B as remote_ip, and not the leftmost IP A.

Reading into the specifics, it is actually rather obvious that a hacker can send any X-Forwarded-For header (called spoofing), thus the leftmost approach is not safe if you use the IP for security measures like rate limiting or access authorization. If you don't care about that you could use it but I won't recommend it.

The approach Rails takes is the same as in the Nginx config you describe; you have to specify (ranges of) trusted proxies, ie. all Cloudfront ip ranges. This is (unfortunately) the correct and safest approach but as you already mentioned it requires parsing the https://ip-ranges.amazonaws.com/ip-ranges.json file for CLOUDFRONT prefixes, which can be updated anytime. You can subscribe for notifications when it changes, check https://docs.aws.amazon.com/general/latest/gr/aws-ip-ranges.html

Another solution I found people using is taking the Nth IP from the right, in my case that would be the third since I use two proxies. If your traffic always goes through the same proxies that you trust, the amount of IPs in the X-Forwarded-For header should be the same. Not sure if you can configure this (easily) in Nginx though, but if you can it would safe you from updating the config with all the IP addresses from Cloudfront.

Matthijs
  • 101
  • 1