How to map static outbound IP with the AWS Lambda function
Published: 2023-01-29 13:00:50

In this article, I will share how to map elastic IP and make sure that, all the outgoing requests from the lambda function have the same IP address/origin.

### Scenario
There is an External API and it only allows or entertains the requests originating from specific IP addresses which are whitelisted as a part of the policy of the external API.

![Scenario](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yiwau597xmvn5i612oke.png)

Here, we want to invoke/access the external API from the lambda function but there is a problem.

### Problem
The problem here is that the AWS Lambda function does not guarantee the same outbound IP address with each invocation since the AWS Lambda function runs on containers within the AWS environment in AWS-managed VPC and at times the container could run in different execution environments. And different environments have a different IP addresses, hence whitelisting any outbound IP within external IP is not possible since it is bound to change.

![Whitelist IP address flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7ui7hrfvcn3m7o6wzjb6.png)

So how can we assign the static IP to the lambda function and make sure that all the requests made from the Lambda function originate from the same IP address?

### Solution
The solution is to map static/elastic IP to all the outgoing traffic from the lambda function and for that, place the lambda function in VPC. However, as soon as you place the lambda function in VPC, it will lose the internet connectivity and here we want to invoke the external API which is over the internet. Now, to enable internet connectivity, the NAT Gateway & Internet Gateway is also required.

### High-level steps

- Create VPC with Public & Private subnets
- Create NAT Gateway under Public subnet with Elastic IP
- Create Internet Gateway
- Map NAT Gateway within private subnets route table (Source: 0.0.0.0/0 Destination: nat-gateway)
- Map Internet Gateway within public subnet route table (Source: 0.0.0.0/0 Destination: internet-gateway)
- Place lambda function in VPC under Private subnet

![High-level solution](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/przfr37e45afgmhjj0c6.png)

## Hands-On

### Create & Configure VPC
To get started, navigate to VPC Management Console to create the VPC and select VPC and more option to create & configure VPC, subnets, AZs, NAT Gateway & Internet Gateway on a single screen.

![Create VPC](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zet9hctiixxps4ia8raq.png)

Configure the asked details as per your requirement. My configuration is as follows:

- **Name tag auto-generation:** _lambda-elastic-ip_
- **IPv4 CIDR block:** _10.100.0.0/16_
- **IPv6 CIDR block:** _No IPv6 CIDR block_
- **Tenancy:** _Default_
- **Number of Availability Zones (AZs):** _2_
  - **First availability zone:** _us-east-1a_
  - **Second availability zone:** _us-east-1b_
- **Number of public subnets:** _2_
  - **Public subnet CIDR block in us-east-1a:** _10.100.0.0/20_
  - **Public subnet CIDR block in us-east-1b:** _10.100.16.0/20_
- **Number of private subnets:** _2_
  - **Private subnet CIDR block in us-east-1a:** _10.100.128.0/20_
  - **Private subnet CIDR block in us-east-1b:** _10.100.144.0/20_
- **NAT gateways:** _In 1 AZ_
- **VPC endpoints:** _None_
- **DNS options**

    ✓ Enable DNS hostnames
    ✓ Enable DNS resolution

![VPC Setup](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0akrrrqhlxydm7nz9nqc.png)

The above VPC setup will take care of adding necessary routes (NAT & IG mappings) in the respective route tables.

### Create & configure lambda function

Navigate to Lambda Management Console and create the lambda function with Python3.9 as runtime. Post creation, open the relevant IAM role attached with the lambda function and add **AWSLambdaVPCAccessExecutionRole** permission to it.

As a next step, add the below snippet as a part of the function code for testing purposes. The below snippet will invoke (GET) the API Endpoint mentioned as a part of **API_URL**.

```
import json
import urllib3
def lambda_handler(event, context):
    http = urllib3.PoolManager()
    API_URL = "YOUR_API_URL"
    response = http.request("GET", API_URL)
    print(response.data)
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Srce Cde!')
    }
```
_Note: Replace **YOUR_API_URL** with the actual API endpoint._

As a next step, place the lambda function in VPC under private subnets as shown below.

![VPC-Lambda Setup](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9aupvr646b0un0c2io94.png)

### Testing

For testing, I have an external REST API (API Gateway) where I can control which requests to entertain based on the origin (IP address). If you also want to have similar setup then you can follow my tutorial video on [How to whitelist IP address to access API Gateway | REST](https://youtu.be/2ExmCFY2VqQ)

Execution log of the lambda function before adding/whitelisting the Elastic IP address of the lambda function.

![CloudWatch log1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/12j1lw2pdms185rs1w58.png)

Execution log of the lambda function after adding/whitelisting the Elastic IP address of the lambda function.

![CloudWatch log2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8mpbp2lqf4zz3qorylg3.png)

Response “**Successful Invocation!**” is returned from the external API.

Finally, we successfully attached/mapped the Elastic IP address with the AWS Lambda function.

For a detailed step-by-step tutorial and implementation of the above setup, you can refer to the below video.

{% embed https://youtu.be/h2H32_4TvPo %}

If you have any questions, comments, or feedback then please leave them below. [Subscribe to my channel](https://www.youtube.com/srcecde?sub_confirmation=1) for more.