mirror of
				https://github.com/coredns/coredns.git
				synced 2025-11-03 18:53:13 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			150 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package tls
 | 
						|
 | 
						|
import (
 | 
						|
	"crypto/tls"
 | 
						|
	"crypto/x509"
 | 
						|
	"fmt"
 | 
						|
	"net"
 | 
						|
	"net/http"
 | 
						|
	"os"
 | 
						|
	"path/filepath"
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
func setTLSDefaults(ctls *tls.Config) {
 | 
						|
	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,
 | 
						|
		tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
 | 
						|
		tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
 | 
						|
		tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// NewTLSConfigFromArgs returns a TLS config based upon the passed
 | 
						|
// in list of arguments. Typically these come straight from the
 | 
						|
// Corefile.
 | 
						|
// no args
 | 
						|
//   - creates a Config with no cert and using system CAs
 | 
						|
//   - use for a client that talks to a server with a public signed cert (CA installed in system)
 | 
						|
//   - the client will not be authenticated by the server since there is no cert
 | 
						|
//
 | 
						|
// one arg: the path to CA PEM file
 | 
						|
//   - creates a Config with no cert using a specific CA
 | 
						|
//   - use for a client that talks to a server with a private signed cert (CA not installed in system)
 | 
						|
//   - the client will not be authenticated by the server since there is no cert
 | 
						|
//
 | 
						|
// two args: path to cert PEM file, the path to private key PEM file
 | 
						|
//   - creates a Config with a cert, using system CAs to validate the other end
 | 
						|
//   - use for:
 | 
						|
//   - a server; or,
 | 
						|
//   - a client that talks to a server with a public cert and needs certificate-based authentication
 | 
						|
//   - the other end will authenticate this end via the provided cert
 | 
						|
//   - the cert of the other end will be verified via system CAs
 | 
						|
//
 | 
						|
// three args: path to cert PEM file, path to client private key PEM file, path to CA PEM file
 | 
						|
//   - creates a Config with the cert, using specified CA to validate the other end
 | 
						|
//   - use for:
 | 
						|
//   - a server; or,
 | 
						|
//   - a client that talks to a server with a privately signed cert and needs certificate-based
 | 
						|
//     authentication
 | 
						|
//   - the other end will authenticate this end via the provided cert
 | 
						|
//   - this end will verify the other end's cert using the specified CA
 | 
						|
func NewTLSConfigFromArgs(args ...string) (*tls.Config, error) {
 | 
						|
	var err error
 | 
						|
	var c *tls.Config
 | 
						|
	switch len(args) {
 | 
						|
	case 0:
 | 
						|
		// No client cert, use system CA
 | 
						|
		c, err = NewTLSClientConfig("")
 | 
						|
	case 1:
 | 
						|
		// No client cert, use specified CA
 | 
						|
		c, err = NewTLSClientConfig(args[0])
 | 
						|
	case 2:
 | 
						|
		// Client cert, use system CA
 | 
						|
		c, err = NewTLSConfig(args[0], args[1], "")
 | 
						|
	case 3:
 | 
						|
		// Client cert, use specified CA
 | 
						|
		c, err = NewTLSConfig(args[0], args[1], args[2])
 | 
						|
	default:
 | 
						|
		err = fmt.Errorf("maximum of three arguments allowed for TLS config, found %d", len(args))
 | 
						|
	}
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return c, nil
 | 
						|
}
 | 
						|
 | 
						|
// NewTLSConfig returns a TLS config that includes a certificate
 | 
						|
// Use for server TLS config or when using a client certificate
 | 
						|
// If caPath is empty, system CAs will be used
 | 
						|
func NewTLSConfig(certPath, keyPath, caPath string) (*tls.Config, error) {
 | 
						|
	cert, err := tls.LoadX509KeyPair(certPath, keyPath)
 | 
						|
	if err != nil {
 | 
						|
		return nil, fmt.Errorf("could not load TLS cert: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	roots, err := loadRoots(caPath)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	tlsConfig := &tls.Config{Certificates: []tls.Certificate{cert}, RootCAs: roots}
 | 
						|
	setTLSDefaults(tlsConfig)
 | 
						|
 | 
						|
	return tlsConfig, nil
 | 
						|
}
 | 
						|
 | 
						|
// NewTLSClientConfig returns a TLS config for a client connection
 | 
						|
// If caPath is empty, system CAs will be used
 | 
						|
func NewTLSClientConfig(caPath string) (*tls.Config, error) {
 | 
						|
	roots, err := loadRoots(caPath)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	tlsConfig := &tls.Config{RootCAs: roots}
 | 
						|
	setTLSDefaults(tlsConfig)
 | 
						|
 | 
						|
	return tlsConfig, nil
 | 
						|
}
 | 
						|
 | 
						|
func loadRoots(caPath string) (*x509.CertPool, error) {
 | 
						|
	if caPath == "" {
 | 
						|
		return nil, nil
 | 
						|
	}
 | 
						|
 | 
						|
	roots := x509.NewCertPool()
 | 
						|
	pem, err := os.ReadFile(filepath.Clean(caPath))
 | 
						|
	if err != nil {
 | 
						|
		return nil, fmt.Errorf("error reading %s: %s", caPath, err)
 | 
						|
	}
 | 
						|
	ok := roots.AppendCertsFromPEM(pem)
 | 
						|
	if !ok {
 | 
						|
		return nil, fmt.Errorf("could not read root certs: %s", err)
 | 
						|
	}
 | 
						|
	return roots, nil
 | 
						|
}
 | 
						|
 | 
						|
// NewHTTPSTransport returns an HTTP transport configured using tls.Config
 | 
						|
func NewHTTPSTransport(cc *tls.Config) *http.Transport {
 | 
						|
	tr := &http.Transport{
 | 
						|
		Proxy: http.ProxyFromEnvironment,
 | 
						|
		Dial: (&net.Dialer{
 | 
						|
			Timeout:   30 * time.Second,
 | 
						|
			KeepAlive: 30 * time.Second,
 | 
						|
		}).Dial,
 | 
						|
		TLSHandshakeTimeout: 10 * time.Second,
 | 
						|
		TLSClientConfig:     cc,
 | 
						|
		MaxIdleConnsPerHost: 25,
 | 
						|
	}
 | 
						|
 | 
						|
	return tr
 | 
						|
}
 |