How We Use CNAME Abstractions at DevRev

In this post we cover a real-world example of using CNAME abstractions

How We Use CNAME Abstractions at DevRev

Here’s the full list of posts for this series:

Most companies will have a series of publically facing endpoints that clients (known or unknown) will need to connect to.

For example, we have the following:

  • devrev.ai (marketing website)
  • app.devrev.ai (main app endpoint)
  • api.devrev.ai (main api endpoint)
  • exp.devrev.ai (experience tier endpoint)
  • etc.

For our marketing website, we currently use Vercel for this. For our platform endpoints, we force everything to go to our edge logic on Fastly and disallow direct communication with our origin (only traffic from Fastly is allowed).

Here’s how we configured our DNS in this scenario:

  • devrev.ai --> Vercel endpoint IPs

NOTE: APEX records (e.g., root) must resolve to an IP address and cannot use CNAMEs

➜  global git:(sp/add_dns_admins_group) dig devrev.ai

; <<>> DiG 9.10.6 <<>> devrev.ai
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 63388
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;devrev.ai.			IN	A

;; ANSWER SECTION:
devrev.ai.		900	IN	A	99.99.99.99

For our platform endpoints, these all point to a CNAME abstraction:

  • app.devrev.ai --> edge.devrev.ai --> Fastly endpoint CNAME --> Fastly IP endpoint
➜  global git:(sp/update_website_apex_record) dig app.devrev.ai

; <<>> DiG 9.10.6 <<>> app.devrev.ai
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53713
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 8192
;; QUESTION SECTION:
;app.devrev.ai.			IN	A

;; ANSWER SECTION:
app.devrev.ai.		900	IN	CNAME	edge.devrev.ai.
edge.devrev.ai.		900	IN	CNAME	n.sni.global.fastly.net.
n.sni.global.fastly.net. 24	IN	A	151.101.189.91

;; Query time: 34 msec
;; SERVER: 172.20.0.1#53(172.20.0.1)
;; WHEN: Sun Mar 19 08:26:46 PDT 2023
;; MSG SIZE  rcvd: 114
  • api.devrev.ai --> edge.devrev.ai --> Fastly endpoint CNAME --> Fastly IP endpoint
➜  global git:(sp/update_website_apex_record) dig api.devrev.ai

; <<>> DiG 9.10.6 <<>> api.devrev.ai
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53713
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 8192
;; QUESTION SECTION:
;api.devrev.ai.			IN	A

;; ANSWER SECTION:
api.devrev.ai.		900	IN	CNAME	edge.devrev.ai.
edge.devrev.ai.		900	IN	CNAME	n.sni.global.fastly.net.
n.sni.global.fastly.net. 24	IN	A	151.101.189.91

;; Query time: 34 msec
;; SERVER: 172.20.0.1#53(172.20.0.1)
;; WHEN: Sun Mar 19 08:26:46 PDT 2023
;; MSG SIZE  rcvd: 114

We don’t (can’t) use CNAME abstraction for the website (devrev.ai) as we cannot use CNAMEs for APEX records and APEX records must resolve to IPs.

However, [app,api,exp,*].devrev.ai all point edge.devrev.ai which points to the Fastly CNAME which is then resolved to the IP of the closest Fastly POP via ANYCAST.

How has this helped us?

Depending on the TLS options the Fastly CNAME will change (e.g., TLS v1.3 vs, 1.3+QUIC, vs. TLS v1.3 + 0RTT, etc.). As we have become more comfortable (and as more have become available), we have evolved this from vanilla TLS v1.3 to more current options.

By having the edge.devrev.ai record, I only had to change this in a single location to update everything pointing to it (e.g., [app,api,exp,*])

Even with automation (we control everything via Terraform), this is valuable as this minimizes the risk by changing the number of updates from n --> 1. Sure, you can do a find and replace, but remember, almost all major cloud outages were caused by having a script modify DNS records. Is it worth the risk?

essential