Cloud Unfold

unfolding the cloud trivia

LambdaVPC

Does my vpc based lambda have internet access?

Some use cases need a Lambda function to be in a vpc with internet access. Whilst Lambda makes networking configurations quite simple, it can still get a bit tricky at times, especially debugging. We can definitely check the individual components but that can take a while, and there are chances where we can miss something too. In this article, we will write a sample script which you can use to test your function vpc configurations.

You can find the script here, and if you’d like to go through the steps you can follow along with the below steps.

We first start off with fetching the Lambda configurations using

lambda.getFunctionConfiguration()

From these configs we will get the VpcConfigs, if the function does not have a vpc association, it has internet access.

If the function is associated with a vpc, we need to perform three checks to confirm if the function has internet access:

  1. Is Lambda associated with private subnets with NAT Gateway(s)?
  2. If this NAT Gateway(s) is in a Public Subnet?
  3. Do the Lambda security groups allow outbound traffic?

Check 1: Is Lambda associated with private subnets?

As we know, the function in a vpc always needs to be in private subnets, and verifying if these associated subnets are private are not, is as simple as checking if these subnets have route to Internet Gateway. If the route to Internet Gateway exists then its a Public subnet otherwise its a private subnet, however for a Lambda in a vpc to have internet access a NAT Gateway is required, so we have to check if the private subnet with NAT Gateway exists.

  • Get all the route table details using
    ec2.describeRouteTables(params)
  • Check if any route with NATGW exists:
    for each route in all_routes:
        if route.NatGatewayId 
            return 'Private'
    return 'Public'
    

If all the function subnets are Private with NAT Gateway, then the check will pass, else if you have multiple subnets associated with the function then list the public subnets so that they can be removed or altered.

Check 2: If this NAT Gateway(s) is in a Public Subnet?

From the above step, we know how to check if a subnet is private or not. We use the same approach to check if the NAT Gateway is placed in a Public Subnet. Again, a public subnet is a subnet with a route to an Internet Gateway.

  • Get NAT Gateway Ids for all the subnet Ids using
    ec2.describeRouteTables(params)
  • Get all the route tables in a subnet and for each route in a route_table check if there exists a route for NatGatewayId
let natGwIds = []
for (let routeTableConfig of response) {
    for (let routeConfig of routeTableConfig.RouteTables) {
        for (let route of routeConfig.Routes) {
            if (route.DestinationCidrBlock === '0.0.0.0/0' && route.NatGatewayId)
                natGwIds.push(route.NatGatewayId)
        }
    }
}
return natGwIds

Check 3: Do the Lambda security groups allow outbound traffic?

Next, for a Lambda to have internet access it needs to be able to make outbound requests. These outbound requests can be restricted to certain ports, and CIDRs. For simplicity, we will consider HTTP and HTTP outbound ports and 0.0.0.0/0 for all outbound traffic.
  • start with all the associated security groups and using
    ec2.describeSecurityGroups(params)

    for each security group check if there exists an outbound (egress) rule for HTTP/HTTPS or ALL_TRAFFIC with 0.0.0.0/0

  • If at least one of the SG has this outbound rule, Lambda will have internet access
let sgResponse = await ec2.describeSecurityGroups(params).promise()
// console.log(sgResponse.SecurityGroups[0])
for (let securityGroup of sgResponse.SecurityGroups) {
    // console.log(securityGroup)
    for (let egress of securityGroup.IpPermissionsEgress) {
        let groupId = securityGroup.GroupId
        let groupName = securityGroup.GroupName

        // ALL Traffic
        if (egress.IpProtocol === ALL_TRAFFIC &&
            egress.IpRanges[0].CidrIp === '0.0.0.0/0') {
            console.log(`\t - ${groupId} (${groupName}) allows All outbound traffic`)
            outboundTrafficAllowedForAll = true
        }
        // Outbound Traffic for HTTP/HTTPS
        else if ('FromPort' in egress)
            if (egress.FromPort === HTTP && egress.IpRanges[0].CidrIp === '0.0.0.0/0')
                console.log(`\t - ${groupId} (${groupName}) allows HTTP traffic only`)
            else if (egress.FromPort === HTTPS && egress.IpRanges[0].CidrIp === '0.0.0.0/0')
                console.log(`\t - ${groupId} (${groupName}) allows HTTPS traffic only`)

    }
}

Lastly if all the above checks pass, we can confirm that the function will have internet access, otherwise the script will list the issues that are blocking the internet access.

Note here we are only looking at the basic and most common configs which could block the internet access for vpc based Lambda, however there can be additional configs like NAT Gateway blackhole, using custom DNS server for vpc, or not using AmazonProvidedDNS as a fallback, vpc DHCP options for DNS and hostname resolutions, vpc peering and/or virtual or transit Gateways. We have not considered all of them assuming that the rest of the things are configured correctly on your end and still with the above configs Lambda fails to access internet.

How to use the script?

Using this script is as simple as creating a new Lambda function with the script, adding the name of the function for which you want to check vpc configs in the script, deploy and Test. You can also use it from your EC2 instance or any client where you have AWS credentials configured to be used with Lambda actions.

Hope that helps!

Was it helpful?

Just another lazy guy

LEAVE A RESPONSE

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

Related Posts