Skip to content

feat(dns): add DNS auto-provisioning via RFC 2136 dynamic updates#24

Draft
fobispo-tc wants to merge 1 commit into
godaddy:mainfrom
fobispo-tc:feat/dns-auto-provisioning
Draft

feat(dns): add DNS auto-provisioning via RFC 2136 dynamic updates#24
fobispo-tc wants to merge 1 commit into
godaddy:mainfrom
fobispo-tc:feat/dns-auto-provisioning

Conversation

@fobispo-tc
Copy link
Copy Markdown
Contributor

Summary

  • Add port.DNSProvisioner interface for automatic DNS record creation/deletion
  • Implement RFC 2136 (DDNS) adapter with TSIG authentication using miekg/dns
  • Hook provisioning into VerifyDNS (auto-create before verify) and Revoke (best-effort cleanup)
  • Add dns.provisioner config section — independent of the dns.type verifier setting
  • Includes the _ans-badge URL fix from PR fix(domain): point _ans-badge DNS record URL at transparency log #23 (badge records now point to TL, not agent endpoint)

Motivation

In org-level deployments where the RA controls the DNS zone, requiring operators to manually add _ans, _ans-badge, and _443._tcp TLSA records between VerifyACME and VerifyDNS is unnecessary friction. This feature lets the RA provision them automatically via RFC 2136 dynamic DNS updates, collapsing the registration flow from 4 steps to 2.

Configuration

dns:
  type: lookup                      # verifier (unchanged)
  server: "8.8.8.8:53"
  provisioner:                      # NEW — optional
    type: ddns
    ddns:
      server: "ns1.example.com:53"  # authoritative nameserver
      zone: "example.com."          # zone to update
      tsig-name: "ans-updater."     # TSIG key name
      tsig-secret: "base64..."      # TSIG shared secret
      tsig-algorithm: "hmac-sha256" # default
      timeout: 5s                   # default

When dns.provisioner is absent or empty, behavior is unchanged (manual DNS).

Design Decisions

  1. Separate DNSProvisioner interface — not combined with DNSVerifier (ISP compliance, matches existing port pattern)
  2. Provisioning inside VerifyDNS — TLSA records need server cert fingerprint (only available after VerifyACME), so provisioning can't happen earlier
  3. Best-effort cleanup on Revoke — DNS deletion failure is logged but doesn't block revocation (TL event is authoritative)
  4. Independent config — verifier and provisioner are orthogonal (dns.type: lookup + dns.provisioner.type: ddns)

Files Changed

File Change
internal/port/dns.go Add DNSProvisioner interface
internal/adapter/dns/ddns.go New — RFC 2136 adapter with TSIG
internal/adapter/dns/ddns_test.go New — 10 tests against in-process UDP server
internal/adapter/dns/noop_provisioner.go New — no-op for dev/test
internal/config/config.go Add provisioner config structs + validation + PublicBaseURL
internal/domain/dnsrecords.go Accept tlPublicBaseURL param for badge URL fix
internal/domain/dnsrecords_test.go 2 new badge URL tests
internal/ra/service/registration.go Add dnsProvisioner field + builder
internal/ra/service/lifecycle.go Hook provisioning into VerifyDNS + Revoke cleanup
internal/ra/handler/*.go Thread TL public URL for badge fix
cmd/ans-ra/main.go Wire provisioner from config
config/ra-{local,docker}.yaml Document new config options

Test plan

  • All 23 packages pass (go test ./...)
  • 10 new DDNS adapter tests (TXT, TLSA, delete, idempotency, TSIG, error cases)
  • 2 new badge URL domain tests
  • Clean build (go build ./...)
  • Deploy with DDNS config against a real BIND/PowerDNS server
  • Register agent → verify records auto-created
  • Revoke agent → verify records auto-deleted

@fobispo-tc fobispo-tc force-pushed the feat/dns-auto-provisioning branch 3 times, most recently from 5255520 to 61e83a5 Compare May 27, 2026 15:59
  Add port.DNSProvisioner interface and DDNS adapter for automatic DNS
  record management (TXT, TLSA, SVCB) using RFC 2136 with TSIG auth.

  When configured, registration issues certs, provisions DNS, and
  activates in a single call. Revoke auto-deletes records. Domain
  suffix config auto-qualifies short hostnames. SVCB records provide
  agent connectivity parameters per the DNS-AID proposal (RFC 9460).

  Includes the _ans-badge URL fix: badge records point to the TL
  badge endpoint when tl-client.public-base-url is configured.

  Signed-off-by: Francisco Obispo <fobispo@tucows.com>

Signed-off-by: Francisco Obispo <fobispo@tucows.com>
@fobispo-tc fobispo-tc force-pushed the feat/dns-auto-provisioning branch from 61e83a5 to 807624e Compare May 27, 2026 23:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant