Skip to content

Commit

Permalink
issuer: acme: clouddns: Only clean up own records
Browse files Browse the repository at this point in the history
If running multiple certmanagers they can race against each other

Signed-off-by: Hans Arnholm <hans@arnholm.dk>
  • Loading branch information
cypres committed Jun 1, 2023
1 parent 2fb9e61 commit 501581a
Showing 1 changed file with 39 additions and 7 deletions.
46 changes: 39 additions & 7 deletions pkg/issuer/acme/dns/clouddns/clouddns.go
Expand Up @@ -14,6 +14,7 @@ import (
"context"
"fmt"
"os"
"strings"
"time"

logf "github.com/cert-manager/cert-manager/pkg/logs"
Expand Down Expand Up @@ -155,19 +156,31 @@ func (c *DNSProvider) Present(domain, fqdn, value string) error {
Ttl: int64(60),
Type: "TXT",
}
change := &dns.Change{
Additions: []*dns.ResourceRecordSet{rec},
}
change := &dns.Change{}

// Look for existing records.
list, err := c.client.ResourceRecordSets.List(c.project, zone).Name(fqdn).Type("TXT").Do()
if err != nil {
return err
}
if len(list.Rrsets) > 0 {
// Attempt to delete the existing records when adding our new one.
// Merge the existing RR Data into the new one, requires a delete and an add operation, or it will fail.
// The operations are applied atomically to the zone, so there is no point in time where the entire TXT record is deleted.
// Reference; https://cloud.google.com/dns/docs/reference/v1/changes
change.Deletions = list.Rrsets
for _, r := range list.Rrsets {
if r.Type == "TXT" && r.Name == fqdn {
// Check if record is already present
for _, s := range r.Rrdatas {
if strings.Trim(s, "\"") == value {
return nil
}
}
rec.Rrdatas = append(rec.Rrdatas, r.Rrdatas...)
}
}
}
change.Additions = []*dns.ResourceRecordSet{rec}

chg, err := c.client.Changes.Create(c.project, zone, change).Do()
if err != nil {
Expand All @@ -194,7 +207,7 @@ func (c *DNSProvider) CleanUp(domain, fqdn, value string) error {
return err
}

records, err := c.findTxtRecords(zone, fqdn)
records, err := c.findTxtRecords(zone, fqdn, value)
if err != nil {
return err
}
Expand All @@ -203,6 +216,19 @@ func (c *DNSProvider) CleanUp(domain, fqdn, value string) error {
change := &dns.Change{
Deletions: []*dns.ResourceRecordSet{rec},
}
// If more than our rrdata, then filter it out but keep the rest
// Like in the Present() call, to keep the other rrdata we must delete, and re-add it, in one atomic operation.
if len(rec.Rrdatas) > 1 {
filtered := new(dns.ResourceRecordSet)
*filtered = *rec // shallow copy
filtered.Rrdatas = make([]string, 0, len(rec.Rrdatas))
for _, r := range rec.Rrdatas {
if strings.Trim(r, "\"") != value {
filtered.Rrdatas = append(filtered.Rrdatas, r)
}
}
change.Additions = []*dns.ResourceRecordSet{filtered}
}
_, err = c.client.Changes.Create(c.project, zone, change).Do()
if err != nil {
return err
Expand Down Expand Up @@ -246,16 +272,22 @@ func (c *DNSProvider) getHostedZone(domain string) (string, error) {
return zones.ManagedZones[0].Name, nil
}

func (c *DNSProvider) findTxtRecords(zone, fqdn string) ([]*dns.ResourceRecordSet, error) {
func (c *DNSProvider) findTxtRecords(zone, fqdn, value string) ([]*dns.ResourceRecordSet, error) {
recs, err := c.client.ResourceRecordSets.List(c.project, zone).Do()
if err != nil {
return nil, err
}

found := []*dns.ResourceRecordSet{}
RecLoop:
for _, r := range recs.Rrsets {
if r.Type == "TXT" && r.Name == fqdn {
found = append(found, r)
for _, s := range r.Rrdatas {
if strings.Trim(s, "\"") == value {
found = append(found, r)
continue RecLoop
}
}
}
}

Expand Down

0 comments on commit 501581a

Please sign in to comment.