From 9b239f41a3d33d2b7d68384981489d14a6d5b452 Mon Sep 17 00:00:00 2001 From: Phil Pennock Date: Sat, 22 Feb 2020 07:09:31 -0500 Subject: [PATCH] Add AUTODNSSEC, implement for DNSimple (#640) * Add AUTODNSSEC, implement for DNSimple There are two models for DNSSEC in DNS management: either dnscontrol manages all the DNSSEC records and has to be invoked regularly for re-signing, or the provider manages DNSSEC automatically and dnscontrol is not involved beyond saying "yeah, do that". This implements the latter, as a model, and for one provider. Potentially we could tune/configure options for DNSSEC such as algorithm, but DNSimple don't expose that API so I haven't implemented it. This minimal model should be something which maps into other providers cleanly. * Fix missing CanAutoDNSSEC on provider * Validation fix for master broken This is broken in master and causing Travis in my branch to fail. The validation tool runs with `gofmt -s` to require "simplify", and so rejects an ignored second bound variable to range iteration. * Correct wire in the AUTODNSSEC validation step --- build/generate/featureMatrix.go | 2 + docs/_functions/domain/AUTODNSSEC.md | 19 +++ docs/_includes/matrix.html | 33 ++++- models/domain.go | 1 + models/record.go | 1 + pkg/js/helpers.js | 5 + pkg/js/parse_tests/025-autodnssec.js | 3 + pkg/js/parse_tests/025-autodnssec.json | 13 ++ pkg/js/static.go | 191 +++++++++++++------------ pkg/normalize/validate.go | 21 ++- providers/capabilities.go | 4 + providers/dnsimple/dnsimpleProvider.go | 100 +++++++++++++ providers/gcloud/gcloudProvider.go | 2 +- 13 files changed, 292 insertions(+), 103 deletions(-) create mode 100644 docs/_functions/domain/AUTODNSSEC.md create mode 100644 pkg/js/parse_tests/025-autodnssec.js create mode 100644 pkg/js/parse_tests/025-autodnssec.json diff --git a/build/generate/featureMatrix.go b/build/generate/featureMatrix.go index 920ff2dda..a34b597a9 100644 --- a/build/generate/featureMatrix.go +++ b/build/generate/featureMatrix.go @@ -30,6 +30,7 @@ func generateFeatureMatrix() error { {"DNS Provider", "Can manage and serve DNS zones"}, {"Registrar", "The provider has registrar capabilities to set nameservers for zones"}, {"ALIAS", "Provider supports some kind of ALIAS, ANAME or flattened CNAME record type"}, + {"AUTODNSSEC", "Provider can automatically manage DNSSEC"}, {"CAA", "Provider can manage CAA records"}, {"PTR", "Provider supports adding PTR records for reverse lookup zones"}, {"NAPTR", "Provider can manage NAPTR records"}, @@ -74,6 +75,7 @@ func generateFeatureMatrix() error { fm.SetSimple("DNS Provider", false, func() bool { return providers.DNSProviderTypes[p] != nil }) fm.SetSimple("Registrar", false, func() bool { return providers.RegistrarTypes[p] != nil }) setCap("ALIAS", providers.CanUseAlias) + setCap("AUTODNSSEC", providers.CanAutoDNSSEC) setCap("CAA", providers.CanUseCAA) setCap("NAPTR", providers.CanUseNAPTR) setCap("PTR", providers.CanUsePTR) diff --git a/docs/_functions/domain/AUTODNSSEC.md b/docs/_functions/domain/AUTODNSSEC.md new file mode 100644 index 000000000..152f8830e --- /dev/null +++ b/docs/_functions/domain/AUTODNSSEC.md @@ -0,0 +1,19 @@ +--- +name: AUTODNSSEC +--- + +AUTODNSSEC indicates that the DNS provider can automatically manage +DNSSEC for a domain and we should ask it to do so. + +At this time, AUTODNSSEC takes no parameters. +There is no ability to tune what the DNS provider sets, no algorithm choice. +We simply ask that they follow their defaults when enabling a no-fuss DNSSEC +data model. + +{% include startExample.html %} +{% highlight js %} +D("example.com", .... , + AUTODNSSEC, +); +{%endhighlight%} +{% include endExample.html %} diff --git a/docs/_includes/matrix.html b/docs/_includes/matrix.html index c49f33cbb..608ae46fd 100644 --- a/docs/_includes/matrix.html +++ b/docs/_includes/matrix.html @@ -309,6 +309,35 @@ + + AUTODNSSEC + + + + + + + + + + + + + + + + + + + + + + + + + + + CAA @@ -939,8 +968,8 @@ - - + + diff --git a/models/domain.go b/models/domain.go index d25a93706..d4e3244b4 100644 --- a/models/domain.go +++ b/models/domain.go @@ -17,6 +17,7 @@ type DomainConfig struct { Nameservers []*Nameserver `json:"nameservers,omitempty"` KeepUnknown bool `json:"keepunknown,omitempty"` IgnoredLabels []string `json:"ignored_labels,omitempty"` + AutoDNSSEC bool `json:"auto_dnssec,omitempty"` //DNSSEC bool `json:"dnssec,omitempty"` // These fields contain instantiated provider instances once everything is linked up. diff --git a/models/record.go b/models/record.go index 4b5c8c5f4..dbfd488a7 100644 --- a/models/record.go +++ b/models/record.go @@ -28,6 +28,7 @@ import ( // TXT // Pseudo-Types: // ALIAS +// AUTODNSSEC // CF_REDIRECT // CF_TEMP_REDIRECT // FRAME diff --git a/pkg/js/helpers.js b/pkg/js/helpers.js index 6ad8f6811..a5c6f1395 100644 --- a/pkg/js/helpers.js +++ b/pkg/js/helpers.js @@ -413,6 +413,11 @@ function NO_PURGE(d) { d.KeepUnknown = true; } +// AUTODNSSEC() +function AUTODNSSEC(d) { + d.auto_dnssec = true; +} + /** * @deprecated */ diff --git a/pkg/js/parse_tests/025-autodnssec.js b/pkg/js/parse_tests/025-autodnssec.js new file mode 100644 index 000000000..3b2cb5288 --- /dev/null +++ b/pkg/js/parse_tests/025-autodnssec.js @@ -0,0 +1,3 @@ +D("foo.com","none", + AUTODNSSEC +); diff --git a/pkg/js/parse_tests/025-autodnssec.json b/pkg/js/parse_tests/025-autodnssec.json new file mode 100644 index 000000000..dd8f5a2d6 --- /dev/null +++ b/pkg/js/parse_tests/025-autodnssec.json @@ -0,0 +1,13 @@ +{ + "registrars": [], + "dns_providers": [], + "domains": [ + { + "name": "foo.com", + "registrar": "none", + "dnsProviders": {}, + "records":[], + "auto_dnssec": true + } + ] +} diff --git a/pkg/js/static.go b/pkg/js/static.go index 0a545ec15..2e1fd9b39 100644 --- a/pkg/js/static.go +++ b/pkg/js/static.go @@ -212,103 +212,104 @@ var _escData = map[string]*_escFile{ "/helpers.js": { name: "helpers.js", local: "pkg/js/helpers.js", - size: 21786, + size: 21856, modtime: 0, compressed: ` -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 +AA== `, }, } diff --git a/pkg/normalize/validate.go b/pkg/normalize/validate.go index 977f9a391..b999c37fe 100644 --- a/pkg/normalize/validate.go +++ b/pkg/normalize/validate.go @@ -436,23 +436,34 @@ func checkProviderCapabilities(dc *models.DomainConfig) error { cap providers.Capability }{ {"ALIAS", providers.CanUseAlias}, - {"PTR", providers.CanUsePTR}, - {"SRV", providers.CanUseSRV}, + {"AUTODNSSEC", providers.CanAutoDNSSEC}, {"CAA", providers.CanUseCAA}, + {"PTR", providers.CanUsePTR}, + {"SSHFP", providers.CanUseSSHFP}, + {"SRV", providers.CanUseSRV}, {"TLSA", providers.CanUseTLSA}, } for _, ty := range types { hasAny := false - for _, r := range dc.Records { - if r.Type == ty.rType { + switch ty.rType { + case "AUTODNSSEC": + if dc.AutoDNSSEC { hasAny = true - break } + default: + for _, r := range dc.Records { + if r.Type == ty.rType { + hasAny = true + break + } + } + } if !hasAny { continue } for _, provider := range dc.DNSProviderInstances { + // fmt.Printf(" (checking if %q can %q for domain %q)\n", provider.ProviderType, ty.rType, dc.Name) if !providers.ProviderHasCapability(provider.ProviderType, ty.cap) { return fmt.Errorf("Domain %s uses %s records, but DNS provider type %s does not support them", dc.Name, ty.rType, provider.ProviderType) } diff --git a/providers/capabilities.go b/providers/capabilities.go index 14b325d5b..1bb52f628 100644 --- a/providers/capabilities.go +++ b/providers/capabilities.go @@ -34,6 +34,10 @@ const ( // CanUseTXTMulti indicates the provider can handle TXT records with multiple strings CanUseTXTMulti + // CanAutoDNSSEC indicates that the provider can automatically handle DNSSEC, + // so folks can ask for that. + CanAutoDNSSEC + // CantUseNOPURGE indicates NO_PURGE is broken for this provider. To make it // work would require complex emulation of an incremental update mechanism, // so it is easier to simply mark this feature as not working for this diff --git a/providers/dnsimple/dnsimpleProvider.go b/providers/dnsimple/dnsimpleProvider.go index 74cc8c6e2..bdec1d8ab 100644 --- a/providers/dnsimple/dnsimpleProvider.go +++ b/providers/dnsimple/dnsimpleProvider.go @@ -23,6 +23,7 @@ var features = providers.DocumentationNotes{ providers.CanUseSSHFP: providers.Can(), providers.CanUseSRV: providers.Can(), providers.CanUseTXTMulti: providers.Can(), + providers.CanAutoDNSSEC: providers.Can(), providers.CanUseTLSA: providers.Cannot(), providers.DocCreateDomains: providers.Cannot(), providers.DocDualHost: providers.Cannot("DNSimple does not allow sufficient control over the apex NS records"), @@ -85,6 +86,8 @@ func (client *DnsimpleApi) GetZoneRecords(domain string) (models.Records, error) } rec.SetLabel(r.Name, domain) switch rtype := r.Type; rtype { + case "DNSKEY", "CDNSKEY", "CDS": + continue case "ALIAS", "URL": rec.Type = r.Type rec.SetTarget(r.Content) @@ -119,6 +122,12 @@ func (c *DnsimpleApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.C return nil, err } + dnssecFixes, err := c.getDNSSECCorrections(dc) + if err != nil { + return nil, err + } + corrections = append(corrections, dnssecFixes...) + records, err := c.GetZoneRecords(dc.Name) if err != nil { return nil, err @@ -201,6 +210,34 @@ func (c *DnsimpleApi) GetRegistrarCorrections(dc *models.DomainConfig) ([]*model return corrections, nil } +// getDNSSECCorrections returns corrections that update a domain's DNSSEC state. +func (c *DnsimpleApi) getDNSSECCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { + enabled, err := c.getDnssec(dc.Name) + if err != nil { + return nil, err + } + + if enabled && !dc.AutoDNSSEC { + return []*models.Correction{ + { + Msg: "Disable DNSSEC", + F: func() error { _, err := c.disableDnssec(dc.Name); return err }, + }, + }, nil + } + + if !enabled && dc.AutoDNSSEC { + return []*models.Correction{ + { + Msg: "Enable DNSSEC", + F: func() error { _, err := c.enableDnssec(dc.Name); return err }, + }, + }, nil + } + + return []*models.Correction{}, nil +} + // DNSimple calls func (c *DnsimpleApi) getClient() *dnsimpleapi.Client { @@ -258,6 +295,69 @@ func (c *DnsimpleApi) getRecords(domainName string) ([]dnsimpleapi.ZoneRecord, e return recs, nil } +func (c *DnsimpleApi) getDnssec(domainName string) (bool, error) { + var ( + client *dnsimpleapi.Client + accountID string + err error + ) + client = c.getClient() + if accountID, err = c.getAccountID(); err != nil { + return false, err + } + + dnssecResponse, err := client.Domains.GetDnssec(accountID, domainName) + if err != nil { + return false, err + } + if dnssecResponse.Data == nil { + return false, nil + } + return dnssecResponse.Data.Enabled, nil +} + +func (c *DnsimpleApi) enableDnssec(domainName string) (bool, error) { + var ( + client *dnsimpleapi.Client + accountID string + err error + ) + client = c.getClient() + if accountID, err = c.getAccountID(); err != nil { + return false, err + } + + dnssecResponse, err := client.Domains.EnableDnssec(accountID, domainName) + if err != nil { + return false, err + } + if dnssecResponse.Data == nil { + return false, nil + } + return dnssecResponse.Data.Enabled, nil +} + +func (c *DnsimpleApi) disableDnssec(domainName string) (bool, error) { + var ( + client *dnsimpleapi.Client + accountID string + err error + ) + client = c.getClient() + if accountID, err = c.getAccountID(); err != nil { + return false, err + } + + dnssecResponse, err := client.Domains.DisableDnssec(accountID, domainName) + if err != nil { + return false, err + } + if dnssecResponse.Data == nil { + return false, nil + } + return dnssecResponse.Data.Enabled, nil +} + // Returns the name server names that should be used. If the domain is registered // then this method will return the delegation name servers. If this domain // is hosted only, then it will return the default DNSimple name servers. diff --git a/providers/gcloud/gcloudProvider.go b/providers/gcloud/gcloudProvider.go index 5520c4c60..769703b75 100644 --- a/providers/gcloud/gcloudProvider.go +++ b/providers/gcloud/gcloudProvider.go @@ -108,7 +108,7 @@ func (g *gcloud) loadZoneInfo() error { // ListZones returns the list of zones (domains) in this account. func (g *gcloud) ListZones() ([]string, error) { var zones []string - for i, _ := range g.zones { + for i := range g.zones { zones = append(zones, strings.TrimSuffix(i, ".")) } return zones, nil