Browse Source

Merge pull request #8616 from mitake/peer-cn-auth

RFC: etcdmain, pkg: CN based auth for inter peer connection
Gyu-Ho Lee 8 years ago
parent
commit
863dfd1f0e

+ 5 - 0
Documentation/op-guide/configuration.md

@@ -295,6 +295,11 @@ The security flags help to [build a secure etcd cluster][security].
 + default: false
 + default: false
 + env variable: ETCD_PEER_AUTO_TLS
 + env variable: ETCD_PEER_AUTO_TLS
 
 
+### --peer-cert-allowed-cn
++ Allowed CommonName for inter peer authentication.
++ default: none
++ env variable: ETCD_PEER_CERT_ALLOWED_CN
+
 ## Logging flags
 ## Logging flags
 
 
 ### --debug
 ### --debug

+ 77 - 0
e2e/etcd_config_test.go

@@ -113,3 +113,80 @@ func TestEtcdUnixPeers(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 }
 }
+
+// TestEtcdPeerCNAuth checks that the inter peer auth based on CN of cert is working correctly.
+func TestEtcdPeerCNAuth(t *testing.T) {
+	peers, tmpdirs := make([]string, 3), make([]string, 3)
+	for i := range peers {
+		peers[i] = fmt.Sprintf("e%d=https://127.0.0.1:%d", i, etcdProcessBasePort+i)
+		d, err := ioutil.TempDir("", fmt.Sprintf("e%d.etcd", i))
+		if err != nil {
+			t.Fatal(err)
+		}
+		tmpdirs[i] = d
+	}
+	ic := strings.Join(peers, ",")
+
+	procs := make([]*expect.ExpectProcess, len(peers))
+	defer func() {
+		for i := range procs {
+			if procs[i] != nil {
+				procs[i].Stop()
+			}
+			os.RemoveAll(tmpdirs[i])
+		}
+	}()
+
+	// node 0 and 1 have a cert with the correct CN, node 2 doesn't
+	for i := range procs {
+		commonArgs := []string{
+			binDir + "/etcd",
+			"--name", fmt.Sprintf("e%d", i),
+			"--listen-client-urls", "http://0.0.0.0:0",
+			"--data-dir", tmpdirs[i],
+			"--advertise-client-urls", "http://0.0.0.0:0",
+			"--listen-peer-urls", fmt.Sprintf("https://127.0.0.1:%d,https://127.0.0.1:%d", etcdProcessBasePort+i, etcdProcessBasePort+len(peers)+i),
+			"--initial-advertise-peer-urls", fmt.Sprintf("https://127.0.0.1:%d", etcdProcessBasePort+i),
+			"--initial-cluster", ic,
+		}
+
+		var args []string
+		if i <= 1 {
+			args = []string{
+				"--peer-cert-file", certPath,
+				"--peer-key-file", privateKeyPath,
+				"--peer-trusted-ca-file", caPath,
+				"--peer-client-cert-auth",
+				"--peer-cert-allowed-cn", "example.com",
+			}
+		} else {
+			args = []string{
+				"--peer-cert-file", certPath2,
+				"--peer-key-file", privateKeyPath2,
+				"--peer-trusted-ca-file", caPath,
+				"--peer-client-cert-auth",
+				"--peer-cert-allowed-cn", "example2.com",
+			}
+		}
+
+		commonArgs = append(commonArgs, args...)
+
+		p, err := spawnCmd(commonArgs)
+		if err != nil {
+			t.Fatal(err)
+		}
+		procs[i] = p
+	}
+
+	for i, p := range procs {
+		var expect []string
+		if i <= 1 {
+			expect = etcdServerReadyLines
+		} else {
+			expect = []string{"(remote error: tls: bad certificate)"}
+		}
+		if err := waitReadyExpectProc(p, expect); err != nil {
+			t.Fatal(err)
+		}
+	}
+}

+ 6 - 0
e2e/main_test.go

