Configure AWS NAT Gateway for Lambda Functions to Access Public SQS Queues from VPC

AWS Lambda function times out when trying to reach an SQS service from inside a VPC.

Lambda functions can be deployed in three ways:

  1. Without VPC, where they can communicate with a public network, but cannot talk to any of our internal (VPC) AWS services
  2. Inside a VPC, where they can communicate with our VPC services but cannot reach the Internet
  3. 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:

2 thoughts on “Configure AWS NAT Gateway for Lambda Functions to Access Public SQS Queues from VPC

Leave a Reply

Your email address will not be published. Required fields are marked *