Skip to content

Commit 692292f

Browse files
bilhackmacmjuraga
authored andcommitted
BUG/MEDIUM: acme: append dns-01 records instead of replacing them
A certificate covering both `example.com` and `*.example.com` gets two dns-01 authorizations, each with its own token, but both use the same record name: `_acme-challenge.example.com`. `Present()` uses `SetRecords()`, which by libdns semantics replaces every record with the same name and type. When the second challenge is deployed, it deletes the TXT record of the first one, and one of the two validations fails. Use `AppendRecords()` when the provider implements `libdns.RecordAppender`, and keep `SetRecords()` as a fallback. Cleanup is unchanged: `DeleteRecords()` matches on name, type and value, so each challenge only removes its own record.
1 parent dd65e7e commit 692292f

1 file changed

Lines changed: 10 additions & 1 deletion

File tree

‎acme/dns01.go‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,16 @@ func (s *DNS01Solver) Present(ctx context.Context, domain, zone, keyAuth string)
8585
// libdns expects record names relative to the zone.
8686
rec.Name = libdns.RelativeName(rec.Name, zone)
8787

88-
results, err := s.provider.SetRecords(ctx, zone, []libdns.Record{rec})
88+
// Append rather than Set: SetRecords replaces every record with the same
89+
// name and type, which breaks certificates covering both a domain and its
90+
// wildcard, since both challenges share the same _acme-challenge name.
91+
var results []libdns.Record
92+
var err error
93+
if appender, ok := s.provider.(libdns.RecordAppender); ok {
94+
results, err = appender.AppendRecords(ctx, zone, []libdns.Record{rec})
95+
} else {
96+
results, err = s.provider.SetRecords(ctx, zone, []libdns.Record{rec})
97+
}
8998
if err != nil {
9099
return fmt.Errorf("adding temporary record for zone %q: %w", zone, err)
91100
}

0 commit comments

Comments
 (0)