6

Is it possible to get the source IP address of a request to your API Gateway in a 'Custom Authorizer' lambda function?

This is definitely possible with the actual integration of your API Gateway to a lambda function. Though it does not seem to be possible to get the requester's IP address in a Custom Authorizer function.

My goal is to do rate based blocking directly in APIG. A similar solution is described here. However, as I am only restricting access to one or two APIG endpoints, I'd rather do this in a custom authorizer function which simply adds the source address to the deny policy of the APIG when it reaches a rate limit.

EDIT: To clarify some potential confusion. I understand that I could do this through the regular integration as mentioned above, and in this other post. But I am trying to utilize the custom authorizer functionality, so that I don't have to write the same rate limiting code in all of my lambda functions.

Community
  • 1
  • 1
unclemeat
  • 5,029
  • 5
  • 28
  • 52
  • 1
    *"a custom authorizer function which simply adds the source address to the deny policy of the APIG when it reaches a rate limit."* Seems problematic. Policies have no locking mechanism, so given multiple concurrent excessive users, doing (fetch policy, modify policy, save policy) could easily put you in a state where each thing you "add" to the policy also deletes something else added at the same time. In a stateless world, how are you keeping count to determine the need for rate limiting? – Michael - sqlbot Mar 20 '17 at 10:48
  • The count is kept in a DDB table with the columns request_id, source_ip, and TTL. Then the Custom Authorizer checks the number of entries with the given source_ip and a TTL greater than the current time. Where the TTL is something like the current time plus 10 seconds. The locking is something I hadn't considered which will be an issue. Perhaps I'll end up using CloudFront and WAF anyway. – unclemeat Mar 20 '17 at 22:26
  • I suppose I could add a locking key in the DDB table for access to the policy. – unclemeat Mar 20 '17 at 23:14
  • Will you consider to use the rate enforcement ability that usage plan feature is providing? It needs to send the requests with an API key. Then API Gateway will throttle requests by API key. – Ka Hou Ieong Mar 21 '17 at 05:31
  • @KaHouIeong Unfortunately, the number of api keys you can have is limited. – HsnVahedi Jan 24 '22 at 13:01

3 Answers3

4

You should look at

event.requestContext.identity.sourceIp

it will contain the original client IP.

When creating the Authorizer on the "Identity Sources" section add

Context: identity.sourceIp

and enable caching (default is 300 sec). That way your authorizer lambda will not be called for each request, because it will cache the returned policy for that IP.

You can experiment yourself if you add logging of passed event parameter (just don't forget about caching, not all calls to API Gateway fire the authorizer lambda).

BTW, don't use "X-Forwarded-For" look at my comment on another @binshi's answer.

pero
  • 4,169
  • 26
  • 27
-1

Custom Authorizers can now use so-called Enhanced Context. You should be able to use the appropriate context variable to get that information (e.g. $context.identity.sourceIp). You may also be able to use API Mappings, but I haven't tested that.

dawebber
  • 3,503
  • 1
  • 16
  • 16
  • The context.identity object is actually just a CognitoIdentity object. Which does not have the attribute 'sourceIp'. I assume you got that information from [this post](http://stackoverflow.com/questions/33062097/how-can-i-retrieve-a-users-public-ip-address-via-amazon-api-gateway-lambda-n). That is saying to create an API mapping to pass through the source IP to the Lambda. API Mappings cannot be used in custom authorizer functions. This variable is not available in the context object by default as you suggest. – unclemeat Mar 20 '17 at 05:32
  • 1
    Having read the link you gave about Enhanced Context, it seems to actually be about returning addition information from the authorizer to APIG. The APIG context object is not passed to your lambda function. They are two separate things. – unclemeat Mar 20 '17 at 05:40
  • In my first comment I was talking about the python context object. – unclemeat Mar 20 '17 at 05:40
  • @unclemeat, I actually believe that the context is being passed to the custom authorizer [per this article](http://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html). Please take a look at the example. There are 2 different use cases: context getting passed to the custom authorizer, as well as output back to the original lambda function at the receiving end of the stage of the API gateway. The first use case if of interest. – dawebber Mar 20 '17 at 14:43
  • Also, please note that the context variable I have listed has come from [this article] (http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#context-variable-reference), which I cited in my original answer. It does have a list of variables present in the context. – dawebber Mar 20 '17 at 14:46
  • The context variable in APIG is not passed through Lambda. Lambda is passed a context variable, but it is not the same as APIG's. You can create a request mapping in APIG to pass through context variables to your Lambda, but you cannot do this with Custom Authorizers. – unclemeat Mar 20 '17 at 22:15
-1

You can get the source ip as well as any proxy server ip in

events['headers']['X-Forwarded-For']
binshi
  • 1,248
  • 2
  • 17
  • 33
  • No. Don't do that. You cannot trust that header. Anybody can add that to their request and put any value inside. I tested and my invented value appeared in the logs. – pero Dec 11 '17 at 17:33