Repository navigation
fix(cloudflare): send CAA records as structured data - #6962
maheshrijal wants to merge 1 commit into
Conversation
|
Welcome @maheshrijal! |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Hi @maheshrijal. Thanks for your PR. I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with Regular contributors should join the org to skip this step. Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
Cloudflare rejects a CAA record sent as content with "flags is a required data field". Send data.flags, data.tag, and data.value on individual create and update, and on batch post and put, as SRV, NAPTR, and TLSA already do. Add CAA to KnownRecordTypes and to the recordType enum. Since v0.23.1 the CRD rejects recordType: CAA at admission, so the provider fix alone does not reach users. make crd updates config/crd/standard only. The chart CRDs follow with the chart release, so the schema test lets only the types in chartPendingRecordTypes be missing from them. Build the read-back target from Cloudflare's structured data and canonicalize desired targets in AdjustEndpoints, so a second sync plans no changes. Parse targets with endpoint.NewCAARecord instead of miekg/dns. On an unquoted value, miekg/dns treats ';' as a comment and drops CAA parameters such as validationmethods=dns-01. It also keeps DNS escapes and caps the value at 255 octets, which RFC 8659 does not. Also map caa- ownership TXT names, keep trailing dots in CAA values, and turn off proxying for CAA. Signed-off-by: maheshrijal <62394512+maheshrijal@users.noreply.github.com>
9af2a95 to
8aa986a
Compare
What does it do ?
Cloudflare rejects a CAA record sent as
contentwithflags is a required data field. The provider now sendsdata.flags,data.tag, anddata.valueon all four write paths: individual create, individual update, batch post, and batch put. SRV, NAPTR, and TLSA already work this way.The PR also:
CAAtoKnownRecordTypesand to therecordTypeenum, then runsmake crd. Since feat(crd): validate DNSEndpoint schema at admission #6620, the CRD rejectsrecordType: CAAat admission, so a provider fix alone does not help users on v0.23.1 or later.AdjustEndpoints. A second sync plans no changes.endpoint.NewCAARecordto parse<flags> <tag> "<value>".caa-ownership TXT names to the mapper, keeps trailing dots in CAA values, and turns off proxying for CAA.NewCAARecorddoes not usemiekg/dns, unlike NAPTR. On an unquoted value,miekg/dnstreats;as a comment, so0 issue letsencrypt.org; validationmethods=dns-01loses its parameters. It also keeps DNS escapes in the value, and it caps the value at 255 octets, which RFC 8659 does not. CAA has one free-text field at the end, so a small parser is enough. It rejects values that contain"or\.Endpoint.Validateruns this parser for every provider, so a CAA target with"or\is skipped with a warning everywhere, not only on Cloudflare.make crdupdates onlyconfig/crd/standard. The chart CRDs follow with the chart release, asdocs/contributing/dev-guide.mddescribes.endpoint/crd_schema_test.gotherefore lets only the types inchartPendingRecordTypes(here,CAA) be missing from the chart CRDs, and themake crd-chartPR empties that list. Until that chart release, a Helm install still rejectsrecordType: CAA. If you prefer to update the chart CRDs in this PR instead, I can change it.Motivation
Fixes #6961.
Real-zone test
I ran
--source=crd --registry=txt --policy=sync --onceagainst a new Cloudflare zone, with--zone-id-filterset to that zone.Unsupported value: "CAA".All records are already up to date.128 issuewild ";", an unquotediodef,validationmethods=dns-01), and deletion all apply, and each next sync plans no changes.0 ISSUE "letsencrypt.org"does not cause repeated updates.At a zone apex, the ownership TXT needs
--txt-prefix=<prefix>-%{record_type}., asdocs/registry/txt.mddescribes for every apex record. Without it, the TXT name falls outside the zone (#6955).Commands and logs
The test zone was a throwaway zone, deleted after the run. The zone ID is redacted.
Current CRD on
master:v0.23.0 build and CRD, same flags as below:
level=error msg="fallback: individual CREATE failed: POST \"https://api.cloudflare.com/client/v4/zones/<zone-id>/dns_records\": 400 Bad Request {\"result\":null,\"success\":false,\"errors\":[{\"code\":9101,\"message\":\"flags is a required data field.\"},{\"code\":9101,\"message\":\"tag is a required data field.\"},{\"code\":9101,\"message\":\"value is a required data field.\"}],\"messages\":[]}" action=CREATE content="0 issue \"letsencrypt.org; validationmethods=dns-01\"" record=extdns-caa-test-0e8ed292.com type=CAA zone=<zone-id>This branch:
Records as Cloudflare stores them after the target change:
{"content":"0 issue \"letsencrypt.org\"","data":{"flags":0,"tag":"issue","value":"letsencrypt.org"}} {"content":"128 issuewild \";\"","data":{"flags":128,"tag":"issuewild","value":";"}} {"content":"0 iodef \"mailto:security@extdns-caa-test-0e8ed292.com\"","data":{"flags":0,"tag":"iodef","value":"mailto:security@extdns-caa-test-0e8ed292.com"}}Checks:
go test ./...passes.golangci-lint runreports 0 issues on the touched packages.make crdis a no-op.More
AI disclosure: this PR was written with the assistance of generative AI (Claude Opus 5.5 in Claude Code), with GPT-6.1 Sol used for code review. I reviewed the changes and ran the test above against a throwaway Cloudflare zone in my account.