Thursday 13th February 2020
Certificate Authority Authorisation (CAA) is a security control that can be used to restrict the Certificate Authorities (CAs) that are permitted to issue certificates for your domain. The purpose of this is to help ensure that only explicitly whitelisted CAs are able to issue certificates, and also to report on any attempted violations of this policy.
CAA policies are set using the
CAA DNS resource record type, and it has been mandatory for issuing CAs to check for and comply with CAA policies since 8th September 2017. The CAA specification is defined in RFC8659.
The following sample CAA policy marks Let's Encrypt as the only CA authorised to issue certificates for
example.com, while requesting that violations are reported to the
example.com IN CAA 0 issue "letsencrypt.org" example.com IN CAA 0 iodef "mailto:firstname.lastname@example.org"
This policy will then be checked by CAs when a certificate request is submitted for your domain.
Skip to Section:
Restricting Who Can Issue Certificates for Your Domain with CAA ┣━━ Example CAA Policies ┣━━ DNS Record Format ┣━━ Querying CAA Records ┣━━ CAA Policy Violation Reports ┣━━ Other Considerations ┗━━ Conclusion
Below are examples of a wide variety of different CAA policy configurations, which should help you to get CAA set up in the way that you want.
Note that I have used
ca2.example.org to represent two different Certificate Authorities. In reality you'll need to use the CAA policy address of your preferred CA. This is usually just their domain name (e.g. for Let's Encrypt the policy address is
letsencrypt.org), however you should check their customer documentation to be sure.
example.com IN CAA 0 issue "ca1.example.net" example.com IN CAA 0 issue "ca2.example.org"
example.com IN CAA 0 issue "ca1.example.net" example.com IN CAA 0 issuewild "ca2.example.org"
example.com IN CAA 0 issue "ca1.example.net" example.com IN CAA 0 issue "ca2.example.org" example.com IN CAA 0 issuewild "ca2.example.org"
subdomain.example.comwhere only ca2 is allowed:
example.com IN CAA 0 issue "ca1.example.net" subdomain.example.com IN CAA 0 issue "ca2.example.org"
subdomain.example.comwhere they are allowed from ca1:
example.com IN CAA 0 issuewild ";" subdomain.example.com IN CAA 0 issuewild "ca1.example.net"
example.com IN CAA 0 issue "ca1.example.net" example.com IN CAA 0 issuewild ";"
example.com IN CAA 0 issue ";" example.com IN CAA 0 issuewild "ca1.example.net"
example.com IN CAA 0 issuewild ";"
example.com IN CAA 0 issue ";"
POSTto an API:
example.com IN CAA 0 iodef "mailto:email@example.com" example.com IN CAA 0 iodef "https://api.example.com/report/caa/"
The format of DNS CAA records consists of the following:
example.com IN CAA <flags> <property tag> <property value>
The property tag is used to specify which specific CAA policy setting a particular CAA record is referring to. Currently there are 3 different property tags defined in the specification:
issue: Used to specify a CA that is permitted to issue certificates for your domain. This applies to both normal and wildcard certificates, unless at least one
issuewildproperty tag is present, at which point it applies only to non-wildcard certificates.
issuewild: Used to specify a CA that is permitted to issue wildcard certificates for your domain. This applies only to wildcard certificates, meaning that you'll still need to add an
issueproperty if you wish to restrict the issuance of non-wildcard certificates as well.
iodef: Used to specify a HTTP endpoint or email address that policy violation reports should be sent to in Incident Object Description Exchange Format (IODEF / RFC7970).
The property value is the actual setting value that is associated with the property tag. In the case of
issuewild, the property value will be the name of a certificate authority, and possibly other metadata such as an account ID (though the latter is not widely supported/implemented). In the case of
iodef, the property value will be either an email address prefixed with
mailto:, or a HTTP endpoint starting with
Flags are designed to allow for extending the CAA specification in the future. They are defined using a single unsigned integer (0 to 255, or
11111111 when represented in binary). Currently there is only one supported flag, which is the Issuer Critical Flag (represented by bit 0). At the time of writing, the flag value is almost always
The Issuer Critical Flag is used to indicate to CAs that they must only issue certificates if all of the critical flagged property tags contained with the CAA policy for a domain are understood.
This is to allow the CAA specification to be extended in the future, without creating a loophole where CAs who don't yet conform to the new specification may still be able to issue certificates for a domain because they don't understand or know how to interpret the potentially more stringent CAA policy requirements.
As a silly example, suppose that the CAA specification was extended to allow for restricting the day of the week that certificates can be issued. E.g.:
example.com IN CAA 0 issue "letsencrypt.org" example.com IN CAA 0 dayofweek "Monday"
If we assume that Let's Encrypt haven't yet updated their CAA policy parsing implementation, the
dayofweek property cannot be parsed/understood. If someone requests a certificate on a Tuesday, Let's Encrypt will issue it, as even though they do not understand the
dayofweek property, the critical flag is
0 so the issuance goes ahead anyway. This issuance would be in violation of the CAA policy.
However, if the CAA policy were to be changed to have the Issuer Critical Flag set:
example.com IN CAA 0 issue "letsencrypt.org" example.com IN CAA 1 dayofweek "Monday"
...all certificate requests would now be denied until Let's Encrypt upgrade their CAA parser. This is compliant with the CAA policy.
Once Let's Encrypt update their CAA parser, certificate requests would then be permitted on Mondays.
CAA records can be easily checked using
$ dig +short example.com CAA 0 issue "letsencrypt.org" 0 issuewild ";" 0 iodef "mailto:firstname.lastname@example.org"
When using Let's Encrypt with Certbot, attempting to issue a certificate that is in violation of the CAA policy for a domain will result in an error similar to the following:
Failed authorization procedure. www.jamiescaife.uk (http-01): urn:ietf:params:acme:error:caa :: CAA record for www.jamiescaife.uk prevents issuance IMPORTANT NOTES: - The following errors were reported by the server: Domain: www.jamiescaife.uk Type: None Detail: CAA record for www.jamiescaife.uk prevents issuance
Each distinct certificate authority has their own CAA error format, however the general message is always the same.
If the targeted domain has a CAA violation reporting endpoint specified via an
iodef property, a violation report should also be sent (to be received by the owner of the affected domain).
CAA violation reports use the Incident Object Description Exchange Format (IODEF / RFC7970), which is a standardised mechanism for exchanging security report information.
Unfortunately, support for CAA violation reporting is currently very uncommon. Let's Encrypt don't support it at the time of writing, nor do most of the other large CAs. I was able to identify a smaller CA who claimed in their customer documentation that they send CAA violation reports, however despite deliberately triggering several CAA violations and waiting over 48 hours, I am yet to receive a report from them.
Keep in mind that CAA does not give blanket permission to whitelisted CAs to issue certificates. It just means that they are allowed to, as long as all other required validation methods are satisfied as well. For example, proving ownership of the domain name/website.
Also note that CAA does not necessarily prevent malicious or compromised CAs from issuing certificates for your domain, nor can it stop a person from socially engineering one of your whitelisted CAs or bypassing their technical validation requirements. These scenarios are not likely to be a concern unless you are a high-profile target, and any CA found to be involved or partaking in such activity would be in clear violation of the Baseline Requirements, and would most likely have their status as a publicly trusted CA removed.
I also recommend implementing Certificate Transparency (CT) monitoring, which will allow you to receive alerts whenever a certificate is issued for your domain. This is because modern browsers require all certificates to be recorded at the point of issuance in a series of public ledgers known as the Certificate Transparency logs, otherwise they will not be considered trusted. You can read more about this in my article Let's Encrypt SCTs in Certificates.
CAA is a valuable extra security control that you can implement for your domain names. Combined with CT log monitoring, it allows you to have control and oversight over the certificates that are issued for your domain.
Now that support for HTTP Public Key Pinning (HPKP) has been removed from most browsers, it is no-longer possible to implement strict certificate fingerprint checking for web-based TLS connections. HPKP was rightly removed due to the availability risks that it brought, however CAA + CT still allows you to achieve 95% of the protection.
If bad actors falsely acquiring certificates is really part of your threat model, then TLS with a trust store full of public CAs is most likely not the best option for you. You may wish to consider using something with native support for strict signature checking instead, such as SSH or GPG, and distributing trusted signatures/fingerprints using a secure out-of-band channel.