16

I have an AWS CDK stack with a lambda function that needs to insert into an RDS database. When the stack is deployed, the lambda function cannot access the database and gives an error: getaddrinfo ENOTFOUND [RDS endpoint as defined by me]. After manually adding the VPC, subnets and Security group that the RDS database is in, the lambda function works correctly.

How do you define the VPC, Subnets and Security group in AWS CDK, preferably in TypeScript? In as far as there is documentation, I tried:

const vpc = ec2.Vpc.fromLookup(this, "VPC", { vpcName: "myVPC" });

const securityGroup = ec2.SecurityGroup.fromSecurityGroupId(
  this,
  "SG",
  "sg-XXXXX"
);

const subnet1a = ec2.PrivateSubnet.fromSubnetAttributes(this, "SUBNET1A", {
  subnetId: "eu-central-1a"
});

const myLambda = new lambda.Function(this, "myLambda", {
  runtime: lambda.Runtime.NODEJS_12_X,
  code: lambda.Code.fromAsset("lambda"),
  handler: "myLambda.handler",
  description: "myLambda",
  environment: {
    DB_HOST: "XXXX",
    DB_USER: "XXXX",
    DB_PASSWORD: "XXXX",
    DB_NAME: "XXXX"
  },
  vpc: vpc,
  vpcSubnets: [subnet1a],
  securityGroups: [securityGroup]
});

When running cdk deploy This gives an AWS CDK error: "Not possible to place Lambda Functions in a Public subnet Subprocess exited with error 1"

Any help is welcome.

jarmod
  • 71,565
  • 16
  • 115
  • 122
Robin
  • 612
  • 1
  • 5
  • 12

4 Answers4

7

Here is a simple example, hope it helps:

//get VPC Info form AWS account, FYI we are not rebuilding we are referencing
const DefaultVpc = Vpc.fromVpcAttributes(this, 'vpcdev', {
    vpcId:'vpc-d0e0000b0',
    availabilityZones: core.Fn.getAzs(),
    privateSubnetIds: 'subnet-00a0de00',
    publicSubnetIds: 'subnet-00a0de00'
});

const YourService = new lambda.Function(this, 'LambdaName', {
    code: lambda.Code.fromAsset("lambda"),
    handler: 'handlers.your_handler',
    role: lambdaExecutionRole,
    securityGroup: lambdaSecurityGroup,
    vpc: DefaultVpc,
    runtime: lambda.Runtime.PYTHON_3_7,
    timeout: Duration.minutes(2),
});
Optimus
  • 1,354
  • 1
  • 21
  • 40
grepit
  • 21,260
  • 6
  • 105
  • 81
5

If you want to deploy a Lambda function into a VPC then you should deploy it into a private subnet (one that has subnetType: SubnetType.PRIVATE) or an isolated subnet (one that has subnetType: SubnetType.ISOLATED).

Which you choose depends on whether or not the Lambda function needs outbound internet access. If it does, then use PRIVATE, otherwise use ISOLATED.

To reach an RDS instance in the same VPC, the Lambda function should be placed in a Security Group that has inbound access on the relevant port number to the RDS instance's security group.

Example of VPC here and Lambda here.

jarmod
  • 71,565
  • 16
  • 115
  • 122
  • Following up to this question: can the lambda be placed in an ISOLATED subnet while the Rest GatewayApi that exposes this lambda be placed in a PRIVATE subnet? – Sammy Apr 08 '20 at 09:49
  • 1
    @Sammy Traffic from API Gateway to your Lambda function doesn't arrive at your Lambda function via regular VPC networking. It's delivered by the API Gateway to the Lambda service control plane and then it's presented by the Lambda service data plane to your Lambda function. The Lambda function can be in any kind of subnet - the choice you make will impact its outbound networking. That's my understanding of how it works. – jarmod Apr 08 '20 at 10:16
  • Thank you @jarmod, yes indeed: my lambda function cannot access the Internet (outbound) even though I added a NAT Instance to my vpc. Any idea how I should go about for giving it outbound internet access? – Sammy May 06 '20 at 14:56
  • The Lambda function should be in a private subnet. The private subnet's default route should be a NAT or NAT Gateway in a public subnet (which has an IGW). – jarmod May 06 '20 at 15:31
  • Ah, maybe the problem is that I’ve placed it in an ISOLATED instead of a PRIVATE subnet. I’ll try switching. – Sammy May 07 '20 at 05:52
  • This doesn't seem to work: I have 1 vpc, and 2 isolated subnets (A&B). With my RDS in A and Lambda in B. When my RDS has a security group that allows incoming traffic on 3306 from B my lambda still times out. This answer is incomplete. – Jesper Bylund Oct 01 '20 at 09:54
0

Your code to configure a lambda with vpc is fine. Your 'subnet1a' is a public subnet and It is recommended to not define any backend service in public subnets. AWS documentation for lambda and vpc configuration Another link for reference

Choose private or isolated subnets for lambda.

nirvana124
  • 903
  • 1
  • 9
  • 12
0

This seems to work (CDK version 2.89.0; I needed subnets too, so I left it in case it's useful):

import * as ec2 from "aws-cdk-lib/aws-ec2"

const myVPC = ec2.Vpc.fromLookup(this, 'myVPC', {
  vpcId: 'vpc-.......',
});

const mySecurityGroup = ec2.SecurityGroup.fromSecurityGroupId(this, 'mySecurityGroup'+env_tag, 'sg-0d304999aa281a0db')


const mySubnet = ec2.Subnet.fromSubnetId(this, 'mySubnet', 'subnet-.....')  

const functionToConsole = new lambda.Function(this, entity_name+'ToConsole', {
  ...
  vpc: myVPC,
  vpcSubnets: { subnets: [mySubnet]},
  securityGroups: [mySecurityGroup],
}); 
Gabriele
  • 420
  • 4
  • 15