DEV Community

Jiri Spac
Jiri Spac

Posted on • Updated on

How to let lambda access the internet outside of your VPC

This article should not exist. It's absolutely a huge problem when something as trivial, as mundane, as obvious generates such a confusion between your users.
When I was first greeted with this:

Error: There are no 'Private' subnet groups in this VPC. Available types: Public
    at LookedUpVpc.selectSubnetObjectsByType (/home/capaj/work-repos/top-secret/node_modules/aws-cdk-lib/aws-ec2/lib/vpc.js:1:4998)
    at LookedUpVpc.selectSubnetObjects (/home/capaj/work-repos/top-secret/node_modules/aws-cdk-lib/aws-ec2/lib/vpc.js:1:3724)
    at LookedUpVpc.selectSubnets (/home/capaj/work-repos/top-secret/node_modules/aws-cdk-lib/aws-ec2/lib/vpc.js:1:1454)
    at Function.configureVpc (/home/capaj/work-repos/top-secret/node_modules/aws-cdk-lib/aws-lambda/lib/function.js:1:18626)
    at new Function (/home/capaj/work-repos/top-secret/node_modules/aws-cdk-lib/aws-lambda/lib/function.js:1:5676)
    at /home/capaj/work-repos/top-secret/cdk/LambdaStack.ts:93:30
    at Array.forEach (<anonymous>)
    at new LambdaStack (/home/capaj/work-repos/top-secret/cdk/LambdaStack.ts:88:17)
    at Object.<anonymous> (/home/capaj/work-repos/top-secret/bin/backend.ts:58:3)
    at Module._compile (node:internal/modules/cjs/loader:1159:14)

Enter fullscreen mode Exit fullscreen mode

I thought it's going to be easy. I'll just flip a switch somewhere and we will be done.
Nope. AWS Cloud had much more in store for me that day. Hell for a few more days.

These were stack overflow answers I was desperately trying to understand:

This AWS CDK error shows up, when you try to deploy lambdas into your default VPC. If you created your VPC without a "Private" subnet like me and you have a TS infa code like this:

      const lambdaFunction = new lambda.Function(this, `${cron.name}-cron`, {
        memorySize: cron.memorySize ?? 2048,
        timeout: cdk.Duration.minutes(15),
        runtime: lambda.Runtime.NODEJS_18_X,
        architecture: Architecture.ARM_64,
        handler: `${cron.name}.${cron.name}`,
        code: lambda.Code.fromAsset(path.join(__dirname, '../dist'), {
          exclude: [
            ...otherLambdas.map((cron) => `${cron.name}.js`),
            ...otherLambdas.map((cron) => `${cron.name}.js.map`)
          ]
        }),
        environment: envVars,
        securityGroups: [lambdaSecurityGroup],
        vpc,
        vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_EGRESS },
        role: lambdaVPCExecutionRole
      })
Enter fullscreen mode Exit fullscreen mode

It will be failing. At first I though I can just switch a subnet into Private by going into AWS console https://eu-west-1.console.aws.amazon.com/vpc/home?region=eu-west-1#subnets:
but it's not as simple.
This is what you need to do:

  1. create a new subnet. You don't choose whether it is public or private in this step.
  2. create a new network ACL with everything blocked- AWS will recognize the subnet as private if it sees network ACL blocking remote access
  3. now click Image description
  4. go into you cdk.context.json and delete your VPC there. This will force AWS CDK to refresh the subnets in your VPC.

The last remaining bit for the subnet to be PRIVATE_WITH_EGRESS is to create a NAT and add it to your routing table.

  1. Image description

  2. name it, ⚠️ select a PUBLIC subnet. This is where a lot of people make a mistake. If you choose a private subnet when creating NAT, it will not work. NAT needs to be in a public subnet with internet gateway(IGW is available by default).

  3. go create a new route table
    Image description

  4. add your nat as target for 0.0.0.0/0 route Image description

  5. associate the new route table with your subnet: Image description

  6. go into you network ACL add the local ip address of the NAT gateway to both Inbound and Outbound rules. This is needed because ACLs are stateless, whereas with security groups it is enough to have just one sided rule. For ACL ALWAYS make sure to have rules for both sides.

  7. cdk deploy

🚀 Congratulations, now you have deployed your lambda into a PRIVATE_WITH_EGRESS subnet and they will be able to do network call outside of their VPC.

Lambdas are a powerful tool, but this should ideally be a single switch somewhere. A senior developer with no prior AWS experience shouldn't need to spend more than 15 minutes to do this. Some reportedly spent several hours, me included.
ATM it's a very error prone process with a lot of steps to achieve. Thankfully for going the other way, there are function URLs, which greatly simplify deployment and provisioning of lambdas when you need to call them from outside of the VPC. If anyone from AWS team reads this, please consider doing the similar simplification for the other way too.

Top comments (0)