Browse Source

Merge pull request #9570 from gyuho/tls

*: fix TLS reload when cert includes only IPs (no domain names in SAN field)
Gyuho Lee 7 years ago
parent
commit
ff6ff9d6e6

+ 4 - 1
CHANGELOG-3.2.md

@@ -11,7 +11,10 @@ See [code changes](https://github.com/coreos/etcd/compare/v3.2.18...v3.2.19) and
 
 
 ### Security, Authentication
 ### Security, Authentication
 
 
-- Fix [TLS reload](TODO) when [cert SAN field only contains IP addresses](https://github.com/coreos/etcd/issues/9541).
+- Fix [TLS reload](https://github.com/coreos/etcd/pull/9570) when [certificate SAN field only includes IP addresses but no domain names](https://github.com/coreos/etcd/issues/9541).
+  - In Go, server calls `(*tls.Config).GetCertificate` for TLS reload if and only if server's `(*tls.Config).Certificates` field is not empty, or `(*tls.ClientHelloInfo).ServerName` is not empty with a valid SNI from the client. Previously, etcd always populates `(*tls.Config).Certificates` on the initial client TLS handshake, as non-empty. Thus, client was always expected to supply a matching SNI in order to pass the TLS verification and to trigger `(*tls.Config).GetCertificate` to reload TLS assets.
+  - However, a certificate whose SAN field does [not include any domain names but only IP addresses](https://github.com/coreos/etcd/issues/9541) would request `*tls.ClientHelloInfo` with an empty `ServerName` field, thus failing to trigger the TLS reload on initial TLS handshake; this becomes a problem when expired certificates need to be replaced online.
+  - Now, `(*tls.Config).Certificates` is created empty on initial TLS client handshake, first to trigger `(*tls.Config).GetCertificate`, and then to populate rest of the certificates on every new TLS connection, even when client SNI is empty (e.g. cert only includes IPs).
 
 
 
 
 ## [v3.2.18](https://github.com/coreos/etcd/releases/tag/v3.2.18) (2018-03-29)
 ## [v3.2.18](https://github.com/coreos/etcd/releases/tag/v3.2.18) (2018-03-29)

+ 4 - 1
CHANGELOG-3.3.md

@@ -11,7 +11,10 @@ See [code changes](https://github.com/coreos/etcd/compare/v3.3.3...v3.3.4) and [
 
 
 ### Security, Authentication
 ### Security, Authentication
 
 
-- Fix [TLS reload](TODO) when [cert SAN field only contains IP addresses](https://github.com/coreos/etcd/issues/9541).
+- Fix [TLS reload](https://github.com/coreos/etcd/pull/9570) when [certificate SAN field only includes IP addresses but no domain names](https://github.com/coreos/etcd/issues/9541).
+  - In Go, server calls `(*tls.Config).GetCertificate` for TLS reload if and only if server's `(*tls.Config).Certificates` field is not empty, or `(*tls.ClientHelloInfo).ServerName` is not empty with a valid SNI from the client. Previously, etcd always populates `(*tls.Config).Certificates` on the initial client TLS handshake, as non-empty. Thus, client was always expected to supply a matching SNI in order to pass the TLS verification and to trigger `(*tls.Config).GetCertificate` to reload TLS assets.
+  - However, a certificate whose SAN field does [not include any domain names but only IP addresses](https://github.com/coreos/etcd/issues/9541) would request `*tls.ClientHelloInfo` with an empty `ServerName` field, thus failing to trigger the TLS reload on initial TLS handshake; this becomes a problem when expired certificates need to be replaced online.
+  - Now, `(*tls.Config).Certificates` is created empty on initial TLS client handshake, first to trigger `(*tls.Config).GetCertificate`, and then to populate rest of the certificates on every new TLS connection, even when client SNI is empty (e.g. cert only includes IPs).
 
 
 
 
 ## [v3.3.3](https://github.com/coreos/etcd/releases/tag/v3.3.3) (2018-03-29)
 ## [v3.3.3](https://github.com/coreos/etcd/releases/tag/v3.3.3) (2018-03-29)

+ 4 - 1
CHANGELOG-3.4.md

@@ -103,7 +103,10 @@ See [security doc](https://github.com/coreos/etcd/blob/master/Documentation/op-g
 - Support [`ttl` field for `etcd` Authentication JWT token](https://github.com/coreos/etcd/pull/8302).
 - Support [`ttl` field for `etcd` Authentication JWT token](https://github.com/coreos/etcd/pull/8302).
   - e.g. `etcd --auth-token jwt,pub-key=<pub key path>,priv-key=<priv key path>,sign-method=<sign method>,ttl=5m`.
   - e.g. `etcd --auth-token jwt,pub-key=<pub key path>,priv-key=<priv key path>,sign-method=<sign method>,ttl=5m`.
 - Allow empty token provider in [`etcdserver.ServerConfig.AuthToken`](https://github.com/coreos/etcd/pull/9369).
 - Allow empty token provider in [`etcdserver.ServerConfig.AuthToken`](https://github.com/coreos/etcd/pull/9369).
-- Fix [TLS reload](TODO) when [cert SAN field only contains IP addresses](https://github.com/coreos/etcd/issues/9541).
+- Fix [TLS reload](https://github.com/coreos/etcd/pull/9570) when [certificate SAN field only includes IP addresses but no domain names](https://github.com/coreos/etcd/issues/9541).
+  - In Go, server calls `(*tls.Config).GetCertificate` for TLS reload if and only if server's `(*tls.Config).Certificates` field is not empty, or `(*tls.ClientHelloInfo).ServerName` is not empty with a valid SNI from the client. Previously, etcd always populates `(*tls.Config).Certificates` on the initial client TLS handshake, as non-empty. Thus, client was always expected to supply a matching SNI in order to pass the TLS verification and to trigger `(*tls.Config).GetCertificate` to reload TLS assets.
+  - However, a certificate whose SAN field does [not include any domain names but only IP addresses](https://github.com/coreos/etcd/issues/9541) would request `*tls.ClientHelloInfo` with an empty `ServerName` field, thus failing to trigger the TLS reload on initial TLS handshake; this becomes a problem when expired certificates need to be replaced online.
+  - Now, `(*tls.Config).Certificates` is created empty on initial TLS client handshake, first to trigger `(*tls.Config).GetCertificate`, and then to populate rest of the certificates on every new TLS connection, even when client SNI is empty (e.g. cert only includes IPs).
 
 
 ### Added: `etcd`
 ### Added: `etcd`
 
 

+ 16 - 0
Documentation/op-guide/security.md

@@ -321,6 +321,22 @@ I | embed: serving client requests on 127.0.0.1:22379
 I | embed: serving client requests on 127.0.0.1:2379
 I | embed: serving client requests on 127.0.0.1:2379
 ```
 ```
 
 
+[v3.2.19](https://github.com/coreos/etcd/blob/master/CHANGELOG-3.2.md) and [v3.3.4](https://github.com/coreos/etcd/blob/master/CHANGELOG-3.3.md) fixes TLS reload when [certificate SAN field only includes IP addresses but no domain names](https://github.com/coreos/etcd/issues/9541). For example, a member is set up with CSRs (with `cfssl`) as below:
+
+```json
+{
+  "CN": "etcd.local",
+  "hosts": [
+    "127.0.0.1"
+  ],
+```
+
+In Go, server calls `(*tls.Config).GetCertificate` for TLS reload if and only if server's `(*tls.Config).Certificates` field is not empty, or `(*tls.ClientHelloInfo).ServerName` is not empty with a valid SNI from the client. Previously, etcd always populates `(*tls.Config).Certificates` on the initial client TLS handshake, as non-empty. Thus, client was always expected to supply a matching SNI in order to pass the TLS verification and to trigger `(*tls.Config).GetCertificate` to reload TLS assets.
+
+However, a certificate whose SAN field does [not include any domain names but only IP addresses](https://github.com/coreos/etcd/issues/9541) would request `*tls.ClientHelloInfo` with an empty `ServerName` field, thus failing to trigger the TLS reload on initial TLS handshake; this becomes a problem when expired certificates need to be replaced online.
+
+Now, `(*tls.Config).Certificates` is created empty on initial TLS client handshake, first to trigger `(*tls.Config).GetCertificate`, and then to populate rest of the certificates on every new TLS connection, even when client SNI is empty (e.g. cert only includes IPs).
+
 ## Notes for Host Whitelist
 ## Notes for Host Whitelist
 
 
 `etcd --host-whitelist` flag specifies acceptable hostnames from HTTP client requests. Client origin policy protects against ["DNS Rebinding"](https://en.wikipedia.org/wiki/DNS_rebinding) attacks to insecure etcd servers. That is, any website can simply create an authorized DNS name, and direct DNS to `"localhost"` (or any other address). Then, all HTTP endpoints of etcd server listening on `"localhost"` becomes accessible, thus vulnerable to DNS rebinding attacks. See [CVE-2018-5702](https://bugs.chromium.org/p/project-zero/issues/detail?id=1447#c2) for more detail.
 `etcd --host-whitelist` flag specifies acceptable hostnames from HTTP client requests. Client origin policy protects against ["DNS Rebinding"](https://en.wikipedia.org/wiki/DNS_rebinding) attacks to insecure etcd servers. That is, any website can simply create an authorized DNS name, and direct DNS to `"localhost"` (or any other address). Then, all HTTP endpoints of etcd server listening on `"localhost"` becomes accessible, thus vulnerable to DNS rebinding attacks. See [CVE-2018-5702](https://bugs.chromium.org/p/project-zero/issues/detail?id=1447#c2) for more detail.

+ 61 - 1
integration/cluster.go

@@ -46,6 +46,7 @@ import (
 	"github.com/coreos/etcd/etcdserver/api/v3rpc"
 	"github.com/coreos/etcd/etcdserver/api/v3rpc"
 	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
 	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
 	"github.com/coreos/etcd/pkg/testutil"
 	"github.com/coreos/etcd/pkg/testutil"
+	"github.com/coreos/etcd/pkg/tlsutil"
 	"github.com/coreos/etcd/pkg/transport"
 	"github.com/coreos/etcd/pkg/transport"
 	"github.com/coreos/etcd/pkg/types"
 	"github.com/coreos/etcd/pkg/types"
 	"github.com/coreos/etcd/rafthttp"
 	"github.com/coreos/etcd/rafthttp"
@@ -83,6 +84,13 @@ var (
 		ClientCertAuth: true,
 		ClientCertAuth: true,
 	}
 	}
 
 
+	testTLSInfoIP = transport.TLSInfo{
+		KeyFile:        "./fixtures/server-ip.key.insecure",
+		CertFile:       "./fixtures/server-ip.crt",
+		TrustedCAFile:  "./fixtures/ca.crt",
+		ClientCertAuth: true,
+	}
+
 	testTLSInfoExpired = transport.TLSInfo{
 	testTLSInfoExpired = transport.TLSInfo{
 		KeyFile:        "./fixtures-expired/server.key.insecure",
 		KeyFile:        "./fixtures-expired/server.key.insecure",
 		CertFile:       "./fixtures-expired/server.crt",
 		CertFile:       "./fixtures-expired/server.crt",
@@ -90,6 +98,13 @@ var (
 		ClientCertAuth: true,
 		ClientCertAuth: true,
 	}
 	}
 
 
+	testTLSInfoExpiredIP = transport.TLSInfo{
+		KeyFile:        "./fixtures-expired/server-ip.key.insecure",
+		CertFile:       "./fixtures-expired/server-ip.crt",
+		TrustedCAFile:  "./fixtures-expired/ca.crt",
+		ClientCertAuth: true,
+	}
+
 	plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "integration")
 	plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "integration")
 )
 )
 
 
@@ -110,6 +125,9 @@ type ClusterConfig struct {
 
 
 	ClientMaxCallSendMsgSize int
 	ClientMaxCallSendMsgSize int
 	ClientMaxCallRecvMsgSize int
 	ClientMaxCallRecvMsgSize int
+
+	// UseIP is true to use only IP for gRPC requests.
+	UseIP bool
 }
 }
 
 
 type cluster struct {
 type cluster struct {
@@ -248,6 +266,7 @@ func (c *cluster) mustNewMember(t *testing.T) *member {
 			grpcKeepAliveTimeout:     c.cfg.GRPCKeepAliveTimeout,
 			grpcKeepAliveTimeout:     c.cfg.GRPCKeepAliveTimeout,
 			clientMaxCallSendMsgSize: c.cfg.ClientMaxCallSendMsgSize,
 			clientMaxCallSendMsgSize: c.cfg.ClientMaxCallSendMsgSize,
 			clientMaxCallRecvMsgSize: c.cfg.ClientMaxCallRecvMsgSize,
 			clientMaxCallRecvMsgSize: c.cfg.ClientMaxCallRecvMsgSize,
+			useIP: c.cfg.UseIP,
 		})
 		})
 	m.DiscoveryURL = c.cfg.DiscoveryURL
 	m.DiscoveryURL = c.cfg.DiscoveryURL
 	if c.cfg.UseGRPC {
 	if c.cfg.UseGRPC {
@@ -511,6 +530,7 @@ type member struct {
 	keepDataDirTerminate     bool
 	keepDataDirTerminate     bool
 	clientMaxCallSendMsgSize int
 	clientMaxCallSendMsgSize int
 	clientMaxCallRecvMsgSize int
 	clientMaxCallRecvMsgSize int
+	useIP                    bool
 }
 }
 
 
 func (m *member) GRPCAddr() string { return m.grpcAddr }
 func (m *member) GRPCAddr() string { return m.grpcAddr }
@@ -527,6 +547,7 @@ type memberConfig struct {
 	grpcKeepAliveTimeout     time.Duration
 	grpcKeepAliveTimeout     time.Duration
 	clientMaxCallSendMsgSize int
 	clientMaxCallSendMsgSize int
 	clientMaxCallRecvMsgSize int
 	clientMaxCallRecvMsgSize int
+	useIP                    bool
 }
 }
 
 
 // mustNewMember return an inited member with the given name. If peerTLS is
 // mustNewMember return an inited member with the given name. If peerTLS is
@@ -600,6 +621,7 @@ func mustNewMember(t *testing.T, mcfg memberConfig) *member {
 	}
 	}
 	m.clientMaxCallSendMsgSize = mcfg.clientMaxCallSendMsgSize
 	m.clientMaxCallSendMsgSize = mcfg.clientMaxCallSendMsgSize
 	m.clientMaxCallRecvMsgSize = mcfg.clientMaxCallRecvMsgSize
 	m.clientMaxCallRecvMsgSize = mcfg.clientMaxCallRecvMsgSize
+	m.useIP = mcfg.useIP
 
 
 	m.InitialCorruptCheck = true
 	m.InitialCorruptCheck = true
 
 
@@ -610,6 +632,9 @@ func mustNewMember(t *testing.T, mcfg memberConfig) *member {
 func (m *member) listenGRPC() error {
 func (m *member) listenGRPC() error {
 	// prefix with localhost so cert has right domain
 	// prefix with localhost so cert has right domain
 	m.grpcAddr = "localhost:" + m.Name
 	m.grpcAddr = "localhost:" + m.Name
+	if m.useIP { // for IP-only sTLS certs
+		m.grpcAddr = "127.0.0.1:" + m.Name
+	}
 	l, err := transport.NewUnixListener(m.grpcAddr)
 	l, err := transport.NewUnixListener(m.grpcAddr)
 	if err != nil {
 	if err != nil {
 		return fmt.Errorf("listen failed on grpc socket %s (%v)", m.grpcAddr, err)
 		return fmt.Errorf("listen failed on grpc socket %s (%v)", m.grpcAddr, err)
@@ -785,10 +810,45 @@ func (m *member) Launch() error {
 		if m.ClientTLSInfo == nil {
 		if m.ClientTLSInfo == nil {
 			hs.Start()
 			hs.Start()
 		} else {
 		} else {
-			hs.TLS, err = m.ClientTLSInfo.ServerConfig()
+			info := m.ClientTLSInfo
+			hs.TLS, err = info.ServerConfig()
 			if err != nil {
 			if err != nil {
 				return err
 				return err
 			}
 			}
+
+			// baseConfig is called on initial TLS handshake start.
+			//
+			// Previously,
+			// 1. Server has non-empty (*tls.Config).Certificates on client hello
+			// 2. Server calls (*tls.Config).GetCertificate iff:
+			//    - Server's (*tls.Config).Certificates is not empty, or
+			//    - Client supplies SNI; non-empty (*tls.ClientHelloInfo).ServerName
+			//
+			// When (*tls.Config).Certificates is always populated on initial handshake,
+			// client is expected to provide a valid matching SNI to pass the TLS
+			// verification, thus trigger server (*tls.Config).GetCertificate to reload
+			// TLS assets. However, a cert whose SAN field does not include domain names
+			// but only IP addresses, has empty (*tls.ClientHelloInfo).ServerName, thus
+			// it was never able to trigger TLS reload on initial handshake; first
+			// ceritifcate object was being used, never being updated.
+			//
+			// Now, (*tls.Config).Certificates is created empty on initial TLS client
+			// handshake, in order to trigger (*tls.Config).GetCertificate and populate
+			// rest of the certificates on every new TLS connection, even when client
+			// SNI is empty (e.g. cert only includes IPs).
+			//
+			// This introduces another problem with "httptest.Server":
+			// when server initial certificates are empty, certificates
+			// are overwritten by Go's internal test certs, which have
+			// different SAN fields (e.g. example.com). To work around,
+			// re-overwrite (*tls.Config).Certificates before starting
+			// test server.
+			tlsCert, err := tlsutil.NewCert(info.CertFile, info.KeyFile, nil)
+			if err != nil {
+				return err
+			}
+			hs.TLS.Certificates = []tls.Certificate{*tlsCert}
+
 			hs.StartTLS()
 			hs.StartTLS()
 		}
 		}
 		closer := func() {
 		closer := func() {

+ 16 - 16
integration/fixtures-expired/ca.crt

@@ -1,23 +1,23 @@
 -----BEGIN CERTIFICATE-----
 -----BEGIN CERTIFICATE-----
-MIID0jCCArqgAwIBAgIUbY6SSy/rF2TQzWsH4GxG+h+Pvw8wDQYJKoZIhvcNAQEL
+MIID0jCCArqgAwIBAgIUEKEIOO1O97Bz4car+7SHDxT5tB4wDQYJKoZIhvcNAQEL
 BQAwbzEMMAoGA1UEBhMDVVNBMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH
 BQAwbzEMMAoGA1UEBhMDVVNBMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH
 Ew1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKEwRldGNkMRYwFAYDVQQLEw1ldGNkIFNl
 Ew1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKEwRldGNkMRYwFAYDVQQLEw1ldGNkIFNl
-Y3VyaXR5MQswCQYDVQQDEwJjYTAeFw0xODA0MDgxNzUzMDBaFw0yODA0MDUxNzUz
+Y3VyaXR5MQswCQYDVQQDEwJjYTAeFw0wMDA0MTMxODU1MDBaFw0xMDA0MTExODU1
 MDBaMG8xDDAKBgNVBAYTA1VTQTETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UE
 MDBaMG8xDDAKBgNVBAYTA1VTQTETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UE
 BxMNU2FuIEZyYW5jaXNjbzENMAsGA1UEChMEZXRjZDEWMBQGA1UECxMNZXRjZCBT
 BxMNU2FuIEZyYW5jaXNjbzENMAsGA1UEChMEZXRjZDEWMBQGA1UECxMNZXRjZCBT
 ZWN1cml0eTELMAkGA1UEAxMCY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
 ZWN1cml0eTELMAkGA1UEAxMCY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
-AoIBAQCqhEOeNSLK5CcfvZgHFHPJzRWeDc/fAQ3U2GSF1+KEslOA0mmHiL1paloS
-CbuwzoY/EGPCudFxIwFwjl2BAxbMdaCAKCxPwMHfn/38I45GgJFODjcOP0AX9i3O
-z2jsAGm02HNicmF24TuQgij8lvhhKjNsy2Lrb8/i6NmX8AKZl9smkRRd5HpUz9DD
-HelH2CXYCjbGXdpCyjN2PwfGSoCsAV8NDwbe0CAg6+dZCQrbqt2PJE2uRBoLgp3p
-AsVdPiFL1igOimgQRShGvMEVLkA7cmB3fALZy1WTGGj4h76HtEz8nywN7PmoWQJv
-AZFM168XPQ35S9+1CROtWUoM7dlhAgMBAAGjZjBkMA4GA1UdDwEB/wQEAwIBBjAS
-BgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQWBBSLaEU8nqrYzNEcmi0oZKd1AAFK
-gTAfBgNVHSMEGDAWgBSLaEU8nqrYzNEcmi0oZKd1AAFKgTANBgkqhkiG9w0BAQsF
-AAOCAQEApPHGwdcMRWMk+RS1NVb3yCPdf2Tx8pPYAJpLY46OPenGnFt6+wJs6Nhq
-bj9zmEEqyn1WLXtuel+X4E4BEofkTEAM+06UT7SGgEF7zMY+zQjfPqD52jLhS11I
-hp3u/hDR5c8r6RmvuH1TiPK5twxmV1w6LRGQcGJtw1PdTVfgHM+1s7kQ+Ineo4kK
-8m1JR44B3GHyw+o0jsf5NqnmQnW6aMACQXiX93fnelkPOsKez/oxiy/WK5dDMrzH
-JgNonK+bZRpef15XK3EOhmHp8YrY0CEq4MFsxxmkMZT0OnvIMEi9SkPV1cFq2N7r
-uTB9aMzzD/1u+3+IpHCrkb0QICj3YQ==
+AoIBAQDFeNJ9r2TFcJp9UHS42QN2NN1A96LQXxn/BirHzXdeTk6YEe0eloA91SJT
+BAae7aGdPMkpMyAAXheGPGHAbSde5dONYx2QE4nqWRl79v6kDbX6EmqwpzTOGD/T
+UfLXe65g6w6kaXcNZWiMdqfkUImke/WWM1qunsCKoGOXF8Jg1DLy7NSjqT2Kg1UP
+evJ5GOrWmIj5rEnEvW0ohR7mKV23xl5okVjrlzCi+arWDdl5RzE0I9x7vKNE0TKX
+NNHG9hMSJQ/ipXXXyMcahqGZXtkGvOpwpO3lpsGjo3WIUZMQW2FA3xR0nBC6Lt+0
+d+7IXOy/LbzXpkcL8Ws5BZuLDSKLAgMBAAGjZjBkMA4GA1UdDwEB/wQEAwIBBjAS
+BgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQWBBT5Z7kwwTNntO1UsuMdUv/Yq3Ad
+cDAfBgNVHSMEGDAWgBT5Z7kwwTNntO1UsuMdUv/Yq3AdcDANBgkqhkiG9w0BAQsF
+AAOCAQEAkFF/fIVlcgj1uRL36wP4DgkOMCpU5+vwlDdHihDzRJHZqik+3+oNz7DD
+pRIURHMeeF+Wk5/GRQ/oGzKYotNLLzqCOggnLCxET6Hkb07vfve91HmYVOYix5pU
+GPW8+M3XyFTL3+2BnPpqPpJWpJ28g+N3eQjAG8rIbjXESdxrpJFKY22nMbtyS1rH
+dyzf3OO4S7LZiRQx0nuD9SZtX2vj5DyN8Am/zieSYm+GCtJsvIiDoB+Uhndnxxt0
+FA0/89vGJ1gCo+Z6clzqBIbesRUBnLvPbUdpxhFAtjUKZhQv05IrE81/GP7F7kEr
+oODS2+D5WC6mKDO4v2k736OTw6HwOQ==
 -----END CERTIFICATE-----
 -----END CERTIFICATE-----

+ 11 - 0
integration/fixtures-expired/gencerts.sh

@@ -24,8 +24,19 @@ cfssl gencert \
   ./server-ca-csr.json | cfssljson --bare ./server
   ./server-ca-csr.json | cfssljson --bare ./server
 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 IP: 127.0.0.1, CN: example.com certificates
+cfssl gencert \
+  --ca ./ca.crt \
+  --ca-key ./ca-key.pem \
+  --config ./gencert.json \
+  ./server-ca-csr-ip.json | cfssljson --bare ./server-ip
+mv server-ip.pem server-ip.crt
+mv server-ip-key.pem server-ip.key.insecure
+
 if which openssl >/dev/null; then
 if which openssl >/dev/null; then
   openssl x509 -in ./server.crt -text -noout
   openssl x509 -in ./server.crt -text -noout
+  openssl x509 -in ./server-ip.crt -text -noout
 fi
 fi
 
 
 rm -f *.csr *.pem *.stderr *.txt
 rm -f *.csr *.pem *.stderr *.txt

+ 19 - 0
integration/fixtures-expired/server-ca-csr-ip.json

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

+ 24 - 0
integration/fixtures-expired/server-ip.crt

@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEBzCCAu+gAwIBAgIUOc4vrxQ6OeHoGslhL7daP1Ye8ZYwDQYJKoZIhvcNAQEL
+BQAwbzEMMAoGA1UEBhMDVVNBMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH
+Ew1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKEwRldGNkMRYwFAYDVQQLEw1ldGNkIFNl
+Y3VyaXR5MQswCQYDVQQDEwJjYTAeFw0wMDA0MTMxODU1MDBaFw0wMDA0MTMxOTU1
+MDBaMHgxDDAKBgNVBAYTA1VTQTETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UE
+BxMNU2FuIEZyYW5jaXNjbzENMAsGA1UEChMEZXRjZDEWMBQGA1UECxMNZXRjZCBT
+ZWN1cml0eTEUMBIGA1UEAxMLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQDLUZuwXwiky2VvujM0EOP9LL85sx1dKLc/16hOl6qYRPOg
+PH7zsmXMVndsD2Fi9NDbhV9rVHfVNkCyZO/D81u52UEyr2uSFHOfIqLkFGKvcxhO
+FtOLA7wTjzHiYO1pFgqYBWzSfIyreYYo13tCYxHUlhn3ibqvCz9fimGsQmswhUiP
+yaC4C8iBICWNd4vrXHhtKb5pHHzUDFHkOxKF6VS9f7InKBy2yTr8ekgoEYyE3gtp
+ncoVbVlwxehChbZThFi0xsQc/kG/eoyGznKo9RUlUW+h3SEJR3bYizYP76ZwWXus
+nP5vgLmZ0wIi/689uTQbEAK438rK3xTSziPv6B51AgMBAAGjgZEwgY4wDgYDVR0P
+AQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMB
+Af8EAjAAMB0GA1UdDgQWBBR8bgC5SVrIrOAkjED8FB6OThk0IjAfBgNVHSMEGDAW
+gBT5Z7kwwTNntO1UsuMdUv/Yq3AdcDAPBgNVHREECDAGhwR/AAABMA0GCSqGSIb3
+DQEBCwUAA4IBAQDEV4Ec8TpDXvFTJYXrpME5KnKvtq1fEv100jc88cmlGb/rygge
+MtisA1rYSaSEPMF0j7HoMtTwP90yrJCBTr7/vziAXCZU2H6bg24exRzqtMDpDhXg
+mvqkqvMVFem8ANIF3a+qXPY/pzjh4xrPuOw10TfG0bE576lAY/KbnY3UvXo6QL54
+AMyimFhq8e9dJ7JnO3eaYmJv6oSjKjqNYSU+01UfxEJGNbx1IELMDlnVKX0Zmn9p
+YbUS3nrowKoVXpuca9KzS1pINgqVsztF5XJxzqlcDwERR/QcTKwUgQ0y0BBRqiGg
+WdtbyamFufvF8GPsNJ0KRHXSIRRXF7hbgiXd
+-----END CERTIFICATE-----

+ 27 - 0
integration/fixtures-expired/server-ip.key.insecure

@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAy1GbsF8IpMtlb7ozNBDj/Sy/ObMdXSi3P9eoTpeqmETzoDx+
+87JlzFZ3bA9hYvTQ24Vfa1R31TZAsmTvw/NbudlBMq9rkhRznyKi5BRir3MYThbT
+iwO8E48x4mDtaRYKmAVs0nyMq3mGKNd7QmMR1JYZ94m6rws/X4phrEJrMIVIj8mg
+uAvIgSAljXeL61x4bSm+aRx81AxR5DsShelUvX+yJygctsk6/HpIKBGMhN4LaZ3K
+FW1ZcMXoQoW2U4RYtMbEHP5Bv3qMhs5yqPUVJVFvod0hCUd22Is2D++mcFl7rJz+
+b4C5mdMCIv+vPbk0GxACuN/Kyt8U0s4j7+gedQIDAQABAoIBAAjHl1+AWxEyr0ip
+07g12oJ+QiutrmDtdyxMlbn/FqDIqXSL6DeBxp+SREnoSB5L0BEKq1opJZuRYi3R
+6gCeK6HU3dngdVazh2KhzkLnFnPZFn2Ywr3IBYEat968rMPS7dYutcpJEpH9B2wQ
+EgSF3qk9ahWkXulcJPptMVaM77ACnZk6yYsPDPqjX/zsCXVga59QL0x1n2ai50er
+W7kthCj69zZP6crbnjyCUDjNdpDio7xurvvxs0k1KWmcN9QjdOyFXDFgTUnphIFX
+pEyVhu+LmLzFKc1WVQ4sIAt6ot9kpWt+cdaBVIWl2yCmqF4nbJ38DDG6wLXaZQd1
+DgEL0YECgYEAzt7QukPfjgw5CKZguQVVn0LGYdHw47qHiusjABzYH4mokMHqR/r5
+LIIRQ4JjB/vpxavj6B0e73tcfwbSzLSwsRI9/6Z27UVpXnpU5LY7+46d+ZXsQorE
+8jeUX6ZQi65ujpFFKkftKlmq67XJtmSh2T+3dMqRXmFWVZThllBJcGUCgYEA+5rd
+gvZhaj9Rng1CwK3FoI/mp0BtSL+TE8/JbV0yA5X6NhXlts/ysafFZsj9RkR1NhXL
+ql8Bl9RxrV6mTIz6/76NC39ZUQUe5FZGv64rqjoFwOnv6ap1/8ntDFy29DgZ5Dqn
+flAtbbEyVG+VCwwhDgUT+FTNNS1eg18GStr6LNECgYASgo1anUgbhax0wa5V38xR
+e8AUcJyFQ+Ns4q03DV2pNMAIc9Fqr2IsQVcaG0iRJlE8hqzV0AU8mGUmWI30Exbc
+QS2a+mIZyOQst/VwoX2sfI5WDrwdGB2XLrHv/Qmn9euehhESP21RJMTOYm2yDD8P
+GUxo/tcTAtKexbuJn5VyoQKBgB7OH0DhmZvAlOWdCgc9P20hMURZBwhZLFDIqAjT
+2EPIIRJuK+nuG/DUcb7b7OalixRMJtt9Nly4jhKD/ChzOmgFlI9L0EuzLM0YIyFk
+2cPFxt6Pxef+DuR6fKN+1oegNstSwx8cAfPkNh1QbBcmLQXiaUeGWnmgTGoZQFP5
+65eBAoGAfV98Mwka+VJ3hYNPL2ZHUXHnXw9Hnf5NnaGfgz7/Ucw3H88HsrIDIZgO
+NKSM3NVRIrweAx8/gDIrGqjXkvrwuCqXXYeS23gRteigUpoQrtGjBxIwtalT8K2O
+jI4vqz8SsNALtR8nehmBPzTj+t+rF5b1cMfyreHccoAa+0TbPac=
+-----END RSA PRIVATE KEY-----

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

@@ -1,24 +1,24 @@
 -----BEGIN CERTIFICATE-----
 -----BEGIN CERTIFICATE-----
-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
+MIIEEjCCAvqgAwIBAgIULscJmimDEFNvw3oQ5paqHc+V/w4wDQYJKoZIhvcNAQEL
 BQAwbzEMMAoGA1UEBhMDVVNBMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH
 BQAwbzEMMAoGA1UEBhMDVVNBMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH
 Ew1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKEwRldGNkMRYwFAYDVQQLEw1ldGNkIFNl
 Ew1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKEwRldGNkMRYwFAYDVQQLEw1ldGNkIFNl
-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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-expired/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-----

+ 16 - 16
integration/fixtures/ca.crt

@@ -1,23 +1,23 @@
 -----BEGIN CERTIFICATE-----
 -----BEGIN CERTIFICATE-----
-MIID0jCCArqgAwIBAgIUGMTka1d/PO3J5ui12qLiCKjR1rMwDQYJKoZIhvcNAQEL
+MIID0jCCArqgAwIBAgIUOJwZrjY0viD0A34jOYtZb/aNy+YwDQYJKoZIhvcNAQEL
 BQAwbzEMMAoGA1UEBhMDVVNBMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH
 BQAwbzEMMAoGA1UEBhMDVVNBMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH
 Ew1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKEwRldGNkMRYwFAYDVQQLEw1ldGNkIFNl
 Ew1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKEwRldGNkMRYwFAYDVQQLEw1ldGNkIFNl
-Y3VyaXR5MQswCQYDVQQDEwJjYTAeFw0xNzEwMDUyMTU5MDBaFw0yNzEwMDMyMTU5
+Y3VyaXR5MQswCQYDVQQDEwJjYTAeFw0xODA0MTMxODUzMDBaFw0yODA0MTAxODUz
 MDBaMG8xDDAKBgNVBAYTA1VTQTETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UE
 MDBaMG8xDDAKBgNVBAYTA1VTQTETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UE
 BxMNU2FuIEZyYW5jaXNjbzENMAsGA1UEChMEZXRjZDEWMBQGA1UECxMNZXRjZCBT
 BxMNU2FuIEZyYW5jaXNjbzENMAsGA1UEChMEZXRjZDEWMBQGA1UECxMNZXRjZCBT
 ZWN1cml0eTELMAkGA1UEAxMCY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
 ZWN1cml0eTELMAkGA1UEAxMCY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
-AoIBAQC/oSHQqlc05uZYMHHxkkF/eTM4uh7Z/6TSjChMfnNk+5rZJzwSkLeL47Am
-kmcGnB9xo4tKkiDjq6MbHwgK2YpgdF5rRSC89BYBWPVvSMxMWV4Pvx/q3mdUjh7N
-tb9udJxG6c3rgI+2t2zcx1+qFGeKw0JSHKpcI6UKNm7E/xY0lqJ0ptHruBgFQaqy
-VdqVa5QkyF2imnFEdgakO2EuQR3vVAr5sM552LLnngNsfsxLStxXWDJZ/+34k2ON
-jJy5KEQ1KgYmVwi8843yQRDkvAjZ4Z1LzbcQQ83/6oT3kAfsOjy8bdsxMZBWSA53
-W9LuKUOk6WLRY0S3vUjzdw8To15RAgMBAAGjZjBkMA4GA1UdDwEB/wQEAwIBBjAS
-BgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQWBBSt4lqZZ20BpzYG8GSym10Intbr
-EzAfBgNVHSMEGDAWgBSt4lqZZ20BpzYG8GSym10IntbrEzANBgkqhkiG9w0BAQsF
-AAOCAQEAA6TqqLkPdI6zuda71LL68myXbN2qdxzs7HK8jkGPM2cU6Ii0G66TvesM
-gf1k3VddbvF8mPCyhdLYRArQeDLxKDLq/efosOj/NiLtepXea6Ib7XEo2AKCe21S
-SpBAZ2Szx8mGa7IY3ISfxkY0PpGhe2G0Rf0kOX5SYhQ/4TdAoe2pr8jFX6b7Kbdl
-yBxq9nDYjSCA7fC5Yr3Pup7Uu9fh1TJr+62DMBeeQN1XFZ0hEdu5sk4jkNq3ijC7
-/vpDyzRduUGpbp8Jy4HzoyWrCmp+KEznEWNmXb/HoPHKBlAz0ovjzU+jnFYi9tVN
-WODbdeGuXqBBmdAGaWBEowVP8ZhdQg==
+AoIBAQCu5s9vCEwShwELpyEXbP5A69ENrkqe3qU1AR3DzWY4gFkkec+QnCdid16Z
+Ayp0Xg1t1GOxTMMGjadyJampzhB/l3oCiIQyQNOy0bCJvn02lBwDFIXDzvdMUfob
+OaTYGwG9vQD6b+ohwzWneF6Ov7UrqAGvRSmTP2Id5vzqGA1+nRA2J4+WOH4ouwZD
+1d53fFk/eBkuHyZO/SEPWH5Ch2J9bZ7jGiTpuroqjbkJXhBfHheEV2NBxIWGWRvh
+JXazBbHwogrR1Op0NkeXPamm9Y3GEL0z/e6hhTGSLFKDioy6P2QrF7C890ru0cX8
+QfLFXj7nBMB+mW6/b4dhywnFwjdpAgMBAAGjZjBkMA4GA1UdDwEB/wQEAwIBBjAS
+BgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQWBBQdqL0i7KF7tmBTUvtR2FpL+Csm
+2zAfBgNVHSMEGDAWgBQdqL0i7KF7tmBTUvtR2FpL+Csm2zANBgkqhkiG9w0BAQsF
+AAOCAQEAjSy+ijzcO3Hu809GvmVl/+aRL/e6iKZ8WC3kpY42ZdyAbhCSYnWmUdHX
+smBVOvjZmQnEtXrrOrzBcbTFdnMzswgoPwtYPKqAqP0vxARbmnbDDuzFstaKSIYm
+T2Tw6r30ivbG7dIyitewCGmTXcdgMLmYgx+zOOj8BmbK1o1jW+qFudggC95qkkiq
+ismo8Ao1/Uw6bDbg/0l30V16bfI7jvPxK6+S2FUlB+ggfQtd2dfKVXNUtfBG8wf0
+1BQdiLPAQGDiprmEpAoUyRfNkMPSZD+WeBYkb0Ji2MyzJ3pUtBPwb57UcbIyp9S5
+MSqy3ciMv+FyBaX6EB2mP8GMgW5WaQ==
 -----END CERTIFICATE-----
 -----END CERTIFICATE-----

+ 9 - 0
integration/fixtures/gencerts.sh

@@ -25,6 +25,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 IP: 127.0.0.1, CN: example.com certificates
+cfssl gencert \
+  --ca ./ca.crt \
+  --ca-key ./ca-key.pem \
+  --config ./gencert.json \
+  ./server-ca-csr-ip.json | cfssljson --bare ./server-ip
+mv server-ip.pem server-ip.crt
+mv server-ip-key.pem server-ip.key.insecure
+
 # generate DNS: localhost, IP: 127.0.0.1, CN: example2.com certificates
 # generate DNS: localhost, IP: 127.0.0.1, CN: example2.com certificates
 cfssl gencert \
 cfssl gencert \
   --ca ./ca.crt \
   --ca ./ca.crt \

BIN
integration/fixtures/revoke.crl


+ 19 - 0
integration/fixtures/server-ca-csr-ip.json

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

+ 24 - 0
integration/fixtures/server-ip.crt

@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEBjCCAu6gAwIBAgITULCLY8OCPd8L4ZLShYUI99ZIFjANBgkqhkiG9w0BAQsF
+ADBvMQwwCgYDVQQGEwNVU0ExEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcT
+DVNhbiBGcmFuY2lzY28xDTALBgNVBAoTBGV0Y2QxFjAUBgNVBAsTDWV0Y2QgU2Vj
+dXJpdHkxCzAJBgNVBAMTAmNhMB4XDTE4MDQxMzE4NTMwMFoXDTI4MDQxMDE4NTMw
+MFoweDEMMAoGA1UEBhMDVVNBMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH
+Ew1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKEwRldGNkMRYwFAYDVQQLEw1ldGNkIFNl
+Y3VyaXR5MRQwEgYDVQQDEwtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAKs3eBWGM6rsQsYOPy48fuFDEg71hNbUw1YCfNQueHpz/jqJ
+E4RDfjb/Ou3V6m/MIsfmdWua+mZ/H3EXwnz0eAXSuspyNHOEaYkgqDYOVGnMD99y
++JhEVhSb+hRR4vR8qoL8fnJWdoINxaLAHm6K/93RPwyvn+m5fjUIt6yRnZ9PZaGv
+CtdQKo82VoNcJyB4Fz4Ahwy4FxKBE+zPOhR/TuBia2E4r/G4qqVf+DPStXFKxrlG
+Mcw9QxSCsOXArrp+E6zya875HSRBvHJO3+ECpEpP9oymisIg2xswCs0r/v5J3RS6
+EQ07vhOr/6Ez5UmCohlnsiUuj1XEqiCRFUFCa0cCAwEAAaOBkTCBjjAOBgNVHQ8B
+Af8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB
+/wQCMAAwHQYDVR0OBBYEFF/PxASI1qkJfBdnZmtsZWyR90etMB8GA1UdIwQYMBaA
+FB2ovSLsoXu2YFNS+1HYWkv4KybbMA8GA1UdEQQIMAaHBH8AAAEwDQYJKoZIhvcN
+AQELBQADggEBAJHrPCBhY9AMfKdh3ZRVMFxRsNCK9OzcWRMGxJ6OG/blUQZdW9FT
+aeAcCuhbu+0VYjfM2hpQ2DWPRjgi2nA0BRbVHY3nExUBgZxGZ8weQWCeZVEbV6Vs
+FLNBCcWIaX53bKPNFqraX7HWot9xvIb9fCc4w3z42fY8XxDg33E829Oe6F3e6+6L
+b04WQ89U/0Nd7vqkUKgsCqBVIg1PW6AbkNmv/uL4eSlcaV1nafXc0BY2i4XOmNBG
+fih23YHubjuLVuURBN+gDm/3bbyGWcCAnInq5/QM2aMd6GaU2Q80sw1W1PgMR+qE
+QiZ+goMjqqkDljEe4+NiP1s0jKtBTGLQFc0=
+-----END CERTIFICATE-----

+ 27 - 0
integration/fixtures/server-ip.key.insecure

@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAqzd4FYYzquxCxg4/Ljx+4UMSDvWE1tTDVgJ81C54enP+OokT
+hEN+Nv867dXqb8wix+Z1a5r6Zn8fcRfCfPR4BdK6ynI0c4RpiSCoNg5UacwP33L4
+mERWFJv6FFHi9Hyqgvx+clZ2gg3FosAebor/3dE/DK+f6bl+NQi3rJGdn09loa8K
+11AqjzZWg1wnIHgXPgCHDLgXEoET7M86FH9O4GJrYTiv8biqpV/4M9K1cUrGuUYx
+zD1DFIKw5cCuun4TrPJrzvkdJEG8ck7f4QKkSk/2jKaKwiDbGzAKzSv+/kndFLoR
+DTu+E6v/oTPlSYKiGWeyJS6PVcSqIJEVQUJrRwIDAQABAoIBAE01MTh7kPcFnULU
+j9cYvppz9UO7oVCDFybE7md8ISYPAliBEcT17od8ZqVzbklFw3VjThXdCAeKUbJc
+5X4Ve74cfdDm2RIyZqjIijH+GkCvHYVEwidfwXV/tLDPEEnxoa55j8edh8kzzqiK
+e+6bTbBIOGdPFwx9chUWPkVaULrShQRkZOMeyQyI1vhL2/TSOk+MsZPcrgQOQh9N
+v3xmmXA+IPNkO2GS5I3MZlLKDIkktejsdkudiE+uDHYzHPOFmu14LYPjZCTyl0Nx
+p6YP77ya/Um7f3zYyakXedGXBXX3h/zS8CarCpwNfzPwEADtommhhi6dR0rnCTfU
+t+aMTakCgYEA1eF1bgd0bKySigm3xx+UXxoOEjV1chdLwnwEL0M2XNvsMsm7Vh+m
+FmrY0I1m5n4bYv0UuEkPM3aUFnJuBW3fr3ypEDSfhLlP6eKX5gpyavJwC/eC+2e4
+ImxbsfRVbjLT7vMgbmMcjqe2B1rwYMDMSVMXieOxpi1ndViRAIpqjaUCgYEAzO8n
+heU7OddugNV5RMn6Gg/pMfiQpoROReFNMln34BZubpAMDHDnbjQOuqZA2UYbsNnb
+2Eu3TwqL+wr0CmQC0/nt1vR5dJZNX6VI61b4Qt4BdUUigonZxSHAnWjMzXmZ3Lvr
+5wgZO1Tq+9KBeMMMTQR5nfw+z5E+4Mh3+IzqWXsCgYAEkaRojVA3YhhfSoXagxow
+TeYvDWVM4qKDrRKJz+3BXhFVpGmUFWj+4ZlwGxUvp1H+c1mV9jmU59uR/y/KfeZh
+YVBbQESIGU1Tubt09pQrJLKwDsGFjVmpopby3j1U9VEBsb/nm8ZoZbzFu3OXHYc/
+qb6++1Y4LpAfOZ0fXdWY4QKBgFM5oGxg/p9r3OWXTCtidx5UbdisYFovivYYHFih
+bufjVC+0ciAvTd1UaNLmJ5nVPfOhVgXOIgCIgPaPqTH7EabybeOI3zY4v+1i220v
+oZzOOftc+znWL8k9/tIuOFYN1y1sZ84oXM7amp9wCsJ3O6yfb6B4Sy3Sh52T7BzV
+ZWq3AoGAeXHNJZj5CpH5tlgoJ2+3OXPTUuIUu7bJezmYkTaerKAtq+/NAlO90P5y
+cUkUETOZuc/jyyD3VLX5Emi5gma4GcRiMJzaZY/apYrr+I9I0A5KPexhzBVdJls9
+2Lk1fTDdilopP6p3W8rRiqlDp7q/iiTvVtdj0tOMZEclmdtZH6Q=
+-----END RSA PRIVATE KEY-----

+ 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,25 +1,25 @@
 -----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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
-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
-RchIgJR6qcPHkR7oloYDxA==
+oihDJmVoNTt+UNfUOXJcNMAbAhzlgdj9ayrjq6YBcJDr8SJySM9qjRpXhEuhJzti
+Yd7uN67G7UdPPnyT0555aMQ7aiG1wRWoh52ncclBqcu5fAFbB6XhMn6XniyRy3iD
+hQBgVquwGFJuPeTzGtt38nNUnssgDnv4MSOQEhmXxVyEmYID5xc6ky7f1jWIbueG
+EeuKjevTteKQlmKo0ofSm61mI15opt28gKgREhumLTQlSAZw7WL7LLe3DVod3pIV
+s0ltBkfYnMfbOLp01WWIQfBNsDlc06/UfDeV2p2ZfGHozus9xPSxSqSmzMY+hcDM
+OyWhJvpGLXfexOqiafT12w==
 -----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-----
-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
+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
-Y3VyaXR5MQswCQYDVQQDEwJjYTAeFw0xNzEwMDUyMTU5MDBaFw0yNzEwMDMyMTU5
+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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.key.insecure

@@ -1,27 +1,27 @@
 -----BEGIN RSA PRIVATE KEY-----
 -----BEGIN RSA PRIVATE KEY-----
-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
+MIIEpAIBAAKCAQEA9E1Ip0+qUkYroPTP5SYIwHIrihR+K/wzPP+lyj9g4NKci3NG
+CJriVkWglBqv9uvzJw92YdDeIKboGkmPLjyry6jxFZkgmL5PrRQPMnEofjkOk466
+MgokF8mvu8FsbZHjf0rqgWJXgGQ7jEvzR7ab32PdGzwb7XRbasmSfCHyRW5nMjJQ
+dzeynNTLi+xyTgf2WmuiFh1KC/AkRnlMpaPZNC/azzdlEVTt6JDPz21E6XAfHGIN
+A7YyeyDnGXBWtJwrI1BY+abNFQZ1QOkFAwUVQwEkkWcdvjY+2ARTv9otCnCSGnSV
+jXjfER9WALV0jRKcz30u4ajoBrCxH50KQ2C2vwIDAQABAoIBAFuoEzYSgYhUo1HE
+B6ulVWs+am9nuN6vxFmCYKU8mhA/dFQtb30S/w/3F4P5b0NoytVAy91vC6ecd0BF
+kN58DMhgHfNIfB5SaHo7KGh4ZATXS0y5I8paW6hBFxmOPCvvrDa52LmqN8IH2P+O
+Dzw8msZ5JR9usduo6BNshPTll4vMYGXSJJWBAczwn7ifEUp0zIzvfbzt5Gj9N7ik
+E3AzIT4lWB1id94BCxXHVTBtuSf2QgkK0oZzsbQr3FN0Mw30Cy5Rk90ns6ejihNp
+YHqsNzaVlxifNpf8ruM22+8tg60EnywKaAhwPnfwkigDECZdkc6SfsgahV/8wcGW
+LBK5NaECgYEA/h9Nk7ghlXCLITM12G6kOTwyz41+PoDJh0v6rMZ7+5HGSCmMtWAe
+ERA41D6NdS0G+RRatnM3D3iClRMD3Folp+nhZjumx/GsCGOo9x6HS1GqWjqe6uJ+
+KgXQyuRyz/v9LxTu+vXvyrwkM+yOzNkZMfB+ouKH3Kr2P7zZ+buiZhsCgYEA9htn
+kKWKZdNY/ACE2v3aW5sebrP6nIatf46MqJKqlB2InhJLjZQ4Dx/d7ZNCadn8WPjc
+R8RIFCTV3xaeYsJWmYWuD7MX3/8WcMo5ObQ3TblmTpWvgrPe/aAKeu0L9jSN1Irm
+DlbQblPoftGrtqOhirqiSUCKujSEU4A/kd/ajC0CgYEAmPQSZ3UOkbn5o/QE1s5R
+fjmjg5VwhQJTSmIK8W9ONK8bH1gS3yCJOFABRI6Z6gs+BTGhH+vdGiy4vC2Dx19j
+BtwY1MXWrsXhe/MwQf1YBZeT51cdS9cjhPuXHme+Sz0quOnqpZbdy7LOP4qEsPuC
+1LIiJrwedk1YhiiPMmcjaj0CgYEAmep7s9gEHTi3rys366nVlXMG7l87PgdwnJTv
+XUIU0ntCBPIWNF5dTQA2EK4HXCILky1Yvr2AArEi3NnNhqBZ/ru/J2xvYxSq2TFv
+5qnR6Jcp573vvUN3E5Gy3DxCPeGSTjnsNU2QH1/0yNOim5/smNGuSzfFSz0rAPn1
+R+sDSKUCgYBl+TSWIAoJG76eqPVXShwhA2kgNgfrYdyY9CEoRXMyxF0nWYXeR5yS
+sn/6WlQz9fNahpQnrqMjgMMYqr1NoLeQa13Yfb7PrLToVZ4AOQOC541ddNQ9352W
+1sf8ZkDljKz8uywdhE5XG8fvomtCp8IuNA5shR6A9qITjMXt+OPiAQ==
 -----END RSA PRIVATE KEY-----
 -----END RSA PRIVATE KEY-----

+ 16 - 16
integration/fixtures/server2.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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
+AAOCAQ8AMIIBCgKCAQEAr/MXz/jk2+YWddZNFCA8uBmWBhytJYxt9vO5cs1h2y2A
+S/cm0u3xSqwe8KSknQNdNpaxnA0j6pryKX9diiMoETowUNu4GzUrLaU1GouA3qHi
+hAFdeXAvRZeV4LXP7rToU7KBigCQKTS1G0Qc++GztzHsn9o0pk4fn76SNHFDfb6r
+3F6WRNXQkDGnZinxZfEQvS5/jJ/8lxJGJ1UpmRDr+vrIG/+UUldv5Noaxgvpgrvu
+uZFkdxerh0LrZyBkFRJlsqiCDLXD2Phbcb9WAsXKjs7hPScQJDGpEd8HKdiMmk0F
+c/5ZcO4PXtUbIxDX250tjCzDd7kjvg/ON8DeZjRFZQIDAQABo4GcMIGZMA4GA1Ud
 DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0T
 DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0T
-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
+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
 -----END CERTIFICATE-----
 -----END CERTIFICATE-----

+ 25 - 25
integration/fixtures/server2.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-----

+ 44 - 4
integration/v3_grpc_test.go

@@ -1654,7 +1654,7 @@ func TestTLSReloadAtomicReplace(t *testing.T) {
 			t.Fatal(err)
 			t.Fatal(err)
 		}
 		}
 	}
 	}
-	testTLSReload(t, cloneFunc, replaceFunc, revertFunc)
+	testTLSReload(t, cloneFunc, replaceFunc, revertFunc, false)
 }
 }
 
 
 // TestTLSReloadCopy ensures server reloads expired/valid certs
 // TestTLSReloadCopy ensures server reloads expired/valid certs
@@ -1684,17 +1684,57 @@ func TestTLSReloadCopy(t *testing.T) {
 			t.Fatal(err)
 			t.Fatal(err)
 		}
 		}
 	}
 	}
-	testTLSReload(t, cloneFunc, replaceFunc, revertFunc)
+	testTLSReload(t, cloneFunc, replaceFunc, revertFunc, false)
 }
 }
 
 
-func testTLSReload(t *testing.T, cloneFunc func() transport.TLSInfo, replaceFunc func(), revertFunc func()) {
+// TestTLSReloadCopyIPOnly ensures server reloads expired/valid certs
+// when new certs are copied over, one by one. And expects server
+// to reject client requests, and vice versa.
+func TestTLSReloadCopyIPOnly(t *testing.T) {
+	certsDir, err := ioutil.TempDir(os.TempDir(), "fixtures-to-load")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(certsDir)
+
+	cloneFunc := func() transport.TLSInfo {
+		tlsInfo, terr := copyTLSFiles(testTLSInfoIP, certsDir)
+		if terr != nil {
+			t.Fatal(terr)
+		}
+		return tlsInfo
+	}
+	replaceFunc := func() {
+		if _, err = copyTLSFiles(testTLSInfoExpiredIP, certsDir); err != nil {
+			t.Fatal(err)
+		}
+	}
+	revertFunc := func() {
+		if _, err = copyTLSFiles(testTLSInfoIP, certsDir); err != nil {
+			t.Fatal(err)
+		}
+	}
+	testTLSReload(t, cloneFunc, replaceFunc, revertFunc, true)
+}
+
+func testTLSReload(
+	t *testing.T,
+	cloneFunc func() transport.TLSInfo,
+	replaceFunc func(),
+	revertFunc func(),
+	useIP bool) {
 	defer testutil.AfterTest(t)
 	defer testutil.AfterTest(t)
 
 
 	// 1. separate copies for TLS assets modification
 	// 1. separate copies for TLS assets modification
 	tlsInfo := cloneFunc()
 	tlsInfo := cloneFunc()
 
 
 	// 2. start cluster with valid certs
 	// 2. start cluster with valid certs
-	clus := NewClusterV3(t, &ClusterConfig{Size: 1, PeerTLS: &tlsInfo, ClientTLS: &tlsInfo})
+	clus := NewClusterV3(t, &ClusterConfig{
+		Size:      1,
+		PeerTLS:   &tlsInfo,
+		ClientTLS: &tlsInfo,
+		UseIP:     useIP,
+	})
 	defer clus.Terminate(t)
 	defer clus.Terminate(t)
 
 
 	// 3. concurrent client dialing while certs become expired
 	// 3. concurrent client dialing while certs become expired

+ 23 - 4
pkg/transport/listener.go

@@ -194,6 +194,26 @@ func SelfCert(lg *zap.Logger, dirpath string, hosts []string) (info TLSInfo, err
 	return SelfCert(lg, dirpath, hosts)
 	return SelfCert(lg, dirpath, hosts)
 }
 }
 
 
+// baseConfig is called on initial TLS handshake start.
+//
+// Previously,
+// 1. Server has non-empty (*tls.Config).Certificates on client hello
+// 2. Server calls (*tls.Config).GetCertificate iff:
+//    - Server's (*tls.Config).Certificates is not empty, or
+//    - Client supplies SNI; non-empty (*tls.ClientHelloInfo).ServerName
+//
+// When (*tls.Config).Certificates is always populated on initial handshake,
+// client is expected to provide a valid matching SNI to pass the TLS
+// verification, thus trigger server (*tls.Config).GetCertificate to reload
+// TLS assets. However, a cert whose SAN field does not include domain names
+// but only IP addresses, has empty (*tls.ClientHelloInfo).ServerName, thus
+// it was never able to trigger TLS reload on initial handshake; first
+// ceritifcate object was being used, never being updated.
+//
+// Now, (*tls.Config).Certificates is created empty on initial TLS client
+// handshake, in order to trigger (*tls.Config).GetCertificate and populate
+// rest of the certificates on every new TLS connection, even when client
+// SNI is empty (e.g. cert only includes IPs).
 func (info TLSInfo) baseConfig() (*tls.Config, error) {
 func (info TLSInfo) baseConfig() (*tls.Config, error) {
 	if info.KeyFile == "" || info.CertFile == "" {
 	if info.KeyFile == "" || info.CertFile == "" {
 		return nil, fmt.Errorf("KeyFile and CertFile must both be present[key: %v, cert: %v]", info.KeyFile, info.CertFile)
 		return nil, fmt.Errorf("KeyFile and CertFile must both be present[key: %v, cert: %v]", info.KeyFile, info.CertFile)
@@ -202,15 +222,14 @@ func (info TLSInfo) baseConfig() (*tls.Config, error) {
 		info.Logger = zap.NewNop()
 		info.Logger = zap.NewNop()
 	}
 	}
 
 
-	tlsCert, err := tlsutil.NewCert(info.CertFile, info.KeyFile, info.parseFunc)
+	_, err := tlsutil.NewCert(info.CertFile, info.KeyFile, info.parseFunc)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
 	cfg := &tls.Config{
 	cfg := &tls.Config{
-		Certificates: []tls.Certificate{*tlsCert},
-		MinVersion:   tls.VersionTLS12,
-		ServerName:   info.ServerName,
+		MinVersion: tls.VersionTLS12,
+		ServerName: info.ServerName,
 	}
 	}
 
 
 	if info.AllowedCN != "" {
 	if info.AllowedCN != "" {