aboutsummaryrefslogtreecommitdiff
path: root/core/https/setup.go
diff options
context:
space:
mode:
authorGravatar Miek Gieben <miek@miek.nl> 2016-08-19 17:14:17 -0700
committerGravatar GitHub <noreply@github.com> 2016-08-19 17:14:17 -0700
commit9ac3cab1b7b1b1e78f86ce3c6a80fbee312162e6 (patch)
tree437e9755927c33af16276ad2602a6da115f948cb /core/https/setup.go
parenta1989c35231b0e5ea271b2f68d82c1a63e697cd0 (diff)
downloadcoredns-9ac3cab1b7b1b1e78f86ce3c6a80fbee312162e6.tar.gz
coredns-9ac3cab1b7b1b1e78f86ce3c6a80fbee312162e6.tar.zst
coredns-9ac3cab1b7b1b1e78f86ce3c6a80fbee312162e6.zip
Make CoreDNS a server type plugin for Caddy (#220)
* Make CoreDNS a server type plugin for Caddy Remove code we don't need and port all middleware over. Fix all tests and rework the documentation. Also make `go generate` build a caddy binary which we then copy into our directory. This means `go build`-builds remain working as-is. And new etc instances in each etcd test for better isolation. Fix more tests and rework test.Server with the newer support Caddy offers. Fix Makefile to support new mode of operation.
Diffstat (limited to 'core/https/setup.go')
-rw-r--r--core/https/setup.go321
1 files changed, 0 insertions, 321 deletions
diff --git a/core/https/setup.go b/core/https/setup.go
deleted file mode 100644
index ec90e0284..000000000
--- a/core/https/setup.go
+++ /dev/null
@@ -1,321 +0,0 @@
-package https
-
-import (
- "bytes"
- "crypto/tls"
- "encoding/pem"
- "io/ioutil"
- "log"
- "os"
- "path/filepath"
- "strconv"
- "strings"
-
- "github.com/miekg/coredns/core/setup"
- "github.com/miekg/coredns/middleware"
- "github.com/miekg/coredns/server"
-)
-
-// Setup sets up the TLS configuration and installs certificates that
-// are specified by the user in the config file. All the automatic HTTPS
-// stuff comes later outside of this function.
-func Setup(c *setup.Controller) (middleware.Middleware, error) {
- if c.Port == "80" {
- c.TLS.Enabled = false
- log.Printf("[WARNING] TLS disabled for %s.", c.Address())
- return nil, nil
- }
- c.TLS.Enabled = true
-
- // TODO(miek): disabled for now
- return nil, nil
-
- for c.Next() {
- var certificateFile, keyFile, loadDir, maxCerts string
-
- args := c.RemainingArgs()
- switch len(args) {
- case 1:
- c.TLS.LetsEncryptEmail = args[0]
-
- // user can force-disable managed TLS this way
- if c.TLS.LetsEncryptEmail == "off" {
- c.TLS.Enabled = false
- return nil, nil
- }
- case 2:
- certificateFile = args[0]
- keyFile = args[1]
- c.TLS.Manual = true
- }
-
- // Optional block with extra parameters
- var hadBlock bool
- for c.NextBlock() {
- hadBlock = true
- switch c.Val() {
- case "protocols":
- args := c.RemainingArgs()
- if len(args) != 2 {
- return nil, c.ArgErr()
- }
- value, ok := supportedProtocols[strings.ToLower(args[0])]
- if !ok {
- return nil, c.Errf("Wrong protocol name or protocol not supported '%s'", c.Val())
- }
- c.TLS.ProtocolMinVersion = value
- value, ok = supportedProtocols[strings.ToLower(args[1])]
- if !ok {
- return nil, c.Errf("Wrong protocol name or protocol not supported '%s'", c.Val())
- }
- c.TLS.ProtocolMaxVersion = value
- case "ciphers":
- for c.NextArg() {
- value, ok := supportedCiphersMap[strings.ToUpper(c.Val())]
- if !ok {
- return nil, c.Errf("Wrong cipher name or cipher not supported '%s'", c.Val())
- }
- c.TLS.Ciphers = append(c.TLS.Ciphers, value)
- }
- case "clients":
- c.TLS.ClientCerts = c.RemainingArgs()
- if len(c.TLS.ClientCerts) == 0 {
- return nil, c.ArgErr()
- }
- case "load":
- c.Args(&loadDir)
- c.TLS.Manual = true
- case "max_certs":
- c.Args(&maxCerts)
- c.TLS.OnDemand = true
- default:
- return nil, c.Errf("Unknown keyword '%s'", c.Val())
- }
- }
-
- // tls requires at least one argument if a block is not opened
- if len(args) == 0 && !hadBlock {
- return nil, c.ArgErr()
- }
-
- // set certificate limit if on-demand TLS is enabled
- if maxCerts != "" {
- maxCertsNum, err := strconv.Atoi(maxCerts)
- if err != nil || maxCertsNum < 1 {
- return nil, c.Err("max_certs must be a positive integer")
- }
- if onDemandMaxIssue == 0 || int32(maxCertsNum) < onDemandMaxIssue { // keep the minimum; TODO: We have to do this because it is global; should be per-server or per-vhost...
- onDemandMaxIssue = int32(maxCertsNum)
- }
- }
-
- // don't try to load certificates unless we're supposed to
- if !c.TLS.Enabled || !c.TLS.Manual {
- continue
- }
-
- // load a single certificate and key, if specified
- if certificateFile != "" && keyFile != "" {
- err := cacheUnmanagedCertificatePEMFile(certificateFile, keyFile)
- if err != nil {
- return nil, c.Errf("Unable to load certificate and key files for %s: %v", c.Host, err)
- }
- log.Printf("[INFO] Successfully loaded TLS assets from %s and %s", certificateFile, keyFile)
- }
-
- // load a directory of certificates, if specified
- if loadDir != "" {
- err := loadCertsInDir(c, loadDir)
- if err != nil {
- return nil, err
- }
- }
- }
-
- setDefaultTLSParams(c.Config)
-
- return nil, nil
-}
-
-// loadCertsInDir loads all the certificates/keys in dir, as long as
-// the file ends with .pem. This method of loading certificates is
-// modeled after haproxy, which expects the certificate and key to
-// be bundled into the same file:
-// https://cbonte.github.io/haproxy-dconv/configuration-1.5.html#5.1-crt
-//
-// This function may write to the log as it walks the directory tree.
-func loadCertsInDir(c *setup.Controller, dir string) error {
- return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
- if err != nil {
- log.Printf("[WARNING] Unable to traverse into %s; skipping", path)
- return nil
- }
- if info.IsDir() {
- return nil
- }
- if strings.HasSuffix(strings.ToLower(info.Name()), ".pem") {
- certBuilder, keyBuilder := new(bytes.Buffer), new(bytes.Buffer)
- var foundKey bool // use only the first key in the file
-
- bundle, err := ioutil.ReadFile(path)
- if err != nil {
- return err
- }
-
- for {
- // Decode next block so we can see what type it is
- var derBlock *pem.Block
- derBlock, bundle = pem.Decode(bundle)
- if derBlock == nil {
- break
- }
-
- if derBlock.Type == "CERTIFICATE" {
- // Re-encode certificate as PEM, appending to certificate chain
- pem.Encode(certBuilder, derBlock)
- } else if derBlock.Type == "EC PARAMETERS" {
- // EC keys generated from openssl can be composed of two blocks:
- // parameters and key (parameter block should come first)
- if !foundKey {
- // Encode parameters
- pem.Encode(keyBuilder, derBlock)
-
- // Key must immediately follow
- derBlock, bundle = pem.Decode(bundle)
- if derBlock == nil || derBlock.Type != "EC PRIVATE KEY" {
- return c.Errf("%s: expected elliptic private key to immediately follow EC parameters", path)
- }
- pem.Encode(keyBuilder, derBlock)
- foundKey = true
- }
- } else if derBlock.Type == "PRIVATE KEY" || strings.HasSuffix(derBlock.Type, " PRIVATE KEY") {
- // RSA key
- if !foundKey {
- pem.Encode(keyBuilder, derBlock)
- foundKey = true
- }
- } else {
- return c.Errf("%s: unrecognized PEM block type: %s", path, derBlock.Type)
- }
- }
-
- certPEMBytes, keyPEMBytes := certBuilder.Bytes(), keyBuilder.Bytes()
- if len(certPEMBytes) == 0 {
- return c.Errf("%s: failed to parse PEM data", path)
- }
- if len(keyPEMBytes) == 0 {
- return c.Errf("%s: no private key block found", path)
- }
-
- err = cacheUnmanagedCertificatePEMBytes(certPEMBytes, keyPEMBytes)
- if err != nil {
- return c.Errf("%s: failed to load cert and key for %s: %v", path, c.Host, err)
- }
- log.Printf("[INFO] Successfully loaded TLS assets from %s", path)
- }
- return nil
- })
-}
-
-// setDefaultTLSParams sets the default TLS cipher suites, protocol versions,
-// and server preferences of a server.Config if they were not previously set
-// (it does not overwrite; only fills in missing values). It will also set the
-// port to 443 if not already set, TLS is enabled, TLS is manual, and the host
-// does not equal localhost.
-func setDefaultTLSParams(c *server.Config) {
- // If no ciphers provided, use default list
- if len(c.TLS.Ciphers) == 0 {
- c.TLS.Ciphers = defaultCiphers
- }
-
- // Not a cipher suite, but still important for mitigating protocol downgrade attacks
- // (prepend since having it at end breaks http2 due to non-h2-approved suites before it)
- c.TLS.Ciphers = append([]uint16{tls.TLS_FALLBACK_SCSV}, c.TLS.Ciphers...)
-
- // Set default protocol min and max versions - must balance compatibility and security
- if c.TLS.ProtocolMinVersion == 0 {
- c.TLS.ProtocolMinVersion = tls.VersionTLS10
- }
- if c.TLS.ProtocolMaxVersion == 0 {
- c.TLS.ProtocolMaxVersion = tls.VersionTLS12
- }
-
- // Prefer server cipher suites
- c.TLS.PreferServerCipherSuites = true
-
- // Default TLS port is 443; only use if port is not manually specified,
- // TLS is enabled, and the host is not localhost
- if c.Port == "" && c.TLS.Enabled && (!c.TLS.Manual || c.TLS.OnDemand) && c.Host != "localhost" {
- c.Port = "443"
- }
-}
-
-// Map of supported protocols.
-// SSLv3 will be not supported in future release.
-// HTTP/2 only supports TLS 1.2 and higher.
-var supportedProtocols = map[string]uint16{
- "ssl3.0": tls.VersionSSL30,
- "tls1.0": tls.VersionTLS10,
- "tls1.1": tls.VersionTLS11,
- "tls1.2": tls.VersionTLS12,
-}
-
-// Map of supported ciphers, used only for parsing config.
-//
-// Note that, at time of writing, HTTP/2 blacklists 276 cipher suites,
-// including all but two of the suites below (the two GCM suites).
-// See https://http2.github.io/http2-spec/#BadCipherSuites
-//
-// TLS_FALLBACK_SCSV is not in this list because we manually ensure
-// it is always added (even though it is not technically a cipher suite).
-//
-// This map, like any map, is NOT ORDERED. Do not range over this map.
-var supportedCiphersMap = map[string]uint16{
- "ECDHE-RSA-AES256-GCM-SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
- "ECDHE-ECDSA-AES256-GCM-SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
- "ECDHE-RSA-AES128-GCM-SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
- "ECDHE-ECDSA-AES128-GCM-SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
- "ECDHE-RSA-AES128-CBC-SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
- "ECDHE-RSA-AES256-CBC-SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
- "ECDHE-ECDSA-AES256-CBC-SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
- "ECDHE-ECDSA-AES128-CBC-SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
- "RSA-AES128-CBC-SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA,
- "RSA-AES256-CBC-SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA,
- "ECDHE-RSA-3DES-EDE-CBC-SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
- "RSA-3DES-EDE-CBC-SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-}
-
-// List of supported cipher suites in descending order of preference.
-// Ordering is very important! Getting the wrong order will break
-// mainstream clients, especially with HTTP/2.
-//
-// Note that TLS_FALLBACK_SCSV is not in this list since it is always
-// added manually.
-var supportedCiphers = []uint16{
- tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
- tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
- tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
- tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
- tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
- tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
- tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
- tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
- tls.TLS_RSA_WITH_AES_256_CBC_SHA,
- tls.TLS_RSA_WITH_AES_128_CBC_SHA,
- tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
- tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-}
-
-// List of all the ciphers we want to use by default
-var defaultCiphers = []uint16{
- tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
- tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
- tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
- tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
- tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
- tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
- tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
- tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
- tls.TLS_RSA_WITH_AES_256_CBC_SHA,
- tls.TLS_RSA_WITH_AES_128_CBC_SHA,
-}