diff --git a/deploy/charts/cert-manager/crds/challenges.yaml b/deploy/charts/cert-manager/crds/challenges.yaml index b2de89f0e..cf3c63e92 100644 --- a/deploy/charts/cert-manager/crds/challenges.yaml +++ b/deploy/charts/cert-manager/crds/challenges.yaml @@ -325,8 +325,8 @@ spec: - nameserver properties: nameserver: - description: 'The IP address of the DNS supporting RFC2136. - Required. Note: FQDN is not a valid value, only IP.' + description: The IP address or hostname of an authoritative + DNS server supporting RFC2136. Required. type: string tsigAlgorithm: description: 'The TSIG Algorithm configured in the DNS supporting diff --git a/deploy/charts/cert-manager/crds/clusterissuers.yaml b/deploy/charts/cert-manager/crds/clusterissuers.yaml index 95e613e83..710e4aa42 100644 --- a/deploy/charts/cert-manager/crds/clusterissuers.yaml +++ b/deploy/charts/cert-manager/crds/clusterissuers.yaml @@ -379,9 +379,8 @@ spec: - nameserver properties: nameserver: - description: 'The IP address of the DNS supporting - RFC2136. Required. Note: FQDN is not a valid value, - only IP.' + description: The IP address or hostname of an authoritative + DNS server supporting RFC2136. Required. type: string tsigAlgorithm: description: 'The TSIG Algorithm configured in the diff --git a/deploy/charts/cert-manager/crds/issuers.yaml b/deploy/charts/cert-manager/crds/issuers.yaml index 664a86fc2..ed3d818a3 100644 --- a/deploy/charts/cert-manager/crds/issuers.yaml +++ b/deploy/charts/cert-manager/crds/issuers.yaml @@ -379,9 +379,8 @@ spec: - nameserver properties: nameserver: - description: 'The IP address of the DNS supporting - RFC2136. Required. Note: FQDN is not a valid value, - only IP.' + description: The IP address or hostname of an authoritative + DNS server supporting RFC2136. Required. type: string tsigAlgorithm: description: 'The TSIG Algorithm configured in the diff --git a/deploy/manifests/00-crds.yaml b/deploy/manifests/00-crds.yaml index 3a015549f..3171f2b30 100644 --- a/deploy/manifests/00-crds.yaml +++ b/deploy/manifests/00-crds.yaml @@ -1080,8 +1080,8 @@ spec: - nameserver properties: nameserver: - description: 'The IP address of the DNS supporting RFC2136. - Required. Note: FQDN is not a valid value, only IP.' + description: The IP address or hostname of an authoritative + DNS server supporting RFC2136. Required. type: string tsigAlgorithm: description: 'The TSIG Algorithm configured in the DNS supporting @@ -2541,9 +2541,8 @@ spec: - nameserver properties: nameserver: - description: 'The IP address of the DNS supporting - RFC2136. Required. Note: FQDN is not a valid value, - only IP.' + description: The IP address or hostname of an authoritative + DNS server supporting RFC2136. Required. type: string tsigAlgorithm: description: 'The TSIG Algorithm configured in the @@ -4295,9 +4294,8 @@ spec: - nameserver properties: nameserver: - description: 'The IP address of the DNS supporting - RFC2136. Required. Note: FQDN is not a valid value, - only IP.' + description: The IP address or hostname of an authoritative + DNS server supporting RFC2136. Required. type: string tsigAlgorithm: description: 'The TSIG Algorithm configured in the diff --git a/pkg/apis/acme/v1alpha2/types_issuer.go b/pkg/apis/acme/v1alpha2/types_issuer.go index c8ac16788..6a6ed605e 100644 --- a/pkg/apis/acme/v1alpha2/types_issuer.go +++ b/pkg/apis/acme/v1alpha2/types_issuer.go @@ -355,8 +355,7 @@ type ACMEIssuerDNS01ProviderAcmeDNS struct { // ACMEIssuerDNS01ProviderRFC2136 is a structure containing the // configuration for RFC2136 DNS type ACMEIssuerDNS01ProviderRFC2136 struct { - // The IP address of the DNS supporting RFC2136. Required. - // Note: FQDN is not a valid value, only IP. + // The IP address or hostname of an authoritative DNS server supporting RFC2136. Required. Nameserver string `json:"nameserver"` // The name of the secret containing the TSIG value. diff --git a/pkg/apis/acme/v1alpha3/types_issuer.go b/pkg/apis/acme/v1alpha3/types_issuer.go index 44a808ffc..b21c4ae24 100644 --- a/pkg/apis/acme/v1alpha3/types_issuer.go +++ b/pkg/apis/acme/v1alpha3/types_issuer.go @@ -355,8 +355,7 @@ type ACMEIssuerDNS01ProviderAcmeDNS struct { // ACMEIssuerDNS01ProviderRFC2136 is a structure containing the // configuration for RFC2136 DNS type ACMEIssuerDNS01ProviderRFC2136 struct { - // The IP address of the DNS supporting RFC2136. Required. - // Note: FQDN is not a valid value, only IP. + // The IP address or hostname of an authoritative DNS server supporting RFC2136. Required. Nameserver string `json:"nameserver"` // The name of the secret containing the TSIG value. diff --git a/pkg/internal/apis/acme/types_issuer.go b/pkg/internal/apis/acme/types_issuer.go index 51e6f3692..020b4bec2 100644 --- a/pkg/internal/apis/acme/types_issuer.go +++ b/pkg/internal/apis/acme/types_issuer.go @@ -314,8 +314,7 @@ type ACMEIssuerDNS01ProviderAcmeDNS struct { // ACMEIssuerDNS01ProviderRFC2136 is a structure containing the // configuration for RFC2136 DNS type ACMEIssuerDNS01ProviderRFC2136 struct { - // The IP address of the DNS supporting RFC2136. Required. - // Note: FQDN is not a valid value, only IP. + // The IP address or hostname of an authoritative DNS server supporting RFC2136. Required. Nameserver string // The name of the secret containing the TSIG value. diff --git a/pkg/internal/apis/certmanager/validation/issuer.go b/pkg/internal/apis/certmanager/validation/issuer.go index 9a2477c99..b7091be0e 100644 --- a/pkg/internal/apis/certmanager/validation/issuer.go +++ b/pkg/internal/apis/certmanager/validation/issuer.go @@ -348,7 +348,7 @@ func ValidateACMEChallengeSolverDNS01(p *cmacme.ACMEChallengeSolverDNS01, fldPat el = append(el, field.Required(fldPath.Child("rfc2136", "nameserver"), "")) } else { if _, err := util.ValidNameserver(p.RFC2136.Nameserver); err != nil { - el = append(el, field.Invalid(fldPath.Child("rfc2136", "nameserver"), "", "Nameserver invalid. Check the documentation for details.")) + el = append(el, field.Invalid(fldPath.Child("rfc2136", "nameserver"), p.RFC2136.Nameserver, "nameserver must be an hostname or IP address in the form host[:port].")) } } if len(p.RFC2136.TSIGAlgorithm) > 0 { diff --git a/pkg/internal/apis/certmanager/validation/issuer_test.go b/pkg/internal/apis/certmanager/validation/issuer_test.go index 88b0c8c4f..99f132fe0 100644 --- a/pkg/internal/apis/certmanager/validation/issuer_test.go +++ b/pkg/internal/apis/certmanager/validation/issuer_test.go @@ -640,15 +640,7 @@ func TestValidateACMEIssuerDNS01Config(t *testing.T) { }, errs: []*field.Error{}, }, - "valid rfc2136 config": { - cfg: &cmacme.ACMEChallengeSolverDNS01{ - RFC2136: &cmacme.ACMEIssuerDNS01ProviderRFC2136{ - Nameserver: "127.0.0.1", - }, - }, - errs: []*field.Error{}, - }, - "missing rfc2136 required field": { + "rfc2136 provider with missing nameserver": { cfg: &cmacme.ACMEChallengeSolverDNS01{ RFC2136: &cmacme.ACMEIssuerDNS01ProviderRFC2136{}, }, @@ -656,14 +648,38 @@ func TestValidateACMEIssuerDNS01Config(t *testing.T) { field.Required(fldPath.Child("rfc2136", "nameserver"), ""), }, }, - "rfc2136 provider invalid nameserver": { + "rfc2136 provider with IPv4 nameserver": { + cfg: &cmacme.ACMEChallengeSolverDNS01{ + RFC2136: &cmacme.ACMEIssuerDNS01ProviderRFC2136{ + Nameserver: "127.0.0.1", + }, + }, + errs: []*field.Error{}, + }, + "rfc2136 provider with FQDN nameserver": { cfg: &cmacme.ACMEChallengeSolverDNS01{ RFC2136: &cmacme.ACMEIssuerDNS01ProviderRFC2136{ Nameserver: "dns.example.com", }, }, + errs: []*field.Error{}, + }, + "rfc2136 provider with hostname nameserver": { + cfg: &cmacme.ACMEChallengeSolverDNS01{ + RFC2136: &cmacme.ACMEIssuerDNS01ProviderRFC2136{ + Nameserver: "dns", + }, + }, + errs: []*field.Error{}, + }, + "rfc2136 provider with nameserver without host": { + cfg: &cmacme.ACMEChallengeSolverDNS01{ + RFC2136: &cmacme.ACMEIssuerDNS01ProviderRFC2136{ + Nameserver: ":53", + }, + }, errs: []*field.Error{ - field.Invalid(fldPath.Child("rfc2136", "nameserver"), "", "Nameserver invalid. Check the documentation for details."), + field.Invalid(fldPath.Child("rfc2136", "nameserver"), ":53", "nameserver must be an hostname or IP address in the form host[:port]."), }, }, "rfc2136 provider using case-camel in algorithm": { diff --git a/pkg/internal/apis/certmanager/validation/util/nameserver.go b/pkg/internal/apis/certmanager/validation/util/nameserver.go index 33bcbdbd4..766ba22b5 100644 --- a/pkg/internal/apis/certmanager/validation/util/nameserver.go +++ b/pkg/internal/apis/certmanager/validation/util/nameserver.go @@ -24,8 +24,9 @@ import ( var defaultRFC2136Port = "53" -// This function make a valid nameserver as per RFC2136 +// This function returns a valid nameserver (in the form :) for the RFC2136 provider func ValidNameserver(nameserver string) (string, error) { + nameserver = strings.TrimSpace(nameserver) if nameserver == "" { return "", fmt.Errorf("RFC2136 nameserver missing") @@ -40,8 +41,7 @@ func ValidNameserver(nameserver string) (string, error) { // nameserver.com: "nameserver.com" "" // nameserver.com:53 "nameserver.com" 53 // :53 "" 53 - host, port, err := net.SplitHostPort(strings.TrimSpace(nameserver)) - + host, port, err := net.SplitHostPort(nameserver) if err != nil { if strings.Contains(err.Error(), "missing port") { host = nameserver @@ -52,12 +52,8 @@ func ValidNameserver(nameserver string) (string, error) { port = defaultRFC2136Port } - if host != "" { - if ipaddr := net.ParseIP(host); ipaddr == nil { - return "", fmt.Errorf("RFC2136 nameserver must be a valid IP Address, not %v", host) - } - } else { - return "", fmt.Errorf("RFC2136 nameserver has no IP Address defined, %v", nameserver) + if host == "" { + return "", fmt.Errorf("RFC2136 nameserver has no host defined, %v", nameserver) } nameserver = host + ":" + port diff --git a/pkg/issuer/acme/dns/rfc2136/rfc2136_test.go b/pkg/issuer/acme/dns/rfc2136/rfc2136_test.go index 859f17863..c20091e0e 100644 --- a/pkg/issuer/acme/dns/rfc2136/rfc2136_test.go +++ b/pkg/issuer/acme/dns/rfc2136/rfc2136_test.go @@ -135,22 +135,22 @@ func TestRFC2136TsigClient(t *testing.T) { } } -func TestRFC2136InvalidNameserverFQDN(t *testing.T) { - _, err := NewDNSProviderCredentials("nameserver.com", "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) +func TestRFC2136NameserverEmpty(t *testing.T) { + _, err := NewDNSProviderCredentials("", "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) assert.Error(t, err) } -func TestRFC2136InvalidNameserverFQDNWithPort(t *testing.T) { - _, err := NewDNSProviderCredentials("nameserver.com:53", "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) +func TestRFC2136NameserverWithoutHost(t *testing.T) { + _, err := NewDNSProviderCredentials(":53", "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) assert.Error(t, err) } -func TestRFC2136InvalidNameserverFQDNWithPort2(t *testing.T) { - _, err := NewDNSProviderCredentials("nameserver.com:", "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) +func TestRFC2136NameserverWithoutHostNorPort(t *testing.T) { + _, err := NewDNSProviderCredentials(":", "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) assert.Error(t, err) } -func TestRFC2136NameserverWithoutPort(t *testing.T) { +func TestRFC2136NameserverIPv4WithoutPort(t *testing.T) { nameserver := "127.0.0.1" dnsProvider, err := NewDNSProviderCredentials(nameserver, "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) assert.NoError(t, err) @@ -161,7 +161,7 @@ func TestRFC2136NameserverWithoutPort(t *testing.T) { } -func TestRFC2136NameserverWithoutPort2(t *testing.T) { +func TestRFC2136NameserverIPv4WithEmptyPort(t *testing.T) { nameserver := "127.0.0.1:" dnsProvider, err := NewDNSProviderCredentials(nameserver, "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) assert.NoError(t, err) @@ -171,7 +171,7 @@ func TestRFC2136NameserverWithoutPort2(t *testing.T) { } } -func TestRFC2136NameserverWithPort(t *testing.T) { +func TestRFC2136NameserverIPv4WithPort(t *testing.T) { nameserver := "127.0.0.1:12345" dnsProvider, err := NewDNSProviderCredentials(nameserver, "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) assert.NoError(t, err) @@ -181,25 +181,66 @@ func TestRFC2136NameserverWithPort(t *testing.T) { } } -func TestRFC2136NameserverWithPortNoIP(t *testing.T) { - _, err := NewDNSProviderCredentials(":53", "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) - assert.Error(t, err) +func TestRFC2136NameserverFQDNWithoutPort(t *testing.T) { + nameserver := "dns.example.net" + dnsProvider, err := NewDNSProviderCredentials(nameserver, "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) + assert.NoError(t, err) + + if dnsProvider.nameserver != nameserver+":"+defaultPort { + t.Errorf("dnsProvider.nameserver to be %v, but it is %v", nameserver+":"+defaultPort, dnsProvider.nameserver) + } } -func TestRFC2136NameserverEmpty(t *testing.T) { - _, err := NewDNSProviderCredentials("", "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) - assert.Error(t, err) +func TestRFC2136NameserverFQDNWithEmptyPort(t *testing.T) { + nameserver := "dns.example.com:" + dnsProvider, err := NewDNSProviderCredentials(nameserver, "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) + assert.NoError(t, err) + + if dnsProvider.nameserver != nameserver+defaultPort { + t.Errorf("dnsProvider.nameserver to be %v%v, but it is %v", nameserver, defaultPort, dnsProvider.nameserver) + } } -func TestRFC2136NameserverIPInvalid(t *testing.T) { - _, err := NewDNSProviderCredentials("900.65.3.64", "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) - assert.Error(t, err) +func TestRFC2136NameserverFQDNWithPort(t *testing.T) { + nameserver := "dns.example.net:12345" + dnsProvider, err := NewDNSProviderCredentials(nameserver, "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) + assert.NoError(t, err) + + if dnsProvider.nameserver != nameserver { + t.Errorf("dnsProvider.nameserver to be %v, but it is %v", nameserver, dnsProvider.nameserver) + } } -func TestRFC2136NameserverIPInvalid2(t *testing.T) { - _, err := NewDNSProviderCredentials(":", "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) - assert.Error(t, err) +func TestRFC2136NameserverHostnameWithoutPort(t *testing.T) { + nameserver := "dns" + dnsProvider, err := NewDNSProviderCredentials(nameserver, "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) + assert.NoError(t, err) + + if dnsProvider.nameserver != nameserver+":"+defaultPort { + t.Errorf("dnsProvider.nameserver to be %v, but it is %v", nameserver+":"+defaultPort, dnsProvider.nameserver) + } } + +func TestRFC2136NameserverHostnameWithEmptyPort(t *testing.T) { + nameserver := "dns:" + dnsProvider, err := NewDNSProviderCredentials(nameserver, "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) + assert.NoError(t, err) + + if dnsProvider.nameserver != nameserver+defaultPort { + t.Errorf("dnsProvider.nameserver to be %v%v, but it is %v", nameserver, defaultPort, dnsProvider.nameserver) + } +} + +func TestRFC2136NameserverHostnameWithPort(t *testing.T) { + nameserver := "dns:12345" + dnsProvider, err := NewDNSProviderCredentials(nameserver, "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) + assert.NoError(t, err) + + if dnsProvider.nameserver != nameserver { + t.Errorf("dnsProvider.nameserver to be %v, but it is %v", nameserver, dnsProvider.nameserver) + } +} + func TestRFC2136DefaultTSIGAlgorithm(t *testing.T) { provider, err := NewDNSProviderCredentials("127.0.0.1:0", "", rfc2136TestTsigKeyName, rfc2136TestTsigSecret) if err != nil {