Blog post
Giving VPC Lambdas Internet Access using Serverless Framework
Giving VPC Lambdas Internet Access using Serverless Framework
Nikola Jovanovic
2021-06-09
In the last tutorial, we showed how to connect to an RDS using an RDS Proxy with a Lambda function. To do this, we needed to put the Lambda in the same VPC as the RDS and the RDS Proxy. This, of course, makes Lambda lose internet access. In this tutorial, I will show you how to fix this.
This tutorial will continue from where the last one left off and we will be building the example app.
First, we will create a Lambda function which we will use to test internet access. Add this in the serverless.yml
file under the functions
section:
1 testInternetAccess:
2 handler: lib/handlers/testInternetAccess.handler
3 events:
4 - http:
5 path: test-internet-access
6 method: get
This is how the testInternetAccess.js
file looks like:
1const fetch = require('node-fetch')
2
3const testInternetAccess = async (event, context) => {
4 console.log(JSON.stringify({ event, context }))
5
6 let response
7 try {
8 console.log('Fetching data')
9 const res = await fetch('https://jsonplaceholder.typicode.com/posts/1')
10
11 if (!(res.status >= 200 && res.status < 300)) {
12 throw new Error('Unsuccessful API response')
13 }
14
15 response = {
16 statusCode: 200,
17 body: JSON.stringify({
18 internetStatus: 'Online',
19 data: await res.json()
20 })
21 }
22 } catch (error) {
23 console.error(error)
24 response = {
25 statusCode: 500,
26 body: JSON.stringify({
27 internetStatus: 'Offline',
28 error: error.message
29 })
30 }
31 }
32
33 console.log(response)
34 return response
35}
36
37module.exports.handler = testInternetAccess
You can deploy this function now by running:
1$ serverless deploy --stage dev
Send a GET request to the endpoint shown in the terminal after the deployment has finished. You’ll get a response which looks something like this: {"message": "Internal server error"}
. If you check CloudWatch logs for the testInternetAccess
Lambda, it should tell you that the Lambda had timed out after a certain amount of time. This is expected behavior if your Lambda doesn’t have internet access.
Now we’ll be starting setting up the resources which grant our Lambdas internet access. We’ll begin by creating two more Subnets in our VPC. One for each availability region which we’re already using. We’ll also create a NAT Gateway for one of the previously created Subnets. The Subnet which we choose must have an Internet Gateway in its Route Table. We’ll add the following code anywhere in the VpcResources.yml
file:
1SubnetAPrivate:
2 Type: AWS::EC2::Subnet
3 Properties:
4 VpcId: !Ref VPC
5 AvailabilityZone: ${self:provider.region}a
6 CidrBlock: ${self:custom.VPC_CIDR}.0.2.0/24
7 Tags:
8 - Key: "Name"
9 Value: "SubnetAPrivate"
10
11SubnetBPrivate:
12 Type: AWS::EC2::Subnet
13 Properties:
14 VpcId: !Ref VPC
15 AvailabilityZone: ${self:provider.region}b
16 CidrBlock: ${self:custom.VPC_CIDR}.0.3.0/24
17 Tags:
18 - Key: "Name"
19 Value: "SubnetBPrivate"
20
21EIP:
22 Type: AWS::EC2::EIP
23 Properties:
24 Domain: vpc
25
26NATGateway:
27 Type: AWS::EC2::NatGateway
28 Properties:
29 AllocationId: !GetAtt EIP.AllocationId
30 SubnetId: !Ref SubnetA
Update the vpc
section of the serverless.yml
file to look like this:
1vpc:
2 securityGroupIds:
3 - !Ref LambdaSecurityGroup
4 subnetIds:
5 - !Ref SubnetAPrivate
6 - !Ref SubnetBPrivate
Next, we need to create a Route Table with a Route with a NAT Gateway and associate the newly created private Subnets to that Route Table. Add this code anywhere in the RoutingResources.yml
file:
1RouteTablePrivate:
2 Type: AWS::EC2::RouteTable
3 Properties:
4 VpcId: !Ref VPC
5 Tags:
6 - Key: "Name"
7 Value: "RouteTablePrivate"
8
9RoutePrivate:
10 Type: AWS::EC2::Route
11 Properties:
12 DestinationCidrBlock: 0.0.0.0/0
13 NatGatewayId: !Ref NATGateway
14 RouteTableId: !Ref RouteTablePrivate
15
16RouteTableAssociationSubnetAPrivate:
17 Type: AWS::EC2::SubnetRouteTableAssociation
18 Properties:
19 RouteTableId: !Ref RouteTablePrivate
20 SubnetId: !Ref SubnetAPrivate
21
22RouteTableAssociationSubnetBPrivate:
23 Type: AWS::EC2::SubnetRouteTableAssociation
24 Properties:
25 RouteTableId: !Ref RouteTablePrivate
26 SubnetId: !Ref SubnetBPrivate
That’s it. Now you can deploy your stack and test if your Lambdas have internet access using the testInternetAccess
Lambda.
Suppose you have any deployment errors; check your stack in the AWS CloudFormation console. Go to the Events
tab, and there you’ll see which resources failed, why, and when.
Nikola Jovanovic
2021-06-09
Nikola is software engineer with a problem solving mindset, in love with JavaScript and the whole ecosystem. Passionate about frontend and backend work.
Leave your thought here
Your email address will not be published. Required fields are marked *