Files
mailgoserver/internal/dnspublish/dnspublish.go
T

60 lines
2.6 KiB
Go
Raw Normal View History

2026-08-20 15:55:40 +01:00
// Package dnspublish publishes an arbitrary-name/arbitrary-value DNS TXT record via one
// of four provider APIs (Cloudflare, Route53, DigitalOcean, Google Cloud DNS) — used to
// automate what would otherwise be an admin manually pasting a DKIM TXT record into
// their DNS provider's own UI. Deliberately separate from internal/acmecert's DNS-01
// provider wiring: go-acme/lego's challenge.Provider interface is hardcoded to
// "_acme-challenge.<domain>" naming and an ACME-specific value (confirmed by reading
// lego's dns01.GetChallengeInfo and a concrete provider), so it can't be reused for a
// record with an arbitrary name and value like a DKIM record.
package dnspublish
import "fmt"
// Credentials selects a provider and holds every provider's own field set — fields
// unrelated to the selected Provider are simply ignored. Mirrors the flat-struct shape
// internal/config's [LetsEncrypt] section already uses for the same reason: these are
// admin-entered settings where only one provider is ever configured at a time.
type Credentials struct {
Provider string // "cloudflare", "route53", "digitalocean", "gcloud"
// ZoneName is the DNS zone/domain resource the provider hosts, e.g. "example.com"
// — used to resolve that provider's own zone/domain ID before publishing.
ZoneName string
CloudflareAPIToken string
Route53AccessKeyID string
Route53SecretAccessKey string
Route53Region string
DigitalOceanAPIToken string
GCloudProject string
// GCloudServiceAccountJSON is the service account key's raw JSON content (not a
// file path) — unlike [LetsEncrypt]'s global, file-path-based setting, this needs
// to work for per-domain, DB-stored credentials too.
GCloudServiceAccountJSON string
}
// txtTTL is a fixed, low TTL for every record this package writes — not configurable
// in this pass, so a rotation's new value propagates reasonably quickly regardless of
// what the zone's other records use.
const txtTTL = 300
// SetTXTRecord creates or updates (upserts) a TXT record at recordFQDN (e.g.
// "selector._domainkey.example.com") to value, in the zone named by creds.ZoneName, via
// whichever provider creds.Provider selects.
func SetTXTRecord(creds Credentials, recordFQDN, value string) error {
switch creds.Provider {
case "cloudflare":
return setTXTRecordCloudflare(creds, recordFQDN, value)
case "route53":
return setTXTRecordRoute53(creds, recordFQDN, value)
case "digitalocean":
return setTXTRecordDigitalOcean(creds, recordFQDN, value)
case "gcloud":
return setTXTRecordGCloud(creds, recordFQDN, value)
default:
return fmt.Errorf("dnspublish: unknown or unset DNS provider %q", creds.Provider)
}
}