Overview

CAA records are a mechanism to whitelist certificate authorities that have permission to issue certificates for your domain. This is done via a CAA DNS record. The benefits to this are that insecure certificate authorities, and malicious threat actors will find it more challenging to obtain certificates for your domain, which is an excellent thing.

An example of a CA trying to issue a certificate, in this case, LetsEncrypt, for which it isn't allowed can be seen below.

Failed authorization procedure. pihole.musingitoutloud.com (http-01):
urn:acme:error:caa :: CAA record for pihole.musingitoutloud.com prevents
issuance

IMPORTANT NOTES:
 - The following errors were reported by the server:

   Domain: pihole.musingitoutloud.com
   Type:   None
   Detail: CAA record for pihole.musingitoutloud.com prevents
   issuance

Note: technically this is incorrect, as I don't have CAA enabled for musingitoutloud.com, however, the output is accurate, it's just a domain name substitution to maintain some privacy for the actual domain in question.

Once the CAA record was successfully added, the certificate was issued by LetsEncrypt. That's exactly how it should work.

CAA Record Format

CAA records consist of the following values:

Name Contents Description
Flag 0-255 Only 0 (non-critical) and 1 (critical) are currently used.
Tag "string" A string consisting of one of the following:
issue Allows the CA to issue normal domain certificates
issuewild Allows the CA to issue wildcard certificates
iodef The URL where a CA can report issues or violations. Typically this is an email address, in the "mailto:[email protected]" format.
Value "string" A string defining the contents of the Tag as mentioned above

As an example, I use LetsEncrypt for musingitoutloud.com (on the backend). The CAA records would look like this:

#                          Flag   Tag       Value
musingitoutloud.com. CAA   0      issue     "letsencrypt.org"
musingitoutloud.com. CAA   0      issuewild ";"
musingitoutloud.com. CAA   0      iodef     "mailto:[email protected]"

Note: Including the issuewild record effectively means don't allow LetsEncrypt to issue a wild card for this domain. If you want to enable issuing a wildcard certificate, omit that record.

Sub-domains

CAA records can set policy for the entire domain, or for specific hostnames. In the above example, the entire musingitoutloud.com domain can only have certificates issued by LetsEncrypt, and this is inherited by sub-domains. If I want to allow a sub-domain to be secured by a different CA, I need a more specific CAA record:

vpn.musingitoutloud.com.    CAA    0 issue "digicert.com"
vpn.musingitoutloud.com.    CAA    0 issuewild ";"
vpn.musingitoutloud.com.    CAA    0 iodef "mailto:[email protected]"

Useful overview: https://sslmate.com/caa/about

Legacy Zone Files

If you run a legacy DNS server that that doesn't understand CAA records, such as BIND < 9.9.6, NSD < 4.0.1 or Windows Server 2016, the syntax for the CAA will look like this:

musingitoutloud.com.    IN    TYPE257    \# 22 000569737375656C657473656E63727970742E6F7267
musingitoutloud.com.    IN    TYPE257    \# 12 0009697373756577696C643B
musingitoutloud.com.    IN    TYPE257    \# 39 0005696F6465666D61696C746F3A61646D696E406D7573696E6769746F75746C6F75642E636F6D

I don't know how a generic record is turned into that, but I believe this RFC would go some way to explaining it. With that said, the easiest way to create records is with SSL Mate's Record creator. It will create CAA records in all of the different formats, and that is what I've used for every production CAA record I've implemented.