37
votes

I've followed the tutorial here to create a VPC with public and private subnets.

Then I set up an AWS lambda function inside the public subnet to test if it could connect to the outside internet.

Here's my lambda function written in python3

import requests

def lambda_handler(event, context):
    r = requests.get('http://www.google.com')
    print(r)

The function above failed to fetch the content of http://www.google.com when I set it inside the public subnet in a VPC.

Here's the error message:

"errorMessage": "HTTPConnectionPool(host='www.google.com', port=80): Max retries exceeded with url: / (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 110] Connection timed out',))", "errorType": "ConnectionError",

I don't understand why.

The route table of the public subnet looks like this:

enter image description here

The GET request to http://www.google.com should match igw-XXXXXXXXX target. Why can't the internet-gateway(igw) deliver the request to http://www.google.com and get back the website content?

This article says that I must set the lambda function inside the private subnet in order to have internet access.

If your Lambda function needs to access private VPC resources (for example, an Amazon RDS DB instance or Amazon EC2 instance), you must associate the function with a VPC. If your function also requires internet access (for example, to reach a public AWS service endpoint), your function must use a NAT gateway or instance.

But it doesn't explain why I can't set the lambda function inside the public subnet.

1
What does the Lambda logs in Cloudwatch say? Assume you have included requests modules with your deployment package? Could it be NACL preventing outbound traffic?toringe
Do you actually need to deploy the Lambda function into a VPC?jarmod

1 Answers

92
votes

The reason that your Lambda function cannot access the internet, even though the Lambda function is attached to a public subnet of your VPC, is that Lambda functions do not, and cannot, have public IP addresses. You cannot send traffic to the internet, which happens via the VPC's Internet Gateway, unless you have a public IP.

The only way to access the internet if you do not have a public IP is to route traffic through a NAT.

However, the default route target for traffic in a VPC public subnet is the Internet Gateway (IGW) not a NAT and, because the Lambda function only has a private IP, all packets to the internet from the Lambda function will be dropped at the IGW.

If your Lambda function doesn't actually need to reach private resources inside your VPC then you typically don't need to attach the Lambda to the VPC. But if it does need to, then attach the Lambda function to a private subnet and ensure a default route from that subnet to a NAT instance or NAT Gateway in a public subnet. And configure an IGW, without which internet access is not possible.

Be aware that NAT gateway charges per hour and per GB processed so it's worth understanding how to reduce data transfer costs for NAT gateway.

Note: if the Lambda only needs access to resources in the VPC (e.g. an RDS database in a private subnet) and/or to AWS services that are all available via private VPC Endpoint then you don't need to route through NAT at all.