0

I created a single VPC, with 3 subnets: A,B,C

Subnet A and B are private Subnet C is public, meaning it has an internet Gateway with corresponding routing table attached.

Subnet C has a (public) lambda function which tries to access another (private) lambda function in Subnet A,B. However, this public lambda function seems to time out after 10 seconds when trying to access the private lambda function. What am I missing in my networking configuration to make this work?

The cloudformation template used for this experiment is given below:

AWSTemplateFormatVersion: "2010-09-09"

Parameters:
  ProductName:
    Type: String
    Default: 'vpc-test'
    Description: The name of the product
  EnvironmentCode:
    Type: String
    Default: 'test'
    AllowedValues:
      - test
      - stg
      - prod
      - sandbox
    Description: The environment code used in the naming of all AWS services.


Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: "10.0.0.0/16"
      EnableDnsHostnames: true
      EnableDnsSupport: true

  PrivateSubnetA:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Select
        - 0
        - !GetAZs
          Ref: 'AWS::Region' #select the 1st availability zone in the region
      VpcId: !Ref VPC
      CidrBlock: "10.0.0.0/24"

  PrivateSubnetB:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Select
        - 1
        - !GetAZs
          Ref: 'AWS::Region' #select the 2nd availability zone in the region
      VpcId: !Ref VPC
      CidrBlock: "10.0.1.0/24"

  PublicSubnetC:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Select
        - 1
        - !GetAZs
          Ref: 'AWS::Region' #select the 2nd availability zone in the region
      VpcId: !Ref VPC
      CidrBlock: "10.0.2.0/24"
      MapPublicIpOnLaunch: true

  RouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref "VPC"

  InternetGateway:
    Type: "AWS::EC2::InternetGateway"

  VPCGatewayAttachment:
    Type: "AWS::EC2::VPCGatewayAttachment"
    Properties:
      VpcId: !Ref "VPC"
      InternetGatewayId: !Ref "InternetGateway"

  InternetRoute:
    Type: "AWS::EC2::Route"
    Properties:
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: !Ref InternetGateway
      RouteTableId: !Ref RouteTable

  PublicSubnetCRouteTableAssociation:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      RouteTableId: !Ref RouteTable
      SubnetId: !Ref PublicSubnetC

  PublicLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      Architectures:
        - x86_64
      Code:
        ZipFile:
          Fn::Sub: |
            # Imports
            import io
            import boto3
            
            lambda_client = boto3.client('lambda')
            
            def handler(event, context):
                lambda_client.invoke(
                    FunctionName="lambda-${AWS::Region}-${EnvironmentCode}-${ProductName}-subnet-test",
                    InvocationType='RequestResponse',
                    Payload=b''
                )
                return "successfully accessed private lambda function!"

      Description: "function to test VPC s3 endpoint"
      FunctionName:
         Fn::Sub: "lambda-${AWS::Region}-${EnvironmentCode}-${ProductName}-s3-test"
      Handler: "index.handler"
      PackageType: Zip
      Role: !GetAtt LambdaIAMRole.Arn
      Runtime: python3.10
      Timeout: 10
      VpcConfig:
        SecurityGroupIds:
          - Fn::GetAtt: [VPC, DefaultSecurityGroup]
        SubnetIds:
          - Ref: PublicSubnetC

  PrivateLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      Architectures:
        - x86_64
      Code:
        ZipFile: |
          def handler(event, context):
            return "successfully accessed private lambda function!"
      Description: "function to test private subnets within VPC"
      FunctionName:
        Fn::Sub: "lambda-${AWS::Region}-${EnvironmentCode}-${ProductName}-subnet-test"
      Handler: "index.handler"
      PackageType: Zip
      Role: !GetAtt LambdaIAMRole.Arn
      Runtime: python3.10
      Timeout: 10
      VpcConfig:
        SecurityGroupIds:
          - Fn::GetAtt: [ VPC, DefaultSecurityGroup ]
        SubnetIds:
          - Ref: PrivateSubnetA
          - Ref: PrivateSubnetB

  LambdaIAMRole:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName:
        Fn::Sub: "iam-${AWS::Region}-${EnvironmentCode}-lambda-role"
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Policies:
        - PolicyName: 'root'
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - "logs:CreateLogGroup"
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                Resource: arn:aws:logs:*:*:*
        - PolicyName: 'vpc'
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - "ec2:CreateNetworkInterface"
                  - "ec2:DescribeNetworkInterfaces"
                  - "ec2:DeleteNetworkInterface"
                Resource: "*"
        - PolicyName: 'lambda'
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - "lambda:*"
                Resource: "*"

I expected the public lambda function to return "successfully accessed private lambda function!", instead I got a timeout after 10 seconds, which is caused by a networking issue in the VPC.

  • 1
    What do you mean by "tries to access another (private) lambda function"? Lambda functions can't interact directly with other Lambda functions via VPC networking. For Lambda function A to invoke Lambda function B, Lambda function A needs a network route to the AWS Lambda service (either NAT/IGW or VPC Endpoint) – jarmod Jun 09 '23 at 11:33
  • 1
    If your Lambda functions need to be connected to your VPC (do they?) then configure them in the private subnet, [not public subnet](https://stackoverflow.com/questions/52992085/why-cant-an-aws-lambda-function-inside-a-public-subnet-in-a-vpc-connect-to-the). – jarmod Jun 09 '23 at 11:36
  • 1
    As mentioned above, Lambda functions don't communicate directly with each other, ever. The first lambda function is trying to communicate with the AWS Lambda service API, to instruct the AWS Lambda service to invoke the second Lambda function. – Mark B Jun 09 '23 at 12:06
  • When you say "access another (private) lambda function", do you mean you want to **invoke** another Lambda function? – John Rotenstein Jun 09 '23 at 23:40

0 Answers0