Invoking a Private EC2 Instance from a Lambda Function

The Problem

Recently, we worked on an AWS serverless application, which had an EC2 instance that provided some supportive function to the application. This EC2 implementation was running on a public subnet in a custom VPC. The serverless Lambda functions primarily ultilized the EC2 public IP address to communicate with this instance.

However, the recent security assessment done with the help of AWS Security Hub service [1] gave us some level of indication about the security status of the application. 

The assessment indicated that it has violated a security setting (EC2 instances should not have a public IPv4 address), which is related to the AWS Foundational Security Best Practices v1.0.0 [2]category. This control basically checks whether EC2 instances have a public IP address associated with them. 

The Solution

In general, when it comes to accessing a private EC2 instance hosted in a VPC private subnet, we can use VPC Endpoints [3] to access that instance from another VPC. This approach can certainly improve network latency and security since the traffic flows through within the AWS infrastructure itself.

However, if we are to connect to a private EC2 instance hosted in a VPC from a Lambda function, we probably would utilize the same strategy that we used in VPC Endpoints but in a different way. It would be bit different since the Lambda invocation does not happen within a VPC. 

When you connect a Lambda function to a VPC, Lambda creates an Elastic Network Interface (ENI) for each subnet in your function’s VPC configuration (see Figure 1).

Just like you find execution roles being attached in VPC Endpoints, Lambda also utilizes its permissions/roles to create and manage network interfaces of a particular EC2 instance. We need to update the function's execution role and add the following permissions to it.

Execution role permissions

  • ec2:CreateNetworkInterface
  • ec2:DescribeNetworkInterfaces
  • ec2:DeleteNetworkInterface

These permissions are included in the AWS managed policy AWSLambdaVPCAccessExecutionRole

Go to your Lambda execution role and attach the above AWS managed policy to the Lambda role. Now your Lambda has all the required permissions to connect to the VPC. 

You can configure the VPC when you create the function, but I’m going to configure a VPC for an existing function [4].

  1. Open theFunctions page on the Lambda console.
  2. Choose a function.
  3. Choose Configuration and then choose VPC.
  4. Under VPC, choose Edit.
  5. Choose a VPC, subnets, and security groups.
    To access our private instance, we need to connect our function to private subnets. That requires a minimum of two private subnets. Attach security groups and make sure that security groups allow required ports and protocols depending on your requirement.
  6. Choose Save.

Now try to access your private instance through the Lambda function. In my requirement, my private instance runs an application server that I can access through a private IP and the port. 

protocol://privateIP:port/path

http://10.0.0.15:8080/health

I think you have now understood the primary idea behind this implementation. You can try and change/improve your implementation if you have a similar requirement.

References


  1. AWS Security Hub: www.aws.amazon.com/security-hub
  2. AWS Foundational Security Best Practices Controls: www.docs.aws.amazon.com/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html
  3. VPC Endpoints: www.docs.aws.amazon.com/vpc/latest/privatelink/vpc-endpoints.html

4. www.docs.aws.amazon.com/lambda/latest/dg/configuration-vpc.html

Thiwanka Wickramage

Associate Tech Lead