fix(tls): use Go TLS defaults (#8227)

Remove fixed TLS 1.2 cipher suite list and maximum TLS version so
crypto/tls can use its maintained defaults. Keep TLS 1.2 as the
minimum supported version.

Document the shared TLS default behavior for plugins that expose TLS
configuration and add coverage to ensure CoreDNS leaves Go-managed
TLS fields unset.

Signed-off-by: Ville Vesilehto <ville@vesilehto.fi>
This commit is contained in:
Ville Vesilehto
2026-07-05 02:03:02 +03:00
committed by GitHub
parent 679f764ae1
commit bc4343b083
6 changed files with 44 additions and 16 deletions

View File

@@ -55,6 +55,10 @@ etcd [ZONES...] {
* three arguments - path to cert PEM file, path to client private key PEM file, path to CA PEM * three arguments - path to cert PEM file, path to client private key PEM file, path to CA PEM
file - if the server certificate is not signed by a system-installed CA and client certificate file - if the server certificate is not signed by a system-installed CA and client certificate
is needed. is needed.
CoreDNS sets the minimum TLS version to TLS 1.2. The maximum TLS version, TLS 1.2 cipher suites, and
key exchange mechanisms use the Go `crypto/tls` defaults.
* `min-lease-ttl` the minimum TTL for DNS records based on etcd lease duration. Accepts flexible time formats like '30', '30s', '5m', '1h', '2h30m'. Default: 30 seconds. * `min-lease-ttl` the minimum TTL for DNS records based on etcd lease duration. Accepts flexible time formats like '30', '30s', '5m', '1h', '2h30m'. Default: 30 seconds.
* `max-lease-ttl` the maximum TTL for DNS records based on etcd lease duration. Accepts flexible time formats like '30', '30s', '5m', '1h', '2h30m'. Default: 24 hours. * `max-lease-ttl` the maximum TTL for DNS records based on etcd lease duration. Accepts flexible time formats like '30', '30s', '5m', '1h', '2h30m'. Default: 24 hours.

View File

@@ -89,6 +89,9 @@ forward FROM TO... {
* `tls` **CERT** **KEY** **CA** - client authentication is used with the specified cert/key pair. * `tls` **CERT** **KEY** **CA** - client authentication is used with the specified cert/key pair.
The server certificate is verified using the specified CA file The server certificate is verified using the specified CA file
CoreDNS sets the minimum TLS version to TLS 1.2. The maximum TLS version, TLS 1.2 cipher suites, and
key exchange mechanisms use the Go `crypto/tls` defaults.
* `tls_servername` **NAME** allows you to set a server name in the TLS configuration; for instance 9.9.9.9 * `tls_servername` **NAME** allows you to set a server name in the TLS configuration; for instance 9.9.9.9
needs this to be set to `dns.quad9.net`. Using TLS forwarding but not setting `tls_servername` results in anyone needs this to be set to `dns.quad9.net`. Using TLS forwarding but not setting `tls_servername` results in anyone
being able to man-in-the-middle your connection to the DNS server you are forwarding to. Because of this, being able to man-in-the-middle your connection to the DNS server you are forwarding to. Because of this,

View File

@@ -50,6 +50,9 @@ grpc FROM TO... {
* `tls` **CERT** **KEY** **CA** - client authentication is used with the specified cert/key pair. * `tls` **CERT** **KEY** **CA** - client authentication is used with the specified cert/key pair.
The server certificate is verified using the specified CA file The server certificate is verified using the specified CA file
CoreDNS sets the minimum TLS version to TLS 1.2. The maximum TLS version, TLS 1.2 cipher suites, and
key exchange mechanisms use the Go `crypto/tls` defaults.
* `tls_servername` **NAME** allows you to set a server name in the TLS configuration; for instance 9.9.9.9 * `tls_servername` **NAME** allows you to set a server name in the TLS configuration; for instance 9.9.9.9
needs this to be set to `dns.quad9.net`. Multiple upstreams are still allowed in this scenario, needs this to be set to `dns.quad9.net`. Multiple upstreams are still allowed in this scenario,
but they have to use the same `tls_servername`. E.g. mixing 9.9.9.9 (QuadDNS) with 1.1.1.1 but they have to use the same `tls_servername`. E.g. mixing 9.9.9.9 (QuadDNS) with 1.1.1.1
@@ -158,4 +161,4 @@ example.org {
## Bugs ## Bugs
The TLS config is global for the whole grpc proxy if you need a different `tls_servername` for The TLS config is global for the whole grpc proxy if you need a different `tls_servername` for
different upstreams you're out of luck. different upstreams you're out of luck.

View File

@@ -13,15 +13,6 @@ import (
func setTLSDefaults(ctls *tls.Config) { func setTLSDefaults(ctls *tls.Config) {
ctls.MinVersion = tls.VersionTLS12 ctls.MinVersion = tls.VersionTLS12
ctls.MaxVersion = tls.VersionTLS13
ctls.CipherSuites = []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
}
} }
// NewTLSConfigFromArgs returns a TLS config based upon the passed // NewTLSConfigFromArgs returns a TLS config based upon the passed
@@ -102,7 +93,7 @@ func NewTLSConfig(certPath, keyPath, caPath string) (*tls.Config, error) {
return nil, err return nil, err
} }
// #nosec G402 -- MinVersion and MaxVersion are set in setTLSDefaults // #nosec G402 -- MinVersion is set in setTLSDefaults
tlsConfig := &tls.Config{ tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert}, Certificates: []tls.Certificate{cert},
RootCAs: roots, RootCAs: roots,
@@ -120,7 +111,7 @@ func NewTLSClientConfig(caPath string) (*tls.Config, error) {
return nil, err return nil, err
} }
// #nosec G402 -- MinVersion and MaxVersion are set in setTLSDefaults // #nosec G402 -- MinVersion is set in setTLSDefaults
tlsConfig := &tls.Config{ tlsConfig := &tls.Config{
RootCAs: roots, RootCAs: roots,
} }

View File

@@ -1,6 +1,7 @@
package tls package tls
import ( import (
"crypto/tls"
"path/filepath" "path/filepath"
"testing" "testing"
@@ -21,35 +22,55 @@ func getPEMFiles(t *testing.T) (cert, key, ca string) {
return return
} }
func assertTLSDefaults(t *testing.T, c *tls.Config) {
t.Helper()
if c.MinVersion != tls.VersionTLS12 {
t.Errorf("MinVersion = %d, want %d", c.MinVersion, tls.VersionTLS12)
}
if c.MaxVersion != 0 {
t.Errorf("MaxVersion = %d, want 0 to use Go defaults", c.MaxVersion)
}
if c.CipherSuites != nil {
t.Errorf("CipherSuites = %v, want nil to use Go defaults", c.CipherSuites)
}
if c.CurvePreferences != nil {
t.Errorf("CurvePreferences = %v, want nil to use Go defaults", c.CurvePreferences)
}
}
func TestNewTLSConfig(t *testing.T) { func TestNewTLSConfig(t *testing.T) {
cert, key, ca := getPEMFiles(t) cert, key, ca := getPEMFiles(t)
_, err := NewTLSConfig(cert, key, ca) c, err := NewTLSConfig(cert, key, ca)
if err != nil { if err != nil {
t.Errorf("Failed to create TLSConfig: %s", err) t.Errorf("Failed to create TLSConfig: %s", err)
} }
assertTLSDefaults(t, c)
} }
func TestNewTLSClientConfig(t *testing.T) { func TestNewTLSClientConfig(t *testing.T) {
_, _, ca := getPEMFiles(t) _, _, ca := getPEMFiles(t)
_, err := NewTLSClientConfig(ca) c, err := NewTLSClientConfig(ca)
if err != nil { if err != nil {
t.Errorf("Failed to create TLSConfig: %s", err) t.Errorf("Failed to create TLSConfig: %s", err)
} }
assertTLSDefaults(t, c)
} }
func TestNewTLSConfigFromArgs(t *testing.T) { func TestNewTLSConfigFromArgs(t *testing.T) {
cert, key, ca := getPEMFiles(t) cert, key, ca := getPEMFiles(t)
_, err := NewTLSConfigFromArgs() c, err := NewTLSConfigFromArgs()
if err != nil { if err != nil {
t.Errorf("Failed to create TLSConfig: %s", err) t.Errorf("Failed to create TLSConfig: %s", err)
} }
assertTLSDefaults(t, c)
c, err := NewTLSConfigFromArgs(ca) c, err = NewTLSConfigFromArgs(ca)
if err != nil { if err != nil {
t.Errorf("Failed to create TLSConfig: %s", err) t.Errorf("Failed to create TLSConfig: %s", err)
} }
assertTLSDefaults(t, c)
if c.RootCAs == nil { if c.RootCAs == nil {
t.Error("RootCAs should not be nil when one arg passed") t.Error("RootCAs should not be nil when one arg passed")
} }
@@ -58,6 +79,7 @@ func TestNewTLSConfigFromArgs(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Failed to create TLSConfig: %s", err) t.Errorf("Failed to create TLSConfig: %s", err)
} }
assertTLSDefaults(t, c)
if c.RootCAs != nil { if c.RootCAs != nil {
t.Error("RootCAs should be nil when two args passed") t.Error("RootCAs should be nil when two args passed")
} }
@@ -69,6 +91,7 @@ func TestNewTLSConfigFromArgs(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Failed to create TLSConfig: %s", err) t.Errorf("Failed to create TLSConfig: %s", err)
} }
assertTLSDefaults(t, c)
if c.RootCAs == nil { if c.RootCAs == nil {
t.Error("RootCAs should not be nil when three args passed") t.Error("RootCAs should not be nil when three args passed")
} }
@@ -92,6 +115,7 @@ func TestNewTLSConfigFromArgsWithRoot(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Failed to create TLSConfig: %s", err) t.Errorf("Failed to create TLSConfig: %s", err)
} }
assertTLSDefaults(t, c)
if c.RootCAs == nil { if c.RootCAs == nil {
t.Error("RootCAs should not be nil when three args passed") t.Error("RootCAs should not be nil when three args passed")
} }

View File

@@ -39,6 +39,9 @@ set to verify\_if\_given or require\_and\_verify.
The keylog can be specified to export TLS master secrets in key log format to allow external programs The keylog can be specified to export TLS master secrets in key log format to allow external programs
to decrypt TLS connections. It compromises security and should only be used for debugging! to decrypt TLS connections. It compromises security and should only be used for debugging!
CoreDNS sets the minimum TLS version to TLS 1.2. The maximum TLS version, TLS 1.2 cipher suites, and
key exchange mechanisms use the Go `crypto/tls` defaults.
## Examples ## Examples
Start a DNS-over-TLS server that picks up incoming DNS-over-TLS queries on port 5553 and uses the Start a DNS-over-TLS server that picks up incoming DNS-over-TLS queries on port 5553 and uses the