skip to Main Content

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


  1. 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).

    Login or Signup to reply.
  2. 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:

    • Connecting to an EC2 instance in the public subnet via SSH
    • Then using Port Forwarding to provide access to the database

    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:

    • If it does need to access the database, then the Lambda function needs to be connected to a private subnet in the VPC and a NAT Gateway needs to be in a public subnet (charges apply) to give it access to the Internet.
    • If it does not need access to the database, then do not connect the Lambda function to the VPC and it will automatically receive Internet access.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search