I’m working with an AWS CloudFormation template to deploy a serverless application that requires a Lambda function with internet access and a PostgreSQL RDS instance that I need to access remotely for management purposes. After modifying my subnet and route table associations to enhance security, my Lambda lost internet access, and I was unable to connect to my RDS instance remotely. I’m looking for guidance on how to adjust my CloudFormation template to meet these requirements.
My requirements:
AWS Lambda function that requires internet access for outbound requests.
PostgreSQL RDS instance that needs to be accessible from my local machine for management.
Below is a simplified version of my CloudFormation template highlighting the relevant resources:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
MyVPC:
Type: 'AWS::EC2::VPC'
Properties:
CidrBlock: '10.0.0.0/16'
EnableDnsSupport: true
EnableDnsHostnames: true
MyInternetGateway:
Type: 'AWS::EC2::InternetGateway'
DependsOn: "MyVPC"
AttachGateway:
Type: 'AWS::EC2::VPCGatewayAttachment'
Properties:
VpcId: !Ref MyVPC
InternetGatewayId: !Ref MyInternetGateway
MyRouteTable:
Type: 'AWS::EC2::RouteTable'
Properties:
VpcId: !Ref MyVPC
MyRoute:
Type: 'AWS::EC2::Route'
DependsOn: AttachGateway
Properties:
RouteTableId: !Ref MyRouteTable
DestinationCidrBlock: '0.0.0.0/0'
GatewayId: !Ref MyInternetGateway
MySubnetA:
Type: 'AWS::EC2::Subnet'
Properties:
VpcId: !Ref MyVPC
CidrBlock: '10.0.1.0/24'
AvailabilityZone: !Select [0, !GetAZs '']
MapPublicIpOnLaunch: false
MySubnetB:
Type: 'AWS::EC2::Subnet'
Properties:
VpcId: !Ref MyVPC
CidrBlock: '10.0.2.0/24'
AvailabilityZone: !Select [1, !GetAZs '']
MapPublicIpOnLaunch: false
MyDBSubnetGroup:
Type: 'AWS::RDS::DBSubnetGroup'
Properties:
SubnetIds:
- !Ref MySubnetA
- !Ref MySubnetB
MySecurityGroup:
Type: 'AWS::EC2::SecurityGroup'
Properties:
VpcId: !Ref MyVPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 5433
ToPort: 5433
CidrIp: 10.0.0.0/16 # VPC internal
- IpProtocol: tcp
FromPort: 5433
ToPort: 5433
CidrIp: 'X.X.X.X/32' # MYLOCALIP
MyDBInstance:
Type: 'AWS::RDS::DBInstance'
Properties:
Engine: postgres
Port: '5433'
DBSubnetGroupName: !Ref MyDBSubnetGroup
VPCSecurityGroups:
- !Ref MySecurityGroup
PubliclyAccessible: true
MyEIP:
Type: 'AWS::EC2::EIP'
Properties:
Domain: vpc
MyPublicSubnet:
Type: 'AWS::EC2::Subnet'
Properties:
VpcId: !Ref MyVPC
CidrBlock: '10.0.3.0/24'
AvailabilityZone: !Select [0, !GetAZs '']
MapPublicIpOnLaunch: true
MyNatGateway:
Type: 'AWS::EC2::NatGateway'
Properties:
AllocationId: !GetAtt MyEIP.AllocationId
SubnetId: !Ref MyPublicSubnet
MyPrivateRouteTable:
Type: 'AWS::EC2::RouteTable'
Properties:
VpcId: !Ref MyVPC
PrivateRoute:
Type: 'AWS::EC2::Route'
DependsOn: MyNatGateway
Properties:
RouteTableId: !Ref MyPrivateRouteTable
DestinationCidrBlock: '0.0.0.0/0'
NatGatewayId: !Ref MyNatGateway
SubnetARouteTableAssociation:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
SubnetId: !Ref MySubnetA
RouteTableId: !Ref MyPrivateRouteTable
SubnetBRouteTableAssociation:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
SubnetId: !Ref MySubnetB
RouteTableId: !Ref MyPrivateRouteTable
PublicSubnetRouteTableAssociation:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
SubnetId: !Ref MyPublicSubnet
RouteTableId: !Ref MyRouteTable
SenderFunction:
Type: AWS::Serverless::Function
Properties:
PackageType: Image
VpcConfig:
SubnetIds:
- !Ref MySubnetA
- !Ref MySubnetB
SecurityGroupIds:
- !Ref MySecurityGroup
Issue:
My Lambda has external internal access but I can’t access my RDS from my localhost.
I tried to switch the association:
SubnetARouteTableAssociation:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
SubnetId: !Ref MySubnetA
RouteTableId: !Ref MyRouteTable
SubnetBRouteTableAssociation:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
SubnetId: !Ref MySubnetB
RouteTableId: !Ref MyRouteTable
PublicSubnetRouteTableAssociation:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
SubnetId: !Ref MyPublicSubnet
RouteTableId: !Ref MyPrivateRouteTable
The result is that I can access my RDS remotely but then I lost internet access inside my Lambda.
I also tried to ask ChatGPT and he didn’t succeed to help! ๐
My Question:
How can I adjust my CloudFormation template to ensure that my Lambda functions have internet access while also maintaining remote access to my RDS instance?
Any advice on how to structure my VPC, subnets, route tables, or any other configuration to achieve these goals would be greatly appreciated.
2
Answers
You need to create public subnets (subnets with a route to the Internet Gateway) to place the RDS instance in. The RDS instance has to be in public subnets for you to access it directly from your localhost. The NAT Gateway also needs to be in a public subnet.
The Lambda function has to be in private subnets (subnets with a route to the NAT Gateway). The Lambda function doesn’t need to be in the same subnets as the RDS instance, it just needs to be in the same VPC.
So you need at least two public subnets (for the RDS), and at least two private subnets (for the Lambda function).
Once you configure it this way, the Lambda function will be able to access all the resources in the VPC (such as the RDS instance) as well as resources on the Internet (via the NAT Gateway).
For best security, it is recommended to always keep the database in a private subnet. The database can be accessed by anything running in the VPC.
You mention that you "need to access remotely for management purposes" — if this is just occasional access and isn’t needed for the app itself, then you can still connect to a database in a private subnet by:
This might seem like extra work and extra cost (and it is!), but it adds another layer of security to protect the database.
As for your Lambda function, you don’t mention whether it also needs to access the database: