When building a serverless application using AWS Lambda, you might need to access external services or resources outside your AWS account. In this case, you must configure your VPC to allow Lambda functions to access external services securely. Amazon VPC (Virtual Private Cloud) provides a secure and isolated environment to deploy your resources, allowing you to control your network configuration.
In this blog post, we will use Terraform to create a VPC to allow access to external services from a Lambda function. We will create public and private subnets in different availability-zones, and configure an internet gateway, a NAT gateway, and route tables to enable communication between the resources.
A nifty little diagram at the bottom of this post shows how all the resources in the Terraform code are connected.
The Terraform code that will build our VPC is a bit lengthy, so it isn't included here for brevity you can find it here.
Now that we have set up our VPC, we can use it to create a Lambda function that has access to external services. To create the Lambda function, we will use the aws_lambda_function
resource in Terraform.
The aws_lambda_function
resource allows us to create and manage AWS Lambda functions. We will specify the following attributes for this resource:
function_name
: the name of the Lambda function we want to create.runtime
: the runtime environment for the Lambda function. In our case, we will use Node.js 18.x (the latest at time of writing).handler
: the name of the file and handler function that the Lambda function will execute.role
: the ARN of the IAM role that the Lambda function will use to access AWS resources.source_code_hash
: the base64-encoded SHA256 hash of the ZIP archive containing the Lambda function's deployment package.vpc_config
: the VPC configuration for the Lambda function, which includes the IDs of the VPC, subnets, and security groups that the Lambda function will use.
Here is an example of how we would use the aws_lambda_function resource to create a Lambda function that can access external services:
1resource "aws_lambda_function" "lambda_function" { 2 function_name = "myapp-lambda-function" 3 runtime = "nodejs18.x" 4 handler = "index.handler" 5 role = aws_iam_role.lambda_role.arn 6 source_code_hash = base64sha256(file("${path.module}/function.zip")) 7 8 vpc_config { 9 subnet_ids = [ 10 aws_subnet.subnet_private_apse2a.id, 11 aws_subnet.subnet_private_apse2b.id 12 ] 13 security_group_ids = [aws_security_group.lambda_security_group.id] 14 vpc_id = aws_vpc.vpc.id 15 } 16}
In the vpc_config
block, we specify the IDs of the two private subnets we created earlier and the ID of the security group we created for the Lambda function. We also specify the ID of the VPC we created earlier.
By specifying the VPC configuration for the Lambda function, we are ensuring that the Lambda function can access external services securely and in a controlled manner while also being able to access resources within the VPC.
In summary, using Terraform to set up a VPC and a Lambda function with VPC configuration is essential for securely accessing external services from within AWS. With this approach, we can ensure that our Lambda function is isolated from the public internet and has controlled access to external services while having access to resources within the VPC.
Caveat - while this is indeed indicative of best practices, the dependency on two NAT Gateways drastically increases your monthly costs. You may want to consider opting for a VPC-less or alternate approach to avoid NAT Gateways, such as using Internet Gateways.