AWS Lambda function times out when trying to reach an SQS service from inside a VPC.
Lambda functions can be deployed in three ways:
- Without VPC, where they can communicate with a public network, but cannot talk to any of our internal (VPC) AWS services
- Inside a VPC, where they can communicate with our VPC services but cannot reach the Internet
- Inside a VPC with NAT, where they can communicate with both our VPC services as well as talk to the Internet
We want to configure the latter, so that we can reach VPC based RDS as well as read public SQS queues.
AWS Configuration
We need (at least) two different subnets to, one public and one private. Lambda uses private subnets while inside a VPC.
A public subnet has its default route set to a igw-xxxxxxxx internet gateway (IGW) object. A private subnet has its default route set to a NAT instance or a NAT Gateway.
Therefore we need both the IGW and the NAT gateway for this to work.
Subnets
Create a new VPC and two subnets inside it. Or use an existing VPC if you have one, we use the once called DEV1. Please note that CIDR may and likely will differ.
Route Tables
Create two routing tables assigned to the VPC DEV1 we created the subnets in.
Internet Gateway and NAT Gateway
Create an internet gateway:
Create a NAT gateway. Make sure that the NAT gateway is created inside the subnet EC2-SUBNET, extremelly important!
Attach Gateways to Route Tables
Attach the internet gateway to the route table EC2-to-public:
Attach the NAT gateway to the route table Lambda-to-public:
Associate Subnets to Route Tables
Associate the subnet EC2-SUBNET with the route table EC2-to-public:
Associate the subnet LAMBDA-SUBNET with the route table Lambda-to-public:
That’s it, Lambda functions should now be able to talk to both VPC and public services.
Lambda Function Access to SQS
This part is optional, we are going to run a test.
SQS Queue
Create a new SQS queue, note the queue URL.
Lambda Function
Create a Python based Lambda function with the following code:
from __future__ import print_function import uuid import json import boto3 print('Loading function') def lambda_handler(event, context): delete_message = False message = {"Message":"Test message."} messageAttribut_id = str(uuid.uuid1()) sqs = boto3.resource('sqs') queue = sqs.Queue('https://sqs.eu-west-1.amazonaws.com/XXXXXXXXXXXX/DEV-QUEUE') SQS_response = queue.send_message(MessageBody=json.dumps(message), MessageAttributes={messageAttribut_id: {'StringValue': "Test message.", 'DataType': 'String'}}) if SQS_response: send_response = {"Status":"OK", "Message" : "Message sent"} else: send_response = {"Status":"Error", "Message" : "Error could not send message"} for message in queue.receive_messages(MaxNumberOfMessages=1, MessageAttributeNames=[messageAttribut_id]): receive_response = {"Status":"OK", "Message" : json.loads(message.body)} if delete_message: message.delete() return {"Message_Deleted":delete_message, 'GUID':messageAttribut_id, "send_response":send_response, "receive_response":receive_response}
The function is going to send a test message to the queue. The message can be deleted if you set delete_message to True.
Add the function to the VPC DEV1 and the subnet LAMBDA-SUBNET:
Test the function, there should be messages sent to the SQS queue:
Really good tutorial! Help me a lot. Thanks
You’re welcome!