@@ -21,6 +21,9 @@ var (
 	privateKeyPath string
 	privateKeyPath string
 	caPath         string
 	caPath         string
 
 
+	certPath2       string
+	privateKeyPath2 string
+
 	crlPath               string
 	crlPath               string
 	revokedCertPath       string
 	revokedCertPath       string
 	revokedPrivateKeyPath string
 	revokedPrivateKeyPath string
@@ -43,6 +46,9 @@ func TestMain(m *testing.M) {
 	revokedPrivateKeyPath = certDir + "/server-revoked.key.insecure"
 	revokedPrivateKeyPath = certDir + "/server-revoked.key.insecure"
 	crlPath = certDir + "/revoke.crl"
 	crlPath = certDir + "/revoke.crl"
 
 
+	certPath2 = certDir + "/server2.crt"
+	privateKeyPath2 = certDir + "/server2.key.insecure"
+
 	v := m.Run()
 	v := m.Run()
 	if v == 0 && testutil.CheckLeakedGoroutine() {
 	if v == 0 && testutil.CheckLeakedGoroutine() {
 		os.Exit(1)
 		os.Exit(1)

+ 1 - 0
etcdmain/config.go

@@ -187,6 +187,7 @@ func newConfig() *config {
 	fs.StringVar(&cfg.PeerTLSInfo.TrustedCAFile, "peer-trusted-ca-file", "", "Path to the peer server TLS trusted CA file.")
 	fs.StringVar(&cfg.PeerTLSInfo.TrustedCAFile, "peer-trusted-ca-file", "", "Path to the peer server TLS trusted CA file.")
 	fs.BoolVar(&cfg.PeerAutoTLS, "peer-auto-tls", false, "Peer TLS using generated certificates")
 	fs.BoolVar(&cfg.PeerAutoTLS, "peer-auto-tls", false, "Peer TLS using generated certificates")
 	fs.StringVar(&cfg.PeerTLSInfo.CRLFile, "peer-crl-file", "", "Path to the peer certificate revocation list file.")
 	fs.StringVar(&cfg.PeerTLSInfo.CRLFile, "peer-crl-file", "", "Path to the peer certificate revocation list file.")
+	fs.StringVar(&cfg.PeerTLSInfo.AllowedCN, "peer-cert-allowed-cn", "", "Allowed CN for inter peer authentication.")
 
 
 	// logging
 	// logging
 	fs.BoolVar(&cfg.Debug, "debug", false, "Enable debug-level logging for etcd.")
 	fs.BoolVar(&cfg.Debug, "debug", false, "Enable debug-level logging for etcd.")

+ 15 - 15
integration/fixtures/ca.crt

@@ -1,22 +1,22 @@
 -----BEGIN CERTIFICATE-----
 -----BEGIN CERTIFICATE-----
-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
+MIIDrjCCApagAwIBAgIUD/nWsq3FfCKbMoY0HPFWnT0vEsMwDQYJKoZIhvcNAQEL
 BQAwbzEMMAoGA1UEBhMDVVNBMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH
 BQAwbzEMMAoGA1UEBhMDVVNBMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH
 Ew1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKEwRldGNkMRYwFAYDVQQLEw1ldGNkIFNl
 Ew1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKEwRldGNkMRYwFAYDVQQLEw1ldGNkIFNl
-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
+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
-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
+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
 -----END CERTIFICATE-----
 -----END CERTIFICATE-----

+ 9 - 0
integration/fixtures/gencerts.sh

@@ -23,6 +23,15 @@ cfssl gencert \
 mv server.pem server.crt
 mv server.pem server.crt
 mv server-key.pem server.key.insecure
 mv server-key.pem server.key.insecure
 
 
+# generate DNS: localhost, IP: 127.0.0.1, CN: example2.com certificates
+cfssl gencert \
+    --ca ./ca.crt \
+    --ca-key ./ca-key.pem \
+    --config ./gencert.json \
+    ./server-ca-csr2.json | cfssljson --bare ./server2
+mv server2.pem server2.crt
+mv server2-key.pem server2.key.insecure
+
 # generate revoked certificates and crl
 # generate revoked certificates and crl
 cfssl gencert --ca ./ca.crt \
 cfssl gencert --ca ./ca.crt \
     --ca-key ./ca-key.pem \
     --ca-key ./ca-key.pem \

BIN
integration/fixtures/revoke.crl


+ 20 - 0
integration/fixtures/server-ca-csr2.json

@@ -0,0 +1,20 @@
+{
+  "key": {
+    "algo": "rsa",
+    "size": 2048
+  },
+  "names": [
+    {
+      "O": "etcd",
+      "OU": "etcd Security",
+      "L": "San Francisco",
+      "ST": "California",
+      "C": "USA"
+    }
+  ],
+  "CN": "example2.com",
+  "hosts": [
+    "127.0.0.1",
+    "localhost"
+  ]
+}

+ 16 - 16
integration/fixtures/server-revoked.crt

@@ -1,24 +1,24 @@
 -----BEGIN CERTIFICATE-----
 -----BEGIN CERTIFICATE-----
-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
+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
-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
+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
-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
+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
-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
+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
 -----END CERTIFICATE-----
 -----END CERTIFICATE-----

+ 25 - 25
integration/fixtures/server-revoked.key.insecure

@@ -1,27 +1,27 @@
 -----BEGIN RSA PRIVATE KEY-----
 -----BEGIN RSA PRIVATE KEY-----
-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
+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
 -----END RSA PRIVATE KEY-----
 -----END RSA PRIVATE KEY-----

+ 16 - 16
integration/fixtures/server-wildcard.crt

@@ -1,24 +1,24 @@
 -----BEGIN CERTIFICATE-----
 -----BEGIN CERTIFICATE-----
-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
+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
-Y3VyaXR5MQswCQYDVQQDEwJjYTAeFw0xNzA4MjExMDE4MDBaFw0yNzA4MTkxMDE4
+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
-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
+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
-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
+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
 -----END CERTIFICATE-----
 -----END CERTIFICATE-----

+ 25 - 25
integration/fixtures/server-wildcard.key.insecure

@@ -1,27 +1,27 @@
 -----BEGIN RSA PRIVATE KEY-----
 -----BEGIN RSA PRIVATE KEY-----
-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
+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
 -----END RSA PRIVATE KEY-----
 -----END RSA PRIVATE KEY-----

+ 16 - 16
integration/fixtures/server.crt

@@ -1,24 +1,24 @@
 -----BEGIN CERTIFICATE-----
 -----BEGIN CERTIFICATE-----
-MIIEEjCCAvqgAwIBAgIUb73oe3m2k5Mo/gUdCT5svl4yZFkwDQYJKoZIhvcNAQEL
+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
-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
+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
-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
+A4IBDwAwggEKAoIBAQC9AxnRD8ekAuOX8tjBXyhWewcLTI/G1+n7DgkTE90bKypo
+MBCR5sQljt2TmQbjvFIXxZMxoHnFpg9cDOmi6Y7O7XoUSCLf4Aa/KJvomZbYvFLg
+IPy8bjzh2e/M8+fgvOxyPysqsdLxbUh0jBVcYyiRfMyvzO2hN/BN42DDfnRcarnn
+g3tlae8QbZPuGKGl4zelDHBaClVeXolMqbt5vZRin0ih/hc6Hpy6oHJYPKBSeqUE
+Jugub/WN3UcKvv1mE++fzkFhEHS4t94HWB4rJyODg9glIgYMFMXarRhXMP4ZYm9h
+beWr1NlA02p8GsffMYMDLhpmncyqlz430DVuQZRFAgMBAAGjgZwwgZkwDgYDVR0P
 AQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMB
 AQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMB
-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
+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
 -----END CERTIFICATE-----
 -----END CERTIFICATE-----

+ 25 - 25
integration/fixtures/server.key.insecure

@@ -1,27 +1,27 @@
 -----BEGIN RSA PRIVATE KEY-----
 -----BEGIN RSA PRIVATE KEY-----
-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
+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
 -----END RSA PRIVATE KEY-----
 -----END RSA PRIVATE KEY-----

+ 24 - 0
integration/fixtures/server2.crt

@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEEzCCAvugAwIBAgIURpz1nfYWl/lT2yZitiL/LVW6SZMwDQYJKoZIhvcNAQEL
+BQAwbzEMMAoGA1UEBhMDVVNBMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH
+Ew1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKEwRldGNkMRYwFAYDVQQLEw1ldGNkIFNl
+Y3VyaXR5MQswCQYDVQQDEwJjYTAeFw0xNzA5MjkwNjU0MDBaFw0yNzA5MjcwNjU0
+MDBaMHkxDDAKBgNVBAYTA1VTQTETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UE
+BxMNU2FuIEZyYW5jaXNjbzENMAsGA1UEChMEZXRjZDEWMBQGA1UECxMNZXRjZCBT
+ZWN1cml0eTEVMBMGA1UEAxMMZXhhbXBsZTIuY29tMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAywxQ++cAL++7cHSACpohKAPMEUcYD/SyZnCAYkpIOJg4
+/4z2vsIhH8UMlrpP2j0OakDZorByljYNBV4JKJGWSJQlyONfWe3B1ElssoRkGdyX
+Qluiz+C9P/kGKOZztyz86O9jrjTUXqjkQJLR/JltCWlEvxB6CTSJ0vL99cUwuxJ3
+HstwZ1kBCrmWAvLa4bjjWaicsZYhsBBmhJp72t7O4d/8hNtBg/vX0ny4f2yj6URQ
+oTeR9tvTJ6w6lXDtLgEAdtlTubcvNfvzOuI/ZVR64Jb4YEdUUpFVE+oC2yj/irXS
+P8zSI7+XZIAEOnn8Gw5ddgjdblvH+cwhuCqUDEVuewIDAQABo4GcMIGZMA4GA1Ud
+DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0T
+AQH/BAIwADAdBgNVHQ4EFgQUbyM/QRgv8B8hkDVC91WA2sa/Q0AwHwYDVR0jBBgw
+FoAUF9biSbsHMqdrwCSM0fKMjoXZwwkwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/
+AAABMA0GCSqGSIb3DQEBCwUAA4IBAQBbMStTQJv8LiRlG4SE+RcZk+KvaNZAORoP
+rNHYnIUncUiNavwd1uDywgf5sDHIM7AkTmPAwUG1V5SbnfDAZZMTZWLv26nUam0L
+Yw3Wk4BqbMgPEh4AJgCuiOoJPEPjofmc+nVXdOEtKGAAWYiJWxL0WOnI+FESTVW4
+nQKB3/0+tRNebkdVWuxaiYZ2kuCffwE4zk2d9iWR2/pJmB2WB4xtOs8Dq3MzRqNN
+PHvxoiI6GTgEC/0Mb21XYF1sZ4CXlQF5wHMRGimTZvn3XuzziuepmOwcG5VZnYcD
+O/b2fZINj01SEet/y1P26OhR9CxLX6K1s0hQ6aYOzMK3Jd2ABL+7
+-----END CERTIFICATE-----

+ 27 - 0
integration/fixtures/server2.key.insecure

@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAywxQ++cAL++7cHSACpohKAPMEUcYD/SyZnCAYkpIOJg4/4z2
+vsIhH8UMlrpP2j0OakDZorByljYNBV4JKJGWSJQlyONfWe3B1ElssoRkGdyXQlui
+z+C9P/kGKOZztyz86O9jrjTUXqjkQJLR/JltCWlEvxB6CTSJ0vL99cUwuxJ3Hstw
+Z1kBCrmWAvLa4bjjWaicsZYhsBBmhJp72t7O4d/8hNtBg/vX0ny4f2yj6URQoTeR
+9tvTJ6w6lXDtLgEAdtlTubcvNfvzOuI/ZVR64Jb4YEdUUpFVE+oC2yj/irXSP8zS
+I7+XZIAEOnn8Gw5ddgjdblvH+cwhuCqUDEVuewIDAQABAoIBACPRi2O0j1LlfnJL
+Ct9T6y9s5A3UNclyyBnMFMnCAtWA/OUPz+M8ya0aDKt2OGnuRWG3CO1rJPuck1V0
+DjeK3zD0eWnjuklZ6MxzG2quch4hzMkW8zSql5f2bQDADn+svvy0ZigwB5qfPoyp
+mcNuqU50tHzkAjMngnylAundHEiTm8bGlWbGUNaNud0hC01fsIYhQFPD7naJUb5V
+eoduuBnLRLyY6VOkJT4En9z76MnK988wZeNjH861n0iqD/KDkoR2c+QSyJY01TYC
+SPHMOe24+GNNqsyfVSxazQX7lPf2frXWFqPdnH3w1FHnhtT51H/tr90gCLbgX9Vu
+N27SvSkCgYEA2Kbk4xBU0xoHDCJ9ADbEmA6VuG8jZWRSq3pKeP734f6t3v7sje9v
+jbR3+X609zoCvg/N8OnrVMqvTxD4pGCGhLyKqCqRAuM/QzgeJ5fOkXnlTXHJAP1X
+wMTEGZqDPMKW55wEgnvE1k5H2eZTGT3dgKHLSJibKgGGm2MS+rZ74XcCgYEA7+zr
+qc7ziUM2ow6b+b91kdLzZMHmYrF5CRp+lPDpILxqGrEZBOxFDoaVKwbsNCoipaFI
+6+wUDTbNny7KEZBwj/dQJVvC7xMhw1LIA23WbmVHcXxMdM6tud8PB1P8yRpI4rSB
+VLpgB8Gf23AIqpB4r3C+/fne3le62NIoNaUDPB0CgYBelC0juwNszNX6xCuRplcY
+knVl+I6ZOrykQ1SzkYshS48X5G3cYIRwdjJR5rCVpOuBkWC0JUooz/rMJ3qEN+dB
+lxVo6Hw5qH77l0oCutDgzTf/IQdAuVhPvRZmnv9fzQsXvRJy7Bk3/SB8zYHFaS6D
+cx5NaOGD6vqaZxvn+zYFbQKBgHL/J+V4IBqGcMWu1uvZ7Mw8RBTjKz3aupy2aj2R
+Suw54tFwWQGXDXJs50p8QvKtz3V73KvXt7Sts9i8YHYSuSEH9Q4y8TgN/3zTTLL4
+DnNTb+7hGPRTq8kPNPDaPKtXQeAHjIXD3wtYrvpKtJysKmxMqf6pqT0A57nM4SD1
+OpuxAoGAOh4CXj5Jn6dvMusHChV+yEMybA5Nfk/2ctwYTDEuMlnKXV8+PghimlwB
+Mrqjd99KtGFjeerkTzD+wqt2tPsnRvPrPYBwd3eM8k18dtonvk1nvxcReTRb6QSu
+yGGJAuVfMNE2gL8D0qFcgf+Ss3AyWMglS8fxZnSUSMsXvdawCmo=
+-----END RSA PRIVATE KEY-----

+ 18 - 0
pkg/transport/listener.go

@@ -22,6 +22,7 @@ import (
 	"crypto/x509"
 	"crypto/x509"
 	"crypto/x509/pkix"
 	"crypto/x509/pkix"
 	"encoding/pem"
 	"encoding/pem"
+	"errors"
 	"fmt"
 	"fmt"
 	"math/big"
 	"math/big"
 	"net"
 	"net"
@@ -76,6 +77,9 @@ type TLSInfo struct {
 	// parseFunc exists to simplify testing. Typically, parseFunc
 	// parseFunc exists to simplify testing. Typically, parseFunc
 	// should be left nil. In that case, tls.X509KeyPair will be used.
 	// should be left nil. In that case, tls.X509KeyPair will be used.
 	parseFunc func([]byte, []byte) (tls.Certificate, error)
 	parseFunc func([]byte, []byte) (tls.Certificate, error)
+
+	// AllowedCN is a CN which must be provided by a client.
+	AllowedCN string
 }
 }
 
 
 func (info TLSInfo) String() string {
 func (info TLSInfo) String() string {
@@ -174,6 +178,20 @@ func (info TLSInfo) baseConfig() (*tls.Config, error) {
 		MinVersion:   tls.VersionTLS12,
 		MinVersion:   tls.VersionTLS12,
 		ServerName:   info.ServerName,
 		ServerName:   info.ServerName,
 	}
 	}
+
+	if info.AllowedCN != "" {
+		cfg.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
+			for _, chains := range verifiedChains {
+				if len(chains) != 0 {
+					if info.AllowedCN == chains[0].Subject.CommonName {
+						return nil
+					}
+				}
+			}
+			return errors.New("CommonName authentication failed")
+		}
+	}
+
 	// this only reloads certs when there's a client request
 	// this only reloads certs when there's a client request
 	// TODO: support server-side refresh (e.g. inotify, SIGHUP), caching
 	// TODO: support server-side refresh (e.g. inotify, SIGHUP), caching
 	cfg.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
 	cfg.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {