Provisioning a Lambda Function in a VPC with Internet Access Using AWS CDK

Provisioning a Lambda Function in a VPC with Internet Access Using AWS CDK

Featured on Hashnode

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:

  1. Grant the Lambda function permissions to create and manage elastic network interfaces (ENIs).

  2. Place the function in a private subnet configured with a route to a NAT gateway for internet access.

  3. 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.

💡
The complete code for this post is available on Github and the link can be found in the end of this post.

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.

💡
NAT Gateways incur an hourly charge of about $0.045 in the us-east-1 region.

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.

💡
Remember to destroy the stack to avoid unnecessary costs, because we provisioned a NAT Gateway, which has an hourly billing rate.

The complete code for this post can be found on Github using below link:

Did you find this article valuable?

Support Mikaeel Khalid by becoming a sponsor. Any amount is appreciated!