On Thursday we enabled an implementation of the legacy form of the CAA (RFC6844) spec. Previously, Let’s Encrypt implemented an amended and simplified form of RFC6844 as described in erratum 5065. We’ve been working on getting the erratum officially adopted at the CA/Browser Forum, and there is general consensus at both IETF and the CA/Browser Forum that the amended version is ideal. Unfortunately, the details haven’t yet been formally voted in, so we have implemented the older version temporarily while we wait for the vote to go through.
The difference is the handling of CNAMEs. Under erratum 5065, to check CAA for www.example.com
, the CA looks up CAA for www.example.com
, then example.com
, then com
(this is called tree-climbing). If any CNAMEs are encountered along the way, the CA’s recursive resolver automatically resolves them according to RFC1034, and the CA gets the CAA record at the end of the CNAME chain, if there is one.
Under legacy CAA, the CA is required to additionally climb the DNS tree on each CNAME record it receives along the way, and check CAA for each of those. For instance, if www.example.com
is a CNAME to hosting.customer.example.net
, the CAA must additionally check CAA for customer.example.net
, example.net
, and net
. This may introduce new hostnames into your CAA path that were not there before. If any of those hostnames fails CAA lookup, issuance will be blocked.
There’s another issue with legacy CAA: Mixed CNAME/tree-climbing loops. Normally loops in CNAME records are handled automatically by recursive resolvers, and result in lookup failures. As a result, CNAME loops in the wild are rare. However, the tree-climbing behavior introduces a new potential loop. Say, for example, blog.example.com
is a CNAME to www.blog.example.com
. According to a strict interpretation of RFC6844, the CA is required to check CAA for blog.example.com
, then www.blog.example.com
, then blog.example.com
, then blog.example.com
, and so on forever. We’ve addressed this in our code by setting a limit on how deep we will chase such CNAMEs. In the interest of security and correctness, we fail closed in such a scenario and prevent issuance. RFC6844 does not specify how to handle such loops; under erratum 5065 there is no possibility for loops. Unfortunately, such mixed CNAME/tree-climbing loops are a very common and legitimate DNS setup in the wild, so this blocks issuance for some domains.
We’ve already gotten several reports from users that this is causing breakage:
- Consistent 500's for new-cert (failing CAA for one domain)
- Too many CNAMEs when looking up CAA
- https://github.com/letsencrypt/boulder/issues/3093
We understand this is causing issuance problems for many people, and we’re going to be continuing to push hard to find a solution soon that allows continued issuance and renewal for affected domains.
One workaround that may work for if your DNS provider fully supports setting CAA records: As described in our CAA documentation, CAA processing terminates early if any CAA record is found. Setting a CAA record for your domain that explicitly allows issuance by Let’s Encrypt can help avoid these problems. This is of course not an ideal solution: not all DNS software supports setting CAA records, and not everyone has direct control of their DNS.