How can I retrieve a user's public IP address via Amazon API Gateway + Lambda (node)

51,724

Solution 1

Here is a simple demonstration of using API Gateway's $context.identity.sourceIp in a Lambda function.

API Mapping template:

{
    "sourceIP" : "$context.identity.sourceIp"
}

Lambda function:

'use strict';
console.log('Loading function');
exports.handler = (event, context, callback) => {
    console.log('SourceIP =', event.identity.sourceIP);
    callback(null, event.identity.sourceIP);
};

Solution 2

Update for HTTP APIs

Adding @Elijah's comment. The format for HTTP APIs will be

event['requestContext']['http']['sourceIp']

Edit

A better way is actually to check

event['requestContext']['identity']['sourceIp']

You can also get the User-Agent from the same object

event['requestContext']['identity']['userAgent']

See Cesar's comment below. Headers are easily spoofed and the user can set X-Forwarded-For to anything. AFAIK the sourceIp above is retrieved from the TCP connection.

Original answer

As of September 2017, you can create a method in API Gateway with Lambda Proxy integration, this will give you access to

events['headers']['X-Forwarded-For']

Which will look something like 1.1.1.1,214.25.52.1

The first ip 1.1.1.1 is your user's public ip address.

Solution 3

In the API Gateway, it's the value

$context.identity.sourceIp

http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#context-variable-reference

You can pass that through to your Lambda via a mapping template.

Solution 4

API gateway should already include remote IP in http header X-Forwarded-For, so you could:

// Lambda handler function
module.exports.handlerFunc = async (event, context) => {
    // `X-Forwarded-For` should return a comma-delimited list of IPs, first one being remote IP:
    // X-Forwarded-For: '<remote IP>, <cloudfront/API gateway IP>, ...'
    const remoteIp = event.headers['X-Forwarded-For'].split(', ')[0]
    // If you want to see more info available in event and context, add following, deploy and check CloudWatch log:
    // console.log(event, context)
}
Share:
51,724
rdegges
Author by

rdegges

I'm just a happy programmer that likes to hack stuff. I spend an inordinate amount of time building and growing developer tools and services. I love web security, cryptography, telephony, and general optimization. HACK THE PLANET!

Updated on July 08, 2022

Comments

  • rdegges
    rdegges almost 2 years

    I'm currently writing a Node.js lambda function, in which I want to log the incoming requester's public IP address. I've been looking through both the API Gateway and Lambda docs all day, but haven't found a solution.

    Does the lambda event object include request metadata I can use to extract the user's IP?

  • AaronBaker
    AaronBaker almost 8 years
    Cool. But, how do I reference the passed through value in my Lambda function?
  • Sumit Arora
    Sumit Arora almost 8 years
    I tried doing by mapping template, did almost everything , but that didn't work , Is there any clear step-by-step reference or an example which can talk about it ?
  • rdegges
    rdegges almost 8 years
    This is awesome. Thanks for the mapping info =)
  • Joshua Robinson
    Joshua Robinson over 6 years
    FYI: For proxy integrations, API Gateway passes entire request through to backend and you do not have any option to modify the passthrough behaviors. docs.aws.amazon.com/apigateway/latest/developerguide/…
  • Kenneth Rory Dunn
    Kenneth Rory Dunn over 6 years
    For Lambda proxy integrations, the source IP is included in the event passed to the function. E.g. event.requestContext.identity.sourceIp
  • Dan Esparza
    Dan Esparza over 6 years
    This is the real answer, if you are using Lambda proxy integration. So much easier than adding a mapping for each method.
  • Cesar
    Cesar almost 6 years
    Your original answer should be completely removed! The X-Forwarded-For header can be spoofed by the user and changed to whatever they want.
  • Chris Adams
    Chris Adams over 4 years
    The advice from @Cesar is incomplete: it is true that X-Forwarded-For can be set by the client on requests, which makes it important to only use it in cases where you have a trusted proxy and your code only trusts the rightmost value. See developer.mozilla.org/en-US/docs/Web/HTTP/Headers/…
  • Cesar
    Cesar over 4 years
    The proxy must be trusted to insert additional IPs to the right of whatever value the client passes in, or even overwrite that value.
  • tim
    tim about 4 years
    another question is is it possible to get user-agent too?
  • Elijah Lofgren
    Elijah Lofgren almost 4 years
    If you're using the new HTTP API instead of REST API it will be event['requestContext']['http']['sourceIp'] instead of event['requestContext']['identity']['sourceIp']
  • Jonathan
    Jonathan almost 4 years
    Thanks @ElijahLofgren I've added that to the answer.
  • Roman Kishchenko
    Roman Kishchenko over 3 years
    Please note, that if a request goes through a proxy (in my case it was CloudFront), the actual client id will be given in the X-Forwarded-For header.
  • ryanmc
    ryanmc about 3 years
    I am running into this today and sourceIP is only returning the IP for Cloudfront. Maybe X-Forwarded-For can be spoofed, but it is the only reliable way to get the client IP. The tough part is figuring out which IP in the list is correct.
  • ffxsam
    ffxsam about 3 years
    It should be noted that event.requestContext.identity is not present if you're serving a page that's not behind an authorizer.
  • NealWalters
    NealWalters almost 3 years
    Apparently this is only true if you are using an "authorizer".in the API Gateway.
  • Cadoiz
    Cadoiz over 2 years
    Thanks for the answer @Roman - in my case, I was using an ALB and I also just had event.multiValueHeaders.x-forwarded-for not event.identity.sourceIP
  • Cadoiz
    Cadoiz over 2 years
    In my case, I was using an ALB, so you have to use $context.multiValueHeaders.x-forwarded-for not $context.identity.sourceIP - you can also consider the comment of Roman on the accepted answer.
  • Dzhuneyt
    Dzhuneyt over 2 years
    Note that this is okay for most use cases, but do NOT use it for allowing/rejecting access to confidential content, because the X-Forwarded-For header can be spoofed, if a malicious user gets their hands on your API Gateway URL and makes the request there directly, skipping CloudFront or whatever you have put on its path. See: sjoerdlangkemper.nl/2017/03/01/…