Provisioning a Lambda Function in a VPC with Internet Access Using AWS CDK
In today's cloud architectures, securing your resources within a Virtual Private Cloud (VPC) while maintaining necessary internet access is a common requirement. AWS Lambda functions, by default, do not have internet access when placed in a VPC, which can be a hurdle for functions needing to interact with external services or APIs. This guide will walk you through provisioning a Lambda function within a VPC and enabling it to access the internet using the AWS Cloud Development Kit (CDK).
To achieve this, we need to:
Grant the Lambda function permissions to create and manage elastic network interfaces (ENIs).
Place the function in a private subnet configured with a route to a NAT gateway for internet access.
Configure the security group to allow necessary outbound access.
By following these steps, we ensure that our Lambda function can securely interact with the internet while residing within a VPC. Let's dive into the process of creating the VPC and Lambda function with AWS CDK.
AWS CDK Code for VPC and Lambda Function
import { Duration, Stack, StackProps } from 'aws-cdk-lib';
import { IpAddresses, SubnetType, Vpc } from 'aws-cdk-lib/aws-ec2';
import { Runtime, Function, Code} from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';
import { join } from 'path';
export class LambdaFunctionVpcStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const vpc = new Vpc(this, 'my-vpc', {
ipAddresses: IpAddresses.cidr('10.0.0.0/16'),
natGateways: 1,
maxAzs: 3,
subnetConfiguration: [
{
name: 'private-subnet-1',
subnetType: SubnetType.PRIVATE_WITH_EGRESS,
cidrMask: 24,
},
{
name: 'public-subnet-1',
subnetType: SubnetType.PUBLIC,
cidrMask: 24,
},
],
});
const lambdaFunction = new Function(this, 'my-lambda-function', {
runtime: Runtime.NODEJS_20_X,
vpc,
vpcSubnets: {
subnetType: SubnetType.PRIVATE_WITH_EGRESS,
},
memorySize: 1024,
timeout: Duration.seconds(5),
handler: 'index.handler',
code: Code.fromAsset(join(__dirname, '/../lambda')),
});
}
}
Explanation
We start by creating a VPC with both public and private subnets. The Lambda function is launched in the private subnet, and the VPC provisions one NAT Gateway to allow internet access from the private subnet.
Lambda Function Permissions and Security
The Lambda function created within the VPC has the necessary permissions to manage network interfaces, provided by the AWSLambdaVPCAccessExecutionRole
managed policy, which is automatically attached by CDK.
Since we haven't explicitly provided a security group, CDK creates a default security group with the following rules:
Inbound Rule
Type: All Traffic
Protocol: All
Port: All
Source: default-SG-id
Outbound Rule
Type: All Traffic
Protocol: All
Port: All
Destination: 0.0.0.0/0
The default security group allows all outbound traffic, and since security groups are stateful, responses to outbound requests are automatically allowed.
Lambda Function Code (lambda/index.js
)
exports.handler = async function(event) {
console.log("request:", JSON.stringify(event, undefined, 2));
return {
statusCode: 200,
body: JSON.stringify('hello from lambda in a vpc!'),
};
};
Deployment
To deploy the stack, run:
npx aws-cdk deploy
or
cdk deploy
After deployment, the Lambda function is launched in the VPC, associated with the private subnets, and able to access the internet via the NAT Gateway.
Clean Up
To delete the resources and avoid ongoing costs from the NAT Gateway, run:
npx aws-cdk destroy
or
cdk destroy
Summary
In this guide, we successfully provisioned a Lambda function within a VPC that can access the internet. The AWS CDK simplified the process by handling the VPC components, role creation, and security group configuration. If your Lambda function doesn't need internet access, set allowPublicSubnet
to true
to place it in a public subnet, acknowledging this limitation.
The complete code for this post can be found on Github using below link: