How to get client IP of requests via CloudFront?

With CloudFront Functions, now you can do this without using Lambda@Edge:

function handler(event) {
    var request = event.request;
    var clientIP = event.viewer.ip;

    //Add the true-client-ip header to the incoming request
    request.headers['true-client-ip'] = {value: clientIP};

    return request;
}

Check out guide at AWS docs


My suggestion would be to use CloudFront provided headers, link - [https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-cloudfront-headers.html]

  1. All you need to do first is Go to Cloudfront -> Select Distribution -> Behaviors -> and do the following in 'Cache key and origin requests'

  2. Select 'CachingDisabled' for 'Cache policy' dropdown, if you don't want anything to get cached. I personally faced problems in my app, if I didn't select this option.

  3. For Origin Request Policy do the following -

    Create a new Policy like 'Origin-Policy-For-Cloudfront' and select 'CloudFront-Viewer-Address' and checkout other options as well.

    It'll look something like this -

enter image description here

  1. Save it and, finally the Cloudfront Behaviour should look like this -

enter image description here

  1. Now, open conf.d/node.conf or nginx.conf, whereever you have written your 'server -> /location', and simply write the following -

     server {
         listen 80;
         server_name my-server CLOUDFRONT_URL;
         location / {
             proxy_set_header   X-Client-IP $http_CloudFront_Viewer_Address;
             proxy_set_header   Host $http_host;
             proxy_pass         "http://127.0.0.1:
             proxy_set_header Upgrade $http_upgrade;
             proxy_set_header Connection $connection_upgrade;
         }
     }
    
  2. On the NodeJs Backend, you can fetch the Client IP in the request as follows -

     exports.get = (req, res, next) => {
         console.log('Clinet IP:', req.headers['x-client-ip']);
     }
    

This is an easier method to get the client Ip rather than messing around with Cloudfront CIDR and all.


Is it right?

Not exactly.

CloudFront follows correct semantics for X-Forwarded-For. Specifically, each system handling the request appends its client's address to the right. This means the rightmost address in X-Forwarded-For in the request from CloudFront is always the address of the machine that connected to CloudFront.

If the client (the machine establishing the connection to CloudFront) includes an X-Forwarded-For header in its request, that header may be forged, or it may be legitimate if the client is a proxy server, but you rarely have a way of knowing that... so either way, you should treat this as potentially valuable, but strictly non-authoritative.

The rightmost value (which may also be the only value) is the only value you can trust in the request you receive from CloudFront.

Generally speaking, parsing from the right, any address that is known to you and trusted to have correctly identified its upstream client can be removed from the list... but once you encounter the first untrusted address, right to left, that's the one you're looking for, since nothing to the left of that address can be trusted.

This means that if components in your stack -- such as Application Load Balancer or your web server are also adding X-Forwarded-For, then you will need to account for what those components also add onto the right side of the value, modifying what CloudFront has supplied.

For example. Client sends:

X-Forwarded-For: a, b, c

CloudFront adds the client's IP d:

X-Forwarded-For: a, b, c, d

ALB receives the request from CloudFront, so it adds the CloudFront egress address e:

X-Forwarded-For: a, b, c, d, e

Then your web server adds the internal address of the balancer f:

X-Forwarded-For: a, b, c, d, e, f

You can trust and remove f as long as it is with the CIDR range of your balancer subnets.

You can trust and remove e as long as it is in the CloudFront address ranges.

That leaves you withd as the client address.

The values a and b and c are almost worthless, in this example, because you can't trust their authenticity since they are to the left of the first (from the right) untrusted address... occasionally, they may be forensically useful, later, but you can't make any real-time decisions based on them.

This is how X-Forwarded-For always works. Many developers seem to make naïve assumptions due to lack of understanding. Be certain you understand it before you use it for anything important.


In Lambda@Edge triggers, CloudFront gives you the client IP address in event.Records[0].cf.request.clientIp. This is always just a single address, and is the same as the rightmost value of X-Forwarded-For as the request leaves CloudFront headed to your origin (which may, as noted above, add additional values onto the right side).