AWS Certificate Manager DNS Validation With Namecheap
Jan 18, 2024
4 minute read

The Problem

As of writing this, DNS validation with Namecheap using the web interface is tricky.
At least that was my experience. The page just freeze as soon as I input by typing or pasting the CNAME value.
Testing it with other browsers, the issue still persists.
So it must be on the frontend’s input validation.
As soon as I enter “.” in the CNAME value, the page freezes.

Inspecting further, the input field has a regex pattern of ^(\@|\*|((\*\.)?((?=[a-zA-Z0-9_-]*[a-zA-Z0-9][a-zA-Z0-9_-]*\.?)(?![a-zA-Z0-9_-]{64,}\.?)[a-zA-Z0-9_]([a-zA-Z0-9_-]*[a-zA-Z0-9_])*)(\.((?=[a-zA-Z0-9_-]*[a-zA-Z0-9][a-zA-Z0-9_-]*\.?)(?![a-zA-Z0-9_-]{64,}\.?)[a-zA-Z0-9_]([a-zA-Z0-9_-]*[a-zA-Z0-9_])*))*))$

regex pattern
Input validation regex pattern

The CNAME name (host) that AWS Certificate Manager provides is in the format of _random-string.example.com.. For example, _rg4nt4j4p6gixniqe43dth5gmgg550pf.example.com. (not a real value).

The default CNAME Record for www provided by Namecheap has a value of parkingpage.namecheap.com. whose pattern is not that different from the CNAME value provided by AWS Certificate Manager. So what’s the issue?

The input may be valid but the regex pattern itself could be very complex that processing it takes a long time and the page crashes.

As we can see from Regex testing websites, the regex pattern is very complex.

Pattern tested on regexr
regexr test

Test here: https://regexr.com/7qka9

Pattern tested on regex101
regex101 test

Test here: https://regex101.com/r/nsSttp/1

regex101 debugger
regex101 debugger

If you are experiencing the same issue, here is a workaround.

Namecheap API

This is a bit involved and requires some knowledge of the Namecheap API. Admittedly, this is the only solution I got. I have contacted Namecheap and promised to look into it.

However, there is a catch. The API responses are a bit elusive and does not provide a clear message if the request is successful or not. I will explain this further below.

These are the things we need for the API:

  1. API Key
  2. Whitelisted IP Address

Please head on to https://www.namecheap.com/support/api/intro/ for specific instructions on how to setup these requirements.

The API endpoints we will be using are:

  1. domains.dns.getHosts
  2. domains.dns.setHosts

domains.dns.getHosts

According to the documentation, this endpoint “retrieves DNS host record settings for the requested domain.”

Reference: https://www.namecheap.com/support/api/methods/domains-dns/get-hosts/

Example GET request:

curl --location 'https://api.namecheap.com/xml.response?ApiUser=<APIUSER>&ApiKey=<APIKEY>&Command=namecheap.domains.dns.getHosts&UserName=<USERNAME>&ClientIp=<CLIENTIP>&SLD=example&TLD=com'

Replace the variables with your own values: APIUSER, APIKEY, USERNAME, CLIENTIP.

SLD and TLD is based on the domain that you own. For example, if you own example.com, then SLD is example and TLD is com.

A successful response message would look something like this:

<?xml version="1.0" encoding="utf-8"?>
<ApiResponse Status="OK" xmlns="http://api.namecheap.com/xml.response">
    <Errors />
    <Warnings />
    <RequestedCommand>namecheap.domains.dns.gethosts</RequestedCommand>
    <CommandResponse Type="namecheap.domains.dns.getHosts">
        <DomainDNSGetHostsResult Domain="example.com" EmailType="FWD" IsUsingOurDNS="true">
            <host HostId="00000000" Name="www" Type="CNAME" Address="parkingpage.namecheap.com." MXPref="10" TTL="1800" AssociatedAppTitle="" FriendlyName="CNAME Record" IsActive="true" IsDDNSEnabled="false" />
            <host HostId="00000000" Name="@" Type="URL" Address="http://www.example.com/" MXPref="10" TTL="1800" AssociatedAppTitle="URL Forwarding" FriendlyName="URL Record" IsActive="true" IsDDNSEnabled="false" />
        </DomainDNSGetHostsResult>
    </CommandResponse>
    <Server>PHX01APIEXT01</Server>
    <GMTTimeDifference>--5:00</GMTTimeDifference>
    <ExecutionTime>0.098</ExecutionTime>
</ApiResponse>

Here you can see the default DNS records from a freshly registered domain. It may look different from yours. You can verify this by going to your Namecheap account and checking the DNS records for your domain.

domains.dns.setHosts

The documentation says, “Sets DNS host records settings for the requested domain.”

Reference: https://www.namecheap.com/support/api/methods/domains-dns/set-hosts/

⚠️ CAUTION: This will overwrite all existing DNS records. So make sure you have a backup of your DNS records. To create a successful POST request, you need to include all the existing DNS records on top of the extra DNS records you want to add.

Again, I encourage you to read the documentation for this endpoint. It is very important to understand how this works.

Example POST request:

curl --location 'https://api.namecheap.com/xml.response?ApiUser=<APIUSER>&ApiKey=<APIKEY>&Command=namecheap.domains.dns.setHosts&&UserName=<USERNAME>&ClientIp=<CLIENTIP>&SLD=example&TLD=com' \
--header 'Content-Type: application/json' \
--data '{
    "RequestValues":[
      {
        "Key":"RecordType1",
        "Value":"CNAME"
      },
      {
        "Key":"HostName1",
        "Value":"_rg4nt4j4p6gixniqe43dth5gmgg550pf.example.com."
      },
      {
        "Key": "Address1",
        "Value": "_yg5wehjm4eznkfb0v2ozu4z6rxqschu2.mhbtsbpdnt.acm-validations.aws."
      }
    ],
    "SLD": "example",
    "TLD": "com"
}'

Example response:

<?xml version="1.0" encoding="utf-8"?>
<ApiResponse Status="OK" xmlns="http://api.namecheap.com/xml.response">
    <Errors />
    <Warnings />
    <RequestedCommand>namecheap.domains.dns.sethosts</RequestedCommand>
    <CommandResponse Type="namecheap.domains.dns.setHosts">
        <DomainDNSSetHostsResult Domain="example.com" IsSuccess="true">
            <Warnings />
        </DomainDNSSetHostsResult>
    </CommandResponse>
    <Server>PHX01APIEXT01</Server>
    <GMTTimeDifference>--5:00</GMTTimeDifference>
    <ExecutionTime>0.478</ExecutionTime>
</ApiResponse>

As mentioned, this method does not provide a clear message if the request is successful or not.

If you want to verify that the CNAME records are indeed set, you can use the domains.dns.getHosts endpoint again. But then you may see that it only reports empty records.

How I verified that the CNAME records are indeed set by doing two things:

  1. Checking the AWS Certificate Manager DNS validation status.

At this point, the DNS validation status should be “Success”. Or wait for a bit of time for the records to propagate. If still nothing, then the CNAME records are not set correctly.

  1. Checking the CNAME records using the dig command.
dig example.com. CNAME

Output of the command dig

Conclusion

I intend to perform DNS validation of the AWS Certificate Manager issued certificate with Namecheap using their API instead of the web interface. I contacted Namecheap support and they promised to look into it. This workaround serves me well as of now.

You may find this approach useful. If you have a better solution, please let me know. Also, Namecheap customer support is always available. Thanks!


🐋 hello there! If you enjoy this, a "Thank you" is enough.

Or you can also ...

Buy me a teaBuy me a tea

comments powered by Disqus