CNAME/Alias Record in front of VPC Endpoint / Private API Gateway - achieve exact behavior of underlying url

0

See my Stack Overflow question for more details.

When setting up a private api gateway with a vpc endpoint, route 53 automatically registers a public DNS record as follows:

https://{rest-api-id}-{vpce-id}.execute-api.{region}.amazonaws.com/{stage}

This url obviously is dependent on the id of the api gateway and vpc endpoint.

My desire

Create an Alias/CNAME record in front of this that won't change when I rebuild the infrastructure (e.g. I'll always point the record at the new {apig-id}-{vpce-id} url). This is so client teams never have to update the url or use any special headers.

Problem

If an alias record is setup to the VPCE, it becomes necessary to pass the apig id in the Host header to actually use it (thus forcing a dependency again on the apig guid).

Is there a DNS only solution to this that doesn't require passing special headers?

  • Obviously this could be done with application logic via a server side redirect, but I want to avoid this. Would be really nice if AWS had the feature of specifying details about the r53 record rather than "secretly" creating an invisible record automatically. I'm looking for a workaround.
3 Answers
1

Hi @Joshua,

Maybe I've been not so clear,

But here it goes, with a little bit more detail

Go to AWS Console, Search API gateway and go to Custom domain names on the left

Create a custom domain, In my case I will use dcaballero.net, for example petapi.dcaballero.net. In order to do this properly you need an AWS ACM certificate, with the base domain dcaballero.net and alternative name wildcard *.dcaballero.net in my case!

Now, after the custom domain for api gateway is created you will see a record named "API Gateway domain name" and it will look like:

<some-id>.execute-api.us-east-1.amazonaws.com

Now, in this custom domain go to the tab "API mappings" and map your API gateway and its stage.

Now, in your DNS manager, make sure you have a CNAME dns record for this endpoint. In my case:

[~]$ dig petapi.dcaballero.net CNAME  +short
d-tzbua5tzr1.execute-api.us-east-1.amazonaws.com.

After the dns is resolving properly the endpoint of the custom domain, you will be able to call the API like this:

[~]$ curl -v https://petapi.dcaballero.net/pets
*   Trying 23.21.127.126:443...
* Connected to petapi.dcaballero.net (23.21.127.126) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
*  CAfile: /etc/pki/tls/certs/ca-bundle.crt
*  CApath: none
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS header, Finished (20):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS header, Finished (20):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=dcaballero.net
*  start date: Feb 16 00:00:00 2023 GMT
*  expire date: Mar 16 23:59:59 2024 GMT
*  subjectAltName: host "petapi.dcaballero.net" matched cert's "*.dcaballero.net"
*  issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M01
*  SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* h2h3 [:method: GET]
* h2h3 [:path: /pets]
* h2h3 [:scheme: https]
* h2h3 [:authority: petapi.dcaballero.net]
* h2h3 [user-agent: curl/7.85.0]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x561b1abb2b00)
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
> GET /pets HTTP/2
> Host: petapi.dcaballero.net
> user-agent: curl/7.85.0
> accept: */*
> 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
< HTTP/2 200 
< date: Thu, 16 Feb 2023 15:36:59 GMT
< content-type: application/json
< content-length: 184
< x-amzn-requestid: 905fc8fc-f37e-4df8-b11b-d14681cca5a0
< access-control-allow-origin: *
< x-amz-apigw-id: AcEQSF6NoAMFqxQ=
< x-amzn-trace-id: Root=1-63ee4d9b-393461651075686265d1716e
< 
[
  {
    "id": 1,
    "type": "dog",
    "price": 249.99
  },
  {
    "id": 2,
    "type": "cat",
    "price": 124.99
  },
  {
    "id": 3,
    "type": "fish",
    "price": 0.99
  }
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Connection #0 to host petapi.dcaballero.net left intact

Hope this is better for your use case.

profile picture
answered a year ago
0

Hi @Joshua,

You can create a private hosted zone in r53, with an internal domain and a record for the API Gateway.

For example,

Hosted Zone A (internal) - domain apex: internal.mydomain.com

The VPC will resolve the records on that hosted zone first, make sure there is a record for your API gateway:

CNAME - api.internal.mydomain.com -> https://{rest-api-id}-{vpce-id}.execute-api.{region}.amazonaws.com/{stage}

Now, VPC Endpoint must exist anyways.

In your deployment or re-build process you can update that record everytime you deploy and the services if running inside the same VPC will resolve the API gateway using api.internal.mydomain.com regardless its CNAME value at the hosted zone.

Hope that helps!

profile picture
answered a year ago
  • Hi @DavidCabllero, thanks for the reply.

    As I stated in the question I already implemented that and it doesn't work for my use case because it becomes necessary to pass in a Host header like "{rest-api-id}.execute-api.{region}.amazonaws.com" when calling the url of the CNAME/Alias record from the public/private hosted zone.

    I need the endpoint set up such that it doesn't require special headers to call, as I already stated. Does this make sense?

0

Hi @Joshua,

in your case, like I said before you can use one single CNAME record, the record can be updated everytime you deploy its new API gateway so it will always point to whatever is the API Gateway endpoint. Now, that doesn't need any special Host header or similar, and you can also use API Gateway custom domains to avoid the usage of API Gateway endopoints.

How to custom domains: https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-custom-domains.html

Now, if your use case is a bit more complex, like a ReviewApps scenario where each deployment is generating a new API gateway per MR or PR, then you will need a different strategy in your record, either composing version or short sha over the custom domain record.

Hope that helps! cheers!

profile picture
answered a year ago
  • Hi David, this is sadly a non-answer as this is what I stated that I tried and it didn't work. I understand this solution, it's what I came up with, but it required passing the host header to work. Please see my linked Stack Overflow question for more details and read the whole question before responding, thanks for the help.

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions