1

I'm trying to assign a static ip to multiple lambdas so that when a lambda makes a call to a specific service I can whitelist that ip.

I was able to get this working but as far as I can tell, it will randomly start either taking almost exactly 2 minutes to return where before it was 500ms or just start timing out all together.

Below is the cloudformation I used to setup this VPC and in this cloudformation I setup the following:

  • Public Subnet
  • Private Subnet
  • NAT Gateway
  • Elastic IP
  • 2 Routes (public/private)
  • Internet Gateway
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description": "AWS CloudFormation for VPC",
    "Parameters": {
        "env": {
            "Type": "String"
        }
    },
    "Resources": {
        "VPCStaticIP": {
            "Type": "AWS::EC2::VPC",
            "Properties": {
                "CidrBlock": "11.0.0.0/16",
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Join": [
                                "",
                                ["lambavpc", "-", { "Ref": "env" }]
                            ]
                        }
                    }
                ]
            }
        },
        "SubnetPublic": {
            "Type": "AWS::EC2::Subnet",
            "Properties": {
                "CidrBlock": "11.0.0.0/24",
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Join": [
                                "",
                                [
                                    "lambavpc",
                                    "-",
                                    { "Ref": "env" },
                                    "-",
                                    "public-subnet"
                                ]
                            ]
                        }
                    }
                ],
                "VpcId": {
                    "Ref": "VPCStaticIP"
                }
            }
        },
        "SubnetPrivate": {
            "Type": "AWS::EC2::Subnet",
            "Properties": {
                "CidrBlock": "11.0.1.0/24",
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Join": [
                                "",
                                [
                                    "lambavpc",
                                    "-",
                                    { "Ref": "env" },
                                    "-",
                                    "private-subnet"
                                ]
                            ]
                        }
                    }
                ],
                "VpcId": {
                    "Ref": "VPCStaticIP"
                }
            }
        },
        "InternetGateway": {
            "Type": "AWS::EC2::InternetGateway",
            "Properties": {
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Join": [
                                "",
                                ["lambavpc", "-", { "Ref": "env" }, "-", "igw"]
                            ]
                        }
                    }
                ]
            }
        },
        "VPCGatewayAttachment": {
            "Type": "AWS::EC2::VPCGatewayAttachment",
            "Properties": {
                "InternetGatewayId": {
                    "Ref": "InternetGateway"
                },
                "VpcId": {
                    "Ref": "VPCStaticIP"
                }
            }
        },
        "RouteTablePublic": {
            "Type": "AWS::EC2::RouteTable",
            "Properties": {
                "VpcId": {
                    "Ref": "VPCStaticIP"
                },
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Join": [
                                "",
                                [
                                    "lambavpc",
                                    "-",
                                    { "Ref": "env" },
                                    "-",
                                    "public-route"
                                ]
                            ]
                        }
                    }
                ]
            }
        },
        "RoutePublic": {
            "Type": "AWS::EC2::Route",
            "Properties": {
                "DestinationCidrBlock": "0.0.0.0/0",
                "GatewayId": {
                    "Ref": "InternetGateway"
                },
                "RouteTableId": {
                    "Ref": "RouteTablePublic"
                }
            }
        },
        "SubnetRouteTableAssociationPublic": {
            "Type": "AWS::EC2::SubnetRouteTableAssociation",
            "Properties": {
                "RouteTableId": {
                    "Ref": "RouteTablePublic"
                },
                "SubnetId": {
                    "Ref": "SubnetPublic"
                }
            }
        },
        "EIP": {
            "Type": "AWS::EC2::EIP",
            "Properties": {
                "Domain": "vpc",
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Join": [
                                "",
                                ["lambavpc", "-", { "Ref": "env" }, "-", "eip"]
                            ]
                        }
                    }
                ]
            }
        },
        "NatGateway": {
            "Type": "AWS::EC2::NatGateway",
            "Properties": {
                "AllocationId": {
                    "Fn::GetAtt": ["EIP", "AllocationId"]
                },
                "SubnetId": {
                    "Ref": "SubnetPublic"
                }
            }
        },
        "RouteTablePrivate": {
            "Type": "AWS::EC2::RouteTable",
            "Properties": {
                "VpcId": {
                    "Ref": "VPCStaticIP"
                },
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Join": [
                                "",
                                [
                                    "lambavpc",
                                    "-",
                                    { "Ref": "env" },
                                    "-",
                                    "private-route"
                                ]
                            ]
                        }
                    }
                ]
            }
        },
        "RoutePrivate": {
            "Type": "AWS::EC2::Route",
            "Properties": {
                "DestinationCidrBlock": "0.0.0.0/0",
                "NatGatewayId": {
                    "Ref": "NatGateway"
                },
                "RouteTableId": {
                    "Ref": "RouteTablePrivate"
                }
            }
        },
        "SubnetRouteTableMainAssociationPrivate": {
            "Type": "AWS::EC2::SubnetRouteTableAssociation",
            "Properties": {
                "RouteTableId": {
                    "Ref": "RouteTablePrivate"
                },
                "SubnetId": {
                    "Ref": "SubnetPrivate"
                }
            }
        }
    },
    "Outputs": {}
}

