I have provisioned an AWS API Gateway and created a Lambda function to connect to an external REST API. The API Gateway & Lambda is not in a VPC so the egress IP address is random. The challenge I have is the external REST API is behind a firewall, which requires the IP address or subnet of the Lambda to be whitelisted.
I have looked at the AWS IP Address page (below), however there is no explicit mention of either API Gateway or Lambda.
https://docs.aws.amazon.com/general/latest/gr/aws-ip-ranges.html#filter-json-file
Has anyone come across this before & found a resolution to it. For the purposes of this solution I cannot put the API Gateway & Lambdas in a VPC.
Any help would be greatly appreciated!
API Gateway seems to be irrelevant to this discussion. If I understand your question, you're trying to make API requests from a Lambda function to a remote API server and you want those requests to originate from a known IP address so that you can whitelist that IP at the remote server.
First thing I would say is don't use IP whitelisting; use authenticated API requests instead.
If that's not possible then use VPC with an Internet Gateway (IGW). Create a NAT and an Elastic IP, launch the Lambda into a private subnet of that VPC, and route the subnet's non-local traffic to the NAT. Then whitelist the NAT's Elastic IP on the remote API server. Examples here and here.
I know that you said you "cannot put [...] Lambdas in a VPC", but if you don't then you have no control over the originating IP address.
It is frustrating that the only way to ensure a Lambda function uses a static ip without a hack is to put the Lambda inside a VPC, create a NAT with an Elastic IP, as many other answers nicely explain.
However, NATs cost around $40 per month in regions that I am familiar with, even with minimal traffic. This may be cost prohibitive for certain use cases, such as if you need multiple dev/test/staging environments.
One possible workaround (which should be used with caution) is to create a micro EC2 instance with an elastic IP (which gives the static IP address), then your choice of proxy/routing so you can make HTTP calls by tunnelling from the Lambda function through the EC2 instance. (e.g. SSH from Lambda function into EC2 instance then CURL from EC2 to the endpoint which is protected by an allowlist)
This is a few extra hoops to jump through and could introduce security vulnerabilities which should be mitigated (e.g. Beware storing SSH keys or passwords inside a Lambda function, ensure Security Groups are tight) but I wanted to post this as a possible workaround for any devs who need a cost effective workaround for a requirement to connect to an endpoint which enforces allowlist rules.
Related
I have a lambda function, that has an API Gateway attached to it. It has a publicly accessible IP address and a domain name (Created by the serverless framework). I can access it from the broad internet, from my own browser (and other devices).
The issue is, it seems to be inaccessible from other services on my account, like an EC2 instance. From the mentioned instance, curl google.com works and returns a response, but curl mylink.com times out.
I think this has something to do with VPC setup, but I can't put my finger at it. What might be the issue here?
Update: Using curl --verbose, I found out that while accessed from anywhere else, the IP the API Gateway is leading to is different, than when accessed from within my AWS account. The VPC doesn't seem to matter, I created a new VPC, an EC2 instance inside it, and it still did the same.
Based on the comments.
The issue was caused by the presence of VPC interface endpoint for API Gateway in the default VPC. The VPC interface endpoint for API gateway is used for private API, not public APIs as used be the OP. Subsequently, calls to public API endpoints fail, as explained in AWS blog:
When they’re configured as private, the public networks are not made available to route your API. Instead, your API can only be accessed using the interface endpoints that you have configured.
There are two ways to combat the issue:
disable Private DNS Name option for the endpoint, or
remove the endpoint.
In the OP's case, the second option was used to solve the problem.
The EC2 instance likely lives inside a VPC which doesn't have public internet access (or may but through a load balancer, bastion host, or any myriad of other options).
You'll need to find out which VPC the EC2 instance lives in, and ensure your lambda function has access to it. You can add a function to a VPC by following the documentation
Lets say I have a service running clustered on N ec2 instances. On top of that I have Amazon EKS and Elastic Loadbalancer. There is a service not managed by me running outside of AWS where I have an account that my services in AWS are using via HTTP requests. When I made an account to this external service I was asked for an IP (range) of services which will be using this external service. There is my problem. Currently lets say I have 3 EC2 instances with Elastic IP addresses (which are static), so I can just give those three IP addresses to this external service provider and everything works just fine. But in the future I might add more EC2 instances to scale out and whitelisting new IP addresses in the external service is a pain. In some cases those whitelist change requests may take for a week to approve by the external service provider and I dont have that time. Even further, accessing this external service is the only reason I go for static IPs for the EC2 instances. So if possible I would ditch the Elastic IPs.
So my question is how could I act so that if I make requests outside of the AWS in a random instance in my cluster, external service providers would always see the same IP address for me as a service consumer?
Disclaimer: I actually dont have that setup running yet, but I am in the middle of doing research if that would be a feasible option. So forgive me if my question sounds dumb for some obvious reason
Something like Network address translation (NAT) can solve your problem. A NAT gateway with Elastic IP, used for rerouting all traffic through it.
NAT gateway provided by AWS as service can be expensive if your data traffic is big, so you can make your own NAT instance, but that is bit complicated to set up and maintain.
The main difference between NAT gateway and NAT instance are listed here
The example bellow is assumed that EC2 instances are in private subnet, but it doesn't have to be a case.
I believe you need a proxy server in your environment with an Elastic IP. Basically you can use something like NGINX/Apache and configure it with an elastic IP. Configure the webserver to provide an endpoint to your EC2 instances, and doing a proxy pass to the external endpoint.
For high availability, you can manage a proxy in each availability zone, ideally configured using an auto scaling group to keep at leaset one instance alive in each AZ. Going through this approach, you will need to make sure that you assign the public IP from your elastic IP pool.
Generally, hostnames are better alternative to the IP addresses to avoid such situations as they can provide a static endpoint no matter what is the IP behind. Not sure whether you can explore that path with your external API provider. It can be challenging when there is static IP based routing/whitelisting rules in place.
This is what a NAT Gateway is for. NAT Gateways have an Elastic IP attached and allow the instances inside a VPC to make outbound connections, transparently, using the gateway's static address.
I am looking to assign a static IP to my Lambda which is being invoked via the API gateway. This is required because, the downstream system that i invoke from this lambda accepts web requests only from a Whitelisted IP.
I am successful in achieving this via the VPC that i associate with my lambda. But VPC introduces a bad cold-start time which sometime ranges 12-16seconds. So i am looking for a way to prevent this cold start from the VPC, but at the same time assign a static IP to the lambda.
You will need to:
Create a VPC with an Internet Gateway, a public subnet and a private subnet
Attach the AWS Lambda function to the private subnet
Launch a NAT Gateway in the public subnet and update the Route Table of the private subnet to use the NAT Gateway
The NAT Gateway will use an Elastic IP address (which is a static IP address). All traffic from the Lambda function to the Internet will come from this IP address, which can be used in the whitelist.
You might think that this is a bit of overkill for simply attaching a static IP address, but multiple Lambda function can run in parallel and they could run in multiple Availability Zones. Sending all traffic through the NAT Gateway is the only way to ensure they all have the same IP address. (Or, to be more specific, one IP address per AZ in which the NAT Gateway is launched.)
You can't assign a public/static IP to any Lambda function.
Your only good option is to deploy into a VPC with an Internet Gateway and configure routing from the Lambda's subnet through a NAT which has an Elastic IP. Then your target host can whitelist the Elastic IP.
Also see:
Public IP address for AWS API Gateway & Lambda (no VPC) - Stack Overflow
AWS Lambda functions with a static IP – Matthew Leak – Medium
I agree with the answer by John for having static IP whitelisting part. However, it won't resolve your cold start problem because lambda,if ideal, actually takes a small time to start. So I would recommend you also create a Cloudwatch event to hit lambda periodically to resolve this or write a simple code(either in lambda or somewhere else) which sends an empty request periodically so that cold start problem is resolved. You can view the improvement in X-Ray. This is an overhead but one time process.
To eliminate cold starts, you can use a service like https://lambdawarmer.com to keep a desired number of lambda instances always warm.
It basically uses a bunch of servers to periodically and exactly concurrently hit an endpoint on your lambda to keep a certain number of lambdas always warm.
I want to select specific Elastic IP my own when my lambda function executed.
my service has to respond to several situations, and by user's attributes.
Could I write code in a lambda function, that can choose specific my own elastic IP?
I had searched for this. but old information says it cannot do.
but recently I heard about it is possible by using Network Load Balancer or Application Load Balancer.
But I don't know how to use this for the problem.
No. You cannot associate an Elastic IP (EIP) address with an AWS Lambda function.
Well, actually you can, but I wouldn't recommend it. When a Lambda function is associated with a VPC, it connects via an Elastic Network Interface (ENI). It is possible to attach an EIP to an ENI. This also grants access to the Internet if it is attached to a public subnet.
So why avoid it? Because Lambda might create additional ENIs, especially if the Lambda function is frequently invoked and run in parallel. This means it will not have a consistent ENI.
An alternative method is:
Attach the AWS Lambda function to a private subnet
Put a NAT Gateway in a public subnet
Associate an Elastic IP address with the NAT Gateway
All traffic from the Lambda function to the Internet will then come from the NAT Gateway's EIP (however, I don't think you can change that EIP)
Looking at #John Rotenstein's reply: for small systems, with limited calls to the same lambda adding an EIP to the ENI for a lambda could work - if you put a queue in front of the lambda to handle the requests and limit the concurrency of the lambda to 1. That's cheaper than a NAT Gateway (saves around $30) per month. For larger systems, this may not be an issue and you may need the concurrency to be more than one - in that case the NAT gateway is the only way out.
I have an aws api gateway which has a custom domain.
I have to access one of client's api from AWS api gateway.
Those api's will be accessible based on IP address.
If I want to access those api's from aws, I need to know the Ip address of my AWS apigateway.
But I am not sure where I can get this.
Any possibilities to get the static IP address of AWS apigateway?
Unfortunately the API Gateway doesn't support this scenario of invoking an IP-whitelisted API directly. Basically any AWS instance can be used to make the API call and there's many IPs that AWS is using for this.
There are some ways around this, depending on your situation;
If the server you are reaching is within your own VPC, you could create a VPC link (with NLB) and circumvent the IP-whitelist issue. This solution only works for resources within your control.
If the server is external and is expecting a static IP, your best solution is to make your call from within a VPC. To make sure you have a static public IP you can use an elastic IP and a NAT Gateway in your VPC (more info here).
To invoke the external API triggered from the API Gateway you can use a Lambda but because of the VPC a cold start will be quite slow, >10s. To make sure the API will be responding fast you can use an EC2 instance or ECS service on Fargate.
After you clarified your requirements in the comments above it appears that you need your AWS Lambda function, which is being triggered by API Gateway, to appear to a third party as if it has a static outgoing IP address.
The solution to this is to configure your Lambda function to run in your VPC, in a private subnet of your VPC that has a route to a NAT Gateway. Then all outgoing connections from the Lambda function which access resources outside your VPC will use the NAT Gateway's static IP address.