I have been working on integrating an Amazon Lambda function with connection to a RDS for the mySQL DB and an external API. To access the API, there needed to be an internet gateway and then security groups that allowed connection from 0.0.0.0/0.
I have a a public subnet and private subnet. The public subnet routes to the internet gateway but the private subnet routes to a NAT.
This lead me to think that if I ran the Lambda function with the Public subnet, it would connect to the internet. However, every time it timed out. But, when I ran the lambda function from within the private subnet, it worked! So it the NAT seems to work since that is what the private sunet was associated with, but just using the internet gateway does not work.
Does anyone have any explanation for this?
For an Amazon Lambda function to connect to the Internet, ONE of the following is required:
The Lambda function is not connected to a VPC, OR
The Lambda function is connected to a private subnet and there is a NAT Gateway/NAT Instance configured, OR
The Lambda function is connected to a public subnet and an Elastic IP address is assigned to the Elastic Network Interface (ENI) being used by the Lambda function in the subnet
Merely connecting a Lambda function to a public subnet (without an EIP) will not provide Internet access.
Related
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:
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.
Lambda functions connected to a VPC public subnet cannot typically access the internet.
To access the internet from a public subnet you need a public IP or you need to route via a NAT that itself has a public IP. You also need an Internet Gateway (IGW). However:
Lambda functions do not, and cannot, have public IP addresses, and
the default route target in a VPC public subnet is the IGW, not a NAT
So, because the Lambda function only has a private IP and its traffic is routed to the IGW rather than to a NAT, all packets to the internet from the Lambda function will be dropped at the IGW.
Should I Configure my Lambda Function for VPC Access?
If your Lambda function does not need to reach private resources inside your VPC (e.g. an RDS database or Elasticsearch cluster) then do not configure the Lambda function to connect to the VPC.
If your Lambda function does need to reach private resources inside your VPC, then configure the Lambda function to connect to private subnets (and only private subnets).
NAT or Not?
If the Lambda function only needs access to resources in the VPC (e.g. an RDS database in a private subnet) then you don't need to route through NAT.
If the Lambda function only needs access to resources in the VPC and access to AWS services that are all available via private VPC Endpoint then you don't need to route through NAT. Use VPC Endpoints.
If your Lambda function needs to reach endpoints on the internet then ensure a default route from the Lambda function's private subnets to a NAT instance or NAT Gateway in a public subnet. And configure an IGW, if needed, 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.
Best Practices
When configuring Lambda functions for VPC access, it is an HA best practice to configure multiple (private) subnets across different Availability Zones (AZs).
Intermittent Connectivity
Be sure that all the subnets you configure for your Lambda function are private subnets. It is a common mistake to configure, for example, 1 private subnet and 1 public subnet. This will result in your Lambda function working OK sometimes and failing at other times without any obvious cause.
For example, the Lambda function may succeed 5 times in a row, and then fail with a timeout (being unable to access some internet resource or AWS service). This happens because the first launch was in a private subnet, launches 2-5 reused the same Lambda function execution environment in the same private subnet (the so-called "warm start"), and then launch 6 was a "cold start" where the AWS Lambda service deployed the Lambda function in a public subnet where the Lambda function has no route to the internet.
You can make a lambda function access the public internet from within your VPC, you just need to make sure you really need it.
For accessing resources external to AWS such as Google API (like OP's example) you do need a Public IP. For other cases like RDS or S3 you don't need Public IP, you can use a VPC Endpoint, so communication between your Lambda and the desired AWS Service doesn't leave AWS network.
By default some AWS Services are indeed reached via public internet, but it doesn't have to be.
[EDIT]
Someone was concerned about scalability in the comments, but they missed this from AWS Docs:
"Multiple Lambda functions can share a network interface, if the functions share the same subnet and security group"
Also, you must have a Public IP for reaching Public Internet, whether you're using Lambda, EC2, ECS, even if you use a NAT Gateway it needs an Elastic Public IP if you want to reach the public internet through it.
Solution
To do that, you need to assign Elastic Public IPs to the Network Interfaces for each subnet linked to your lambda. First let's figure which subnets and security groups are linked to your lambda:
Next, go to EC2 Service, find the Public IPs menu under Network & Security. Allocate one IP for each subnet (in the example above there are two subnets).
Go to Network Interfaces menu, find the network interfaces attached to your lambda (same subnet and security group).
Associate the Public IPs in the actions menu for each one:
That's it, now your Lambda can reach out to public internet.
I am trying to run the command “aws lambda list-functions” from an ec2 inside my private subnet that I connected to using a bastion host. The lambda has been deployed to the same VPC and private subnet, but when I try to run the command it times out. They are in the same region, and I have been able to connect to some of my other services within this ec2 but can’t connect to my lambda service endpoint.
I tried connecting from an ec2 inside a public subnet and that worked fine, but can't connect from ec2 inside the private subnet.
You have two options for that:
Setup NAT gateway in a public subnet along with route tables entries directly internet traffic in a private subnet to the NAT.
Setup VPC interface endpoint for lambda so that you can connect to the lambda service without needing internet connectivity.
I've created a VPC (due to the RDS connectivity needs inside the lambdas) in AWS which has internet access most of the time, but some times my outside requests timeout (mostly these happen with SES as they're the majority of outside requests). I've configured my VPC the following way (sorry, not in the created order, just reading them off AWS):
VPC with 172.30.0.0/16 CIDR
3 private subnets with 172.30.0.0/24, 172.30.1.0/24, 172.30.2.0/24 and a different availability zone for each (1a, 1b, 1c) with 0.0.0.0/0 route targeting my NAT
1 public subnet with 172.30.3.0/24 to 1a availability zone with a 0.0.0.0/0 route targeting my IGW
2 route tables (private and public) with the 3 private subnets in the private route table and the public one in it's own
Security groups for lambdas directing all outbound traffic to 0.0.0.0/0
Lambdas are configured to use these subnets and the given security group.
I'm not understanding why my internet requests some times fail from inside the VPC, it's almost as if the lambda gets started at some availability zone and that specific one does not have access to the internet inside the vpc.
EDIT: Resolved! I had the public subnet listed in my lambda function which caused the timeouts
AWS Lambda functions that are connected to a VPC should always be configured to use private subnets.
If those Lambda functions also require Internet access, they can use a NAT Gateway or NAT Instance to reach the Internet. These NAT services should be configured to use the public subnet(s).
When the Lambda function is connected to a private subnet, then traffic destined for the Internet will be routed from the private subnet, through the NAT Gateway/NAT Instance, and out to the Internet. This will not work if the Lambda function is connected to a public subnet. (And a Lambda function cannot connect directly from a VPC to the Internet.)
I have a lambda function which is in a VPC, with an internet gateway. The security group connected to the lambda has all the inbound and outbound routes open. The route table is also updated. The lambda is still not able to access the internet. Am I missing anything?
Lambda in a VPC does not have access to internet. You need to setup internet gateway in public subnet and NAT gateway in private subnet with your lambda to be able to access internet. From docs:
Connect your function to private subnets to access private resources. If your function needs internet access, use NAT. Connecting a function to a public subnet does not give it internet access or a public IP address.
Also you need to add permissions to your lambda's execution role to be able to create network interface in VPC:
ec2:CreateNetworkInterface
ec2:DescribeNetworkInterfaces
ec2:DeleteNetworkInterface
I am now trying to configure a route table for a private subnet, and I config an AWS Lambda function with these subnets. When I use an ENI, I will receive a ssl error (violation of protocol) when I was trying to make an API call through Internet (like a call to the ServiceNow API). When I use NAT, it works.
I investigate for a while, but still confused about when should we use ENI (or nat)? What is the difference?
When an AWS Lambda function is not connected to a VPC, it has direct access to the Internet.
When an AWS Lambda function is connected to a VPC, and requires access to the Internet, then the configuration should be:
Associate the Lambda function with a private subnet in the VPC
Create a NAT Gateway in a public subnet
Configure the Route Table for the private subnet to route 0.0.0.0/0 traffic to the NAT Gateway
You probably received the error because the Lambda function was unable to reach the endpoint on the Internet. I don't know why you specifically received an "SSL Error".
An Elastic Network Interface (ENI) is the virtual network connection between a resource (eg an AWS Lambda function) and a VPC. Think of it like a 'network card' that connects it to the network.
A NAT Gateway is a service that does IP address translation. It accepts the local traffic and sends it to the Internet, also passing back responses. It enables Internet access from private subnets while preventing inbound access to the private subnet.