I've done quite a bit of research and turned up these references:

but I can't seem to reason what the delta is between what I'm doing and what they are suggesting.

Any suggestions would be greatly appreciated it!

amcdnl
  • 8,470
  • 12
  • 63
  • 99

2 Answers2

2

The EIP timeouts probably because you do not have DependsOn attribute on your AWS::EC2::VPCGatewayAttachment. This is required in your case:

If you define an Elastic IP address and associate it with a VPC that is defined in the same template, you must declare a dependency on the VPC-gateway attachment by using the DependsOn Attribute on this resource.

Thus, you could try the following which adds the dependency:

"EIP": {
    "Type": "AWS::EC2::EIP",
    "DependsOn" : "VPCGatewayAttachment",    
    "Properties": {
        "Domain": "vpc",
        "Tags": [
            {
                "Key": "Name",
                "Value": {
                    "Fn::Join": [
                        "",
                        ["lambavpc", "-", { "Ref": "env" }, "-", "eip"]
                    ]
                }
            }
        ]
    }
}

Also, if possible, I would consider using a private IP range of 10.0.0.0/16 for your VPC and subnets instead of 11.0.0.0/16. The range is recommended to be used by AWS:

When you create a VPC, we recommend that you specify a CIDR block (of /16 or smaller) from the private IPv4 address ranges as specified in RFC 1918:

  • 10.0.0.0 - 10.255.255.255 (10/8 prefix)
  • 172.16.0.0 - 172.31.255.255 (172.16/12 prefix)
  • 192.168.0.0 - 192.168.255.255 (192.168/16 prefix)
amcdnl
  • 8,470
  • 12
  • 63
  • 99
Marcin
  • 215,873
  • 14
  • 235
  • 294
  • My reading of the question is that the Lambda function execution times out, not the creation of the EIP. – Mark B Aug 26 '20 at 12:36
  • @MarkB Hi. The tittle suggest that EIP timeouts in my view. Regardless, it still needs dependency on the IGW attachment. – Marcin Aug 26 '20 at 12:38
  • @MarkB - No sorry - its NOT the lambda from what I can tell since it works fine without the VPC. – amcdnl Aug 26 '20 at 12:40
  • @amcdnl I'm fairly certain it is the way you have configured the Lambda to deploy into the VPC (the one thing you left out of your question), not the VPC configuration itself. If the issue is the EIP assignment to the NAT Gateway, then it should be easy to login to the AWS console to verify that the EIP is not assigned to the NAT Gateway. – Mark B Aug 26 '20 at 12:41
  • @MarkB There could be multiple issues. DependsOn is one of them. The other could be, as you suggest, using a wrong subnet. – Marcin Aug 26 '20 at 12:45
  • @MarkB - I was manually selecting the vpc in the lambda config. – amcdnl Aug 26 '20 at 12:46
  • @Marcin any other recommendations for the other cidrs ? – amcdnl Aug 26 '20 at 12:49
  • @amcdnl I would suggest `10.0.0.0/16` for VPC, and `10.0.0.0/24` and `10.0.1.0/24`,. So its same as you have, but with 10 (not 11) to be in line with AWS recommendation. – Marcin Aug 26 '20 at 12:51
  • 1
    @Marcin - I tweaked your json since it was incorrect. Please make sure its valid now. :D – amcdnl Aug 26 '20 at 13:21
  • @Marcin - Quick update - After applying these updates it still seems to timeout :( - I posted a blog post on my final config - https://dev.to/amcdnl/static-ips-for-aws-lambdas-14e7 – amcdnl Jan 20 '21 at 12:34
  • @amcdnl Thank you. I will check it out:-) – Marcin Jan 20 '21 at 12:38
2

You don't show how you are creating the Lambda function, is that created outside of CloudFormation? It sounds like you have the Lambda function configured to use both VPC subnets, and when it runs inside the public subnet it is getting timeouts. You need to configure the Lambda function to only use the private subnet with a route to the NAT Gateway.

Mark B
  • 183,023
  • 24
  • 297
  • 295
  • 1
    To expand upon this... When an AWS Lambda function is connect to an Amazon VPC, it can communicate with all resources in the VPC, but it cannot access the Internet. An Elastic IP address is a **public IP address**, which needs access to the Internet. Therefore, the VPC would need to be configured with a NAT Gateway in the public subnet and the Lambda function should be connected to a private subnet that has a route table entry pointing to the NAT Gateway. If the Elastic IP address belongs to a resource **in the same VPC**, then it should communicate via the **private IP address** instead. – John Rotenstein Aug 27 '20 at 04:35