19

I am trying to make an outbound API request to a third-party service from within a Lambda function, but the function always times out without any error.

This previously happened when trying to perform a s3.putObject operation within a different function (still within the same VPC / subnets), and I managed to get around that by adding an Endpoint with a service name com.amazonaws.us-east-1.s3 and connecting it to the route table that is associated with the VPC that this Lambda function resides in.

Within the Lambda dashboard inside Network box -> Security Groups section, I see this warning:

When you enable VPC, your Lambda function will lose default internet access. If you require external internet access for your function, ensure that your security group allows outbound connections and that your VPC has a NAT gateway.

I believe that this security group allows outbound connections, based off of the Outbound rules table right underneath:

enter image description here

For that second requirement, I can confirm this VPC has a NAT gateway, because on the VPC Dashboard, within NAT Gateways tab, the one that appears there has a VCP associated with it, and that VPC is the same one hosting the Lambda function.

I followed a guide to create a Flow Log to monitor traffic in and out of the VPC, hoping to see that those outbound requests are indeed rejected. However, after doing so and inspecting the CloudWatch logs, all of the records end in either ACCEPT OK or NODATA.

How can I grant internet access to my VPC Lambda function? is the guide I originally tried to follow, but I got stuck on step 4 under To create a public or private subnet:

  1. From the Change to: drop-down menu, choose an appropriate route table: For a private subnet, the default route should point to a NAT gateway or NAT instance:

    Destination: 0.0.0.0/0 Target: nat-… (or eni-…) For a public subnet, the default route should point to an internet gateway:

    Destination: 0.0.0.0/0 Target: igw-…

For all four of the subnets within this VPC, clicking the drop-down to the right of Change to: only showed one option, the one already selected, rtb-xxxxxxxx. After clicking on the link to that route table, and clicking the Routes tab next to Summary, I see this:

enter image description here

What might I be doing wrong that is blocking the Lambda function's access to the Internet?

Pat Needham
  • 5,698
  • 7
  • 43
  • 63

4 Answers4

28

For Lambda to have access to the internet via VPC it should be in the Private Subnet with NAT Gateway attached.

As per your screenshots, route table attached to subnet has igw-xxxxxxx attached making your current subnet a public subnet.

So to make things work, you can do following:

  • Attach NAT Gateway instead of igw-xxxxxx in route table of your current subnet

OR

  • Find ENI attached to your Lambda and attach Elastic IP if you want to have internet access.

OR

As per @John Rotenstein if your Lambda doesnt need VPC recources you can move Lambda out of VPC

Community
  • 1
  • 1
Navpreet Singh
  • 408
  • 4
  • 6
  • I don't think it's possible to attach an Elastic IP to a Lambda ENI. – John Rotenstein May 11 '18 at 23:35
  • 2
    @JohnRotenstein Yes. Navigate to the `Network Interfaces` on EC2 dashboard. Then find the `ENI ID` by searching security group attached to the Lambda ( I did like this .. there will be better ways ). Now you got the `ENI ID`. Navigate to `Elastic IP` page, allocate and attach the required IP. – Navpreet Singh May 14 '18 at 08:51
  • Wow, you're quite right! To test this, I created a public VPC using the VPC Wizard. I created a Lambda function that accessed the Internet. Test 1: No VPC, worked. Test 2: Attached to VPC, failed. Test 3: Associated Elastic IP address to the Lambda ENI, worked! Neat!! – John Rotenstein May 14 '18 at 12:00
  • One thing to note here is a lambda in a VPC has VERY slow cold start(over 12 seconds). – Mrk Fldig May 14 '18 at 22:11
  • 3
    @NavpreetSingh @JohnRotenstein - `Elastic IP => ENI`, this will work but every request lambda will create a new ENI and attach. For continuous Internet access this won't work. – Vaisakh PS Sep 20 '18 at 14:41
  • 1
    @VaisakhPS Every Lambda request does _not_ create a new ENI. However, any Lambda functions running in parallel _will_ create a new ENI. They hang around for future use, but I agree you should not rely on this behaviour. – John Rotenstein Sep 20 '18 at 15:21
8

I developed a step by step tutorial with explicit screenshots about it:

Part I

  1. Create a lambda function in AWS
  2. Create an API Gateway to redirect all the requests to your AWS Lambda Function

