82

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?

Charles
  • 1,153
  • 1
  • 15
  • 27
rdegges
  • 32,786
  • 20
  • 85
  • 109

7 Answers7

81

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.

Jonathan
  • 10,792
  • 5
  • 65
  • 85
  • 2
    This is the real answer, if you are using Lambda proxy integration. So much easier than adding a mapping for each method. – Dan Esparza Nov 06 '17 at 15:32
  • 2
    Your original answer should be completely removed! The `X-Forwarded-For` header can be spoofed by the user and changed to whatever they want. – Cesar Jul 05 '18 at 20:45
  • 2
    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 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For – Chris Adams Oct 30 '19 at 20:16
  • The proxy must be trusted to insert additional IPs to the right of whatever value the client passes in, or even overwrite that value. – Cesar Jan 08 '20 at 15:15
  • 1
    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'] – Elijah Lofgren May 11 '20 at 19:29
  • Thanks @ElijahLofgren I've added that to the answer. – Jonathan May 12 '20 at 15:46
  • 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. – ryanmc Feb 11 '21 at 19:47
  • It should be noted that `event.requestContext.identity` is not present if you're serving a page that's not behind an authorizer. – ffxsam Mar 17 '21 at 20:50
58

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);
};
GViz
  • 167
  • 1
  • 6
  • This is awesome. Thanks for the mapping info =) – rdegges Jun 02 '16 at 16:36
  • FYI: For proxy integrations, API Gateway passes entire request through to backend and you do not have any option to modify the passthrough behaviors. http://docs.aws.amazon.com/apigateway/latest/developerguide/integration-passthrough-behaviors.html?shortFooter=true – Joshua Robinson Jul 28 '17 at 10:23
  • 33
    For Lambda proxy integrations, the source IP is included in the event passed to the function. E.g. event.requestContext.identity.sourceIp – Kenneth Rory Dunn Aug 03 '17 at 09:16
  • 1
    another question is is it possible to get user-agent too? – tim Apr 11 '20 at 06:23
  • 4
    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. – Roman Kishchenko Aug 19 '20 at 11:13
  • 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 Aug 25 '21 at 07:08
19

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.

Mike76
  • 914
  • 7
  • 8
  • Cool. But, how do I reference the passed through value in my Lambda function? – AaronBaker Apr 27 '16 at 02:18
  • 2
    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 ? – Sumit Arora May 09 '16 at 05:29
  • Apparently this is only true if you are using an "authorizer".in the API Gateway. – NealWalters Jun 06 '21 at 18:18
  • 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](https://stackoverflow.com/users/7716944/roman-kishchenko) on the accepted answer. – Cadoiz Aug 25 '21 at 07:10
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)
}
SynergyChen
  • 1,161
  • 9
  • 4
  • 1
    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: https://www.sjoerdlangkemper.nl/2017/03/01/bypass-ip-block-with-x-forwarded-for-header/ – Dzhuneyt Oct 14 '21 at 10:03
2
export const handler = (event) => {
    console.log('ip: ', event.requestContext.identity.sourceIp);
};
yonadav bar ilan
  • 550
  • 6
  • 10
0

I spent a long time trying to figure out how to access this information.

After sifting through a bunch of SO and documentation, I believe you must use the ANY method in AWS API Gateway in order for this information to be included in the request, per this documentation

Additionally, you'll need to configure the api gateway resource to function as a proxy integration endpoint (check the link provided above).

Then you should be able to find what you are looking for using the following sytax (at least for Node) requestContext = event?.requestContext

DonCarleone
  • 544
  • 11
  • 20
-1
exports.handler = (event, context) => {
    console.log('ip:', event.headers["x-forwarded-for"].split(",")[0].trim());
};
Oded Breiner
  • 28,523
  • 10
  • 105
  • 71