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:
|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.
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.