https://medium.com/@shontauro/how-can-i-turn-my-restful-api-into-a-serverless-application-and-deploy-it-to-aws-lambda-step-by-ec7ce38e18be

Part II

  1. Configure a VPC for your lambda function
  2. Grant internet access to the lambda function in a safety way
  3. Deploy the Node.js Restful API into your Lambda Function

https://medium.com/@shontauro/how-can-i-turn-my-restful-api-into-a-serverless-application-and-deploy-it-to-aws-lambda-step-by-8ff6cc97780f

desertnaut
  • 57,590
  • 26
  • 140
  • 166
shontauro
  • 1,812
  • 1
  • 25
  • 26
6

One thing you may be doing wrong (which is exactly what I did wrong but got a hint about from @Ramratan Gupta above) is to put the NAT gateway in the private subnet and not in the public.

The NAT gateway provides your private IP Lambda function with internet connectivity and so it sort of stands to reason the NAT gateway needs to have internet access itself and be in the Public network.

To summarise:

  • You have to create at least two subnets: one public and one private. Put both in the same VPC.

  • What makes a subnet public or private is the 0.0.0.0/0 route.

  • You need to have both an internet gateway (igw) and a NAT gateway (ngw).

  • To create the NAT gateway, you need an Elastic IP.

    Also, and here's what I did wrong, you need to create the NAT gateway in the PUBLIC network.

  • The igw goes in the same subnet that the NAT gateway is: the public one.

  • You need to have two routes: one with the 0.0.0.0/0 route referencing the igw and the other referencing the ngw.

  • You then need to associate the NAT-route containing route table with the private subnet and the igw-route containing route table with the public subnet. Please note that until you do this association, there is no difference between the subnet that would make one public and one private. You make one private and the other public by how you associate the subnets with the route tables.

  • Finally, you need to connect your Lambda function to the VPC and also to the private subnet only. This way, when your lambda tries to reach the internet, it goes to the private subnet, looks for the 0.0.0.0/0 route, which directs it to the NAT gateway that is in the public subnet. The NAT gateway then contacts the internet using the igw (because they are in the same subnet) and upon receiving a response, returns it to your Lambda function.

  • Please also note that there are some permissions your Lambda function needs (that AWS will warn you about) in order to connect to a VPC.

sdgfsdh
  • 33,689
  • 26
  • 132
  • 245
jcalais
  • 63
  • 1
  • 4
1

Setting up AWS Lambda Internet access in VPC mode is tricky as no proper AWS documentation is provaded on AWS side, I did read this aritical many times https://aws.amazon.com/premiumsupport/knowledge-center/internet-access-lambda-function/ but did not wached YouTube Video. After so much of R&D I can summrise as below steps are need for set up AWS Lambda in VPC mode

- Route Tables two router
    - One for EC2 - EC2_ROUTER
    - Another for AWS Lambda - AWS_Lambda_ROUTER
- Create an Internet Gateway
    - Add 0.0.0.0/0 rule in EC2_ROUTER for target igw-xxxxx
    - This will create public subnet and give INTERNET access for EC2

- Create a NATGateway with public subnet which has igw-xxxxx as target
- Create a private subnet which and attach to AWS_Lambda_ROUTER, with target 0.0.0.0/0 as nat-xxxxxxx
- Select VPC for AWS Lambda
- Select a/all private subnet which is private having NAT Gateway for all traffic 0.0.0.0/0

all done, go ahead and enjoy

Note

  • NATGateway is required when access to public API other than AWS
  • There is AWS Endpoints for internal AWS services, and one can attach AWS endpoints in AWS_Lambda_ROUTER by creating

Internet access in AWS Lambda -> Private Subnet with NATGateway -> NATGateway is in public subnet with Internet Gateway which access to AWS Lambda.

PS

I have no Idea why AWS Lambda can not have INTERNET access via InternetGateway why it needs NATGateway

Ramratan Gupta
  • 1,056
  • 3
  • 17
  • 39
  • You can't use an IG because an IG requires a static IP to route traffic to and from some resource. Lambdas are ephemeral and require a long-lived NAT Gateway to act as a proxy for them. – AlexMayle Sep 08 '20 at 16:54