Invoke Private API Gateway Without Host/x-apigw-api-id Headers - amazon-web-services

I have a private API Gateway stage with an associated VPC endpoint, and I have already followed the instructions here: https://aws.amazon.com/premiumsupport/knowledge-center/api-gateway-vpc-connections/
on how to connect to my API from inside the VPC.
Using the Host/x-apigw-api-id works as expected, but I have some services that are third-party and I cannot add those headers to make them connect.
Is there any way to connect to an endpoint-specific hostname WITHOUT either Host or x-apigw-api-id header?
e.g.
(current) curl "https://vpc-endpoint-specific-hostname/route/" -H 'x-apigw-api-id: '
(desired) curl "https://.vpc-endpoint-specific-hostname/route/" (note no headers)
I know what the documents say, which is to use either of the two headers Host/x-apigw-api-id but I cannot add those headers for some of my services.

if you enable private DNS, you can access the private API directly using this url
https://{restapi-id}.execute-api.{region}.amazonaws.com/{stage}
you can get read more here

Even If you don’t have Private DNS enabled, you can still reach the Private API Gateway by using custom domains (which are technically not supported by Private API Gateways), we can ‘trick’ the VPC endpoint into understanding where to send traffic, without custom Host / x-apigw-api-id headers.
Steps:
Create an internal-only Application Load Balancer
The ALB needs to point to the IP addresses of the ENIs for the Interface VPC Endpoint - API Gateway (Steps to Create Interface VPC endpoint - API Gateway)
Make sure that you have a DNS entry - example.com(in Route 53 or any other DNS provider) that points to the above load balancer we created.
Make sure the ACM certificate is created for the above custom domain - example.com
Navigate to the API Gateway console and click Custom Domain Names in the left menu bar. Select Regional and fill in your custom hostname and ACM certificate we created in steps 3 & 4
Please find the detailed steps here.

Related

Static IP for GCP API Gateway

Is there a native option to setup a static IP address for a google cloud API Gateway? As far as I researched, looks like I have to setup a cloud load balancer in front of the API Gateway and then use the static IP of the load balancer. I am not sure how to do this. My goal is to only give access to my API gateway via IP address? I am looking for any documentation/articles on this regard. Thanks in advance.
I don't know and don't understand your requirement, but you can achieve this with a trick with HTTPS load balancer.
Create an external HTTPS load balancer. Use HTTP frontend (so not secure/encrypted) else you will have certificate's checks issues if you use HTTPS with a certificate and if you hit the IP.
Create an internet network endpoint group that points to your API Gateway URL
If it doesn't work, add a header in your backend service named host and with the API gateway base URL as value (without the https:// prefix)
I don't like this design because you add a useless layer (and thus an additional (and useless) potential point of failure) and you will be charge for the load balancer (about $15 per month)

Plumbing for API Gateway to Beanstalk with SSL

I am looking to host an API which I can control customer access to using API Keys, Usage Plans, and Cognito. This is my first time trying to bootstrap DNS+SSL and I can't figure out the basic plumbing to get SSL working when I connect API gateway to my beanstalk environment.
I've got example.com purchased on namecheap. I've got namecheap DNS set up to forward the api subdomain to AWS DNS via an NS record. I've got an API gateway with a custom domain name of api.example.com mapped to an API with a production stage. I've then got route 53 set up to point api.example.com to that API gateway stage. I can curl api.example.com and because I have a cognito user pool authenticator, I see Unauthorized as the response.
What I'm stuck on is how to connect this to my elastic beanstalk environment. My current attempt involves turning the API Gateway into a "HTTP Proxy", and tweaking the endpoint url. Except I'm not sure what to put there, or how to configure what I put there because the Test button in API GW often throws an error.
I'm currently trying to use the domain name of the load balancer in front of beanstalk: https://load-balancer-in-front-of-beanstalk-endpoint.com/{proxy}. I've tried a few configs on that load balancer, but I'm not sure what cert to give it because when I try api.example.com,
it fails with "Host name dualstack.awseb.foo.elb.amazonaws.com does not match the cert provided by peer(api.example.com)".
Some other questions mentioned setting an alias for api.example.com to point to the load balancer's ip... except for me it already points to the API GW, so I think I've gone wrong somewhere. Could use some pointers.

Allow request from API Gateway to private ALB

I have a public API gateway set up, I want to forward the requests from API Gateway to a private ALB in the VPC. On AWS Console, for API Gateway VPC link setup I could only select an NLB in the VPC.
Is there a reason why we can only route to NLB and not to ALB?
Is there a way I can route to private ALB from the API Gateway?
Currently AWS only supports connecting to NLB for VPC link integrations. They have a feature request in place to enable support for ALB as well. For now, you can do -
Public API --> VPC Link --> NLB --> ALB
In the target groups of the NLB, add the private IPs of the ALB. This way you can reap benefits of the NLB (TCP layer) and ALB (HTTPS).
Using static IP addresses for Application Load Balancers
The selected answer is outdated. It is possible to have API Gateway integrate, thorugh http, with an internal facing ALB by using VPC Link and private resource integration.
For step by step details, see my answer on another question: https://stackoverflow.com/a/67413951/2948212
edit: I see I was confusing this post with another one... I believe my answer still adds value though, so I am leaving it (I thought this specified REST API Gateways and not HTTP API Gateways, but it does not).
Answer
While #diegosasw's answer is valid and useful, it is for AWS HTTP API Gateways, not AWS REST API Gateways.
With that being said, they are correct in saying it is possible! Please see the following AWS documentation regarding how to accomplish this: https://aws.amazon.com/premiumsupport/knowledge-center/api-gateway-application-load-balancers/
Please note one particular downside of AWS's documented approach: it requires a public ALB. Of course this is not ideal, though one can still harden their ALB so that it only accepts traffic originating from the REST API Gateway. If this is not acceptable for the existing use case, then #Suraj Bhatia's answer above must be followed (for REST API integrations, at least). If HTTP Gateways are acceptable, then #diegosasw's answer is the better approach to take due to it being simpler to manage and still allowing for a private ALB 🙂
For prosperity, AWS's documentation states the following:
Note: The following procedure assumes two things:
You have access to a public Application Load Balancer and its DNS
name. You have an API Gateway REST API resource with an HTTP method.
In the API Gateway console, choose the API you want to integrate with the Application Load Balancer.
In the Resources pane, for Methods, choose the HTTP method that your API uses.
Choose Integration Request.
In the Integration Request pane, for Integration Type, choose HTTP.
Note: To pass the entire API request and its parameters to the backend
Application Load Balancer, create one of the following instead: An
HTTP proxy integration
-or- An HTTP custom integration
For more information, see Set up HTTP integrations in API Gateway.
In the Endpoint URL field, enter either the Application Load Balancer's default DNS name or custom DNS name. Then, add the
configured protocol of its listener. For example, an Application Load
Balancer that's configured with an HTTPS listener on port 8080
requires the following endpoint URL format: https://domain-name:8080/
Important: Make sure that you create an HTTP listener or HTTPS
listener for the Application Load Balancer using the port and listener
rules of your choice. For more information, see Listeners for your
Application Load Balancers. For an Application Load Balancer
configured with an HTTPS listener, the associated certificate must be
issued by an API Gateway-supported certificate authority. If you have
to use a certificate that's self-signed or issued by a private
certificate authority, then set insecureSkipVerification to true in
the integration's tlsConfig.
Choose Save.
Deploy the API.

AWS: Can I give a Lambda function inside a VPC access to a public Websockets API Gateway?

I have a public API in API Gateway using Websockets protocol. I'm storing its connection IDs in a datastore inside my VPC, and trying to write a Lambda to read those connection IDs and then send data to each of them - using await apigwManagementApi.postToConnection({ ConnectionId: connectionId, Data: postData }).promise();. This times out - the Lambda is unable to send messages to the API gateway. So I tried adding a Gateway to execute-api: aws ec2 create-vpc-endpoint --vpc-id vpc-xyz --vpc-endpoint-type Interface --service-name com.amazonaws.eu-west-1.execute-api --subnet-ids subnet-xyz --security-group-id sg-xyz. Now I get ForbiddenException: Forbidden thrown by my calls to apigwManagementApi.
I've tried looking at the docs for the execute-api Gateway, but the doc for Interfaces https://docs.aws.amazon.com/vpc/latest/userguide/vpce-interface.html points to https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-private-apis.html and leads to creating private APIs - I don't want this, I need my API to be public.
I think I might be able to use a resource policy usually https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-resource-policies-examples.html But this is a websocket API so these instructions don't work as they don't have a resource policies option.
I asked about this on the AWS Slack and it's not possible to use resource policies and would add a lot of networking complexity: https://awsdevelopers.slack.com/archives/C6LDW0BC3/p1570618074008500
From an AWS dev in that thread:
hey there - when Lambda is VPC enabled, its subject to all routing rules of your VPC and Subnet.
To hit any public resource, you will need a NAT GW, routing rules, and SG setting to allow communication.
Resource polices will not work.
I had the same problem - this document explains the reason for it (https://aws.amazon.com/premiumsupport/knowledge-center/api-gateway-vpc-connections/).
To fix it you need to add an edge-optimized custom domain name, which entails the following:
Add a certificate into AWS ACM (you'll need the cert, private key
and provider root cert) into us-east-1 ACM manager (you have to
add it to us-east-1 to see it in the edge-optimized cert list).
In the API Gateway console go to Custom Domain Names and Create a new one.
Set your domain name, leave the type as edge-optimized and apply the cert that you just created
Once the domain is set up (it takes around 40 minutes) you can add base path mappings to send traffic to your apis / stages.

How to CNAME to Amazon API Gateway Endpoint

I'm trying to set a CNAME on Cloudflare to point to an Amazon API Gateway endpoint. The CNAME is for use when referring to one of my subdomains. The gateway in turn points to the IP of a server on DigitalOcean. I am very new to Amazon web services and would appreciate if someone could give me an overview of the correct configuration for the DNS, Amazon Gateway and Cloudfront (which I think is needed to expose the gateway to DNS servers external to Amazon). Any help would be much appreciated.
UPDATE
I've been going at this for a while now and not making much progress. Does anyone have an idea if this is a viable approach or how else it might be done?
UPDATE2
I thought I needed to add the CNAME record to cloudFlare and just ended up in a redirect loop, observed by:
curl -L -i -v https://sub.mydomain.com/
NOTE: It seems this method doesn't work anymore as AWS now only accepts certificates from certain authorities. I haven't tested it myself, but the answer by Gunar looks promising.
There are several reasons why it doens't work to simply point Cloudflare at your API Gateway domain and call it a day:
API Gateway uses shared hosting so it uses the domain name to figure out what API to send requests to. It has no way of knowing that api.yourdomain.com belongs to your API.
API Gateway requires that you use https, but the certificate that it uses is only valid for the default domain.
There is a solution, however. Here are the steps that I followed when I recently set this up:
Generate an origin certificate from the crypto tab of the Cloudflare dashboard.
Import the certificate to AWS Certificate manager in the us-east-1 region, even if your API is located in a different region. If you are prompted for the certificate chain you can copy it from here.
Add your custom domain in the API Gateway console and select the certificate you just added. Check the AWS support article for more information on how to do this.
It usually takes about 45 minutes for the custom domain to finish initializing. Once it's done it will give you a new Cloudfront URL. Go ahead and make sure your API still works through this new URL.
Go to the Cloudflare DNS tab and setup a CNAME record pointing to Cloudfront URL you just created.
Switch to the crypto tab and set your SSL mode to "Full (Strict)". If you skip this step you'll get a redirect loop.
That's it. Enjoy your new highly available API served from your custom domain!
Set up Amazon's API Gateway Custom Domain with CloudFlare
In your AWS management console go to the API Gateway service and select Custom Domain Names from the left menu.
Click the Create button.
Log into CloudFlare, select your domain and open the Crypto tab
Go to SSL and set your SSL mode to "Full (Strict)" to avoid a redirect loop.
Go to Origin Certificates and click Create Certificate
Let CloudFlare generate a private key and a CSR and choose RSA as the private key type
Make sure that the hostname for your custom API domain is covered. (e.g. api.mydomain.com. You can specifically configure this custom domain or use a wildcard such as *.mydomain.com as is configured by default.
Pick PEM as the key format which is selected by default.
In AWS switch to region US-EAST-1 and goto the Certificate Manager.
Click Import a Certificate.
Copy the certificate body from your CloudFlare certificate to Certificate body to the configuration of the custom domain in the AWS Management Console.
Copy the Private key to the certificate private key field in the console
In the certificate chain copy the Cloudflare Origin CA - RSA Root which can be found here.
Enter your custom domain name in the AWS console and a name for your certificate
Now the custom domain name will be created in AWS CloudFront. It can take up to an hour before the domain becomes active.
The next thing you need to do is set up the mappings of the custom domain in the AWS Console.
The final step is to create a new CNAME Record in CloudFlare to link your domain to the CloudFront url. When you open the settings page of your custom domain in the AWS console copy the Distribution domain name. This is the domain you need to use when creating the new CNAME Record.
Source
I couldn't get any of the other answers to work. So I ended up having AWS generate the certificate instead of using a Cloudflare Origin one. That's because AWS wouldn't accept my Cloudflare certificate, even when the chain was provided. I couldn't see Cloudflare in Mozilla's Certificate Authority list (which is what AWS relies on, according to the docs) so I guess that makes sense.
Here's the outline of my solution:
Create AWS Route53 Zone
Create AWS ACM Certificate (must be in us-east-1) with validation method DNS
Create Cloudflare DNS Record with the output of (2)
Create AWS API Gateway Domain Name
Create Cloudflare DNS CNAME Record pointing '#' (root domain) to the Cloudfront domain name from step (4)
Create AWS API Gateway Base Path Mapping
This should be roughly it. May this help someone. Feel free to ask questions.
Both existing answers to this question are correct, but if the issue still persists even after following these directions perfectly, try going into the API Gateway settings, navigate to "Custom Domain Name" and configure the Base Path Mappings.
This was the missing step that solved all my problems.