mirror of https://github.com/status-im/consul.git
Update TLS configurator for peering traffic
When the TLS-enabled gRPC port receives a request for the expected it must use the auto-tls certificates.
This commit is contained in:
parent
0e5131bd33
commit
650e1e32e0
|
@ -199,13 +199,15 @@ type Configurator struct {
|
|||
https protocolConfig
|
||||
internalRPC protocolConfig
|
||||
|
||||
// autoTLS stores configuration that is received from the auto-encrypt or
|
||||
// auto-config features.
|
||||
// autoTLS stores configuration that is received from:
|
||||
// - The auto-encrypt or auto-config features for client agents
|
||||
// - The servercert.CertManager for server agents.
|
||||
autoTLS struct {
|
||||
extraCAPems []string
|
||||
connectCAPems []string
|
||||
cert *tls.Certificate
|
||||
verifyServerHostname bool
|
||||
peeringServerName string
|
||||
}
|
||||
|
||||
// logger is not protected by a lock. It must never be changed after
|
||||
|
@ -372,7 +374,7 @@ func (c *Configurator) UpdateAutoTLSCA(connectCAPems []string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// UpdateAutoTLSCert receives the updated Auto-Encrypt certificate.
|
||||
// UpdateAutoTLSCert receives the updated automatically-provisioned certificate.
|
||||
func (c *Configurator) UpdateAutoTLSCert(pub, priv string) error {
|
||||
cert, err := tls.X509KeyPair([]byte(pub), []byte(priv))
|
||||
if err != nil {
|
||||
|
@ -388,6 +390,16 @@ func (c *Configurator) UpdateAutoTLSCert(pub, priv string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// UpdateAutoTLSPeeringServerName receives the updated automatically-provisioned certificate.
|
||||
func (c *Configurator) UpdateAutoTLSPeeringServerName(name string) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
c.autoTLS.peeringServerName = name
|
||||
atomic.AddUint64(&c.version, 1)
|
||||
c.log("UpdateAutoTLSPeeringServerName")
|
||||
}
|
||||
|
||||
// UpdateAutoTLS receives updates from Auto-Config, only expected to be called on
|
||||
// client agents.
|
||||
func (c *Configurator) UpdateAutoTLS(manualCAPems, connectCAPems []string, pub, priv string, verifyServerHostname bool) error {
|
||||
|
@ -754,6 +766,18 @@ func (c *Configurator) IncomingGRPCConfig() *tls.Config {
|
|||
config.GetConfigForClient = func(*tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
return c.IncomingGRPCConfig(), nil
|
||||
}
|
||||
config.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
if c.autoTLS.peeringServerName != "" && info.ServerName == c.autoTLS.peeringServerName {
|
||||
// For peering control plane traffic we exclusively use the internally managed certificate.
|
||||
// For all other traffic it is only a fallback if no manual certificate is provisioned.
|
||||
return c.autoTLS.cert, nil
|
||||
}
|
||||
|
||||
if c.grpc.cert != nil {
|
||||
return c.grpc.cert, nil
|
||||
}
|
||||
return c.autoTLS.cert, nil
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
|
|
|
@ -225,6 +225,67 @@ func TestConfigurator_IncomingConfig_Common(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestConfigurator_IncomingGRPCConfig_Peering(t *testing.T) {
|
||||
// Manually configure Alice's certificates
|
||||
cfg := Config{
|
||||
GRPC: ProtocolConfig{
|
||||
CertFile: "../test/hostname/Alice.crt",
|
||||
KeyFile: "../test/hostname/Alice.key",
|
||||
},
|
||||
}
|
||||
c := makeConfigurator(t, cfg)
|
||||
|
||||
// Set Bob's certificate via auto TLS.
|
||||
bobCert := loadFile(t, "../test/hostname/Bob.crt")
|
||||
bobKey := loadFile(t, "../test/hostname/Bob.key")
|
||||
require.NoError(t, c.UpdateAutoTLSCert(bobCert, bobKey))
|
||||
|
||||
peeringServerName := "server.dc1.peering.1234"
|
||||
c.UpdateAutoTLSPeeringServerName(peeringServerName)
|
||||
|
||||
testutil.RunStep(t, "with peering name", func(t *testing.T) {
|
||||
client, errc, _ := startTLSServer(c.IncomingGRPCConfig())
|
||||
if client == nil {
|
||||
t.Fatalf("startTLSServer err: %v", <-errc)
|
||||
}
|
||||
tlsClient := tls.Client(client, &tls.Config{
|
||||
// When the peering server name is provided the server should present
|
||||
// the certificates configured via AutoTLS (Bob).
|
||||
ServerName: peeringServerName,
|
||||
InsecureSkipVerify: true,
|
||||
})
|
||||
require.NoError(t, tlsClient.Handshake())
|
||||
|
||||
certificates := tlsClient.ConnectionState().PeerCertificates
|
||||
require.NotEmpty(t, certificates)
|
||||
require.Equal(t, "Bob", certificates[0].Subject.CommonName)
|
||||
|
||||
// Check the server side of the handshake succeded.
|
||||
require.NoError(t, <-errc)
|
||||
})
|
||||
|
||||
testutil.RunStep(t, "without name", func(t *testing.T) {
|
||||
client, errc, _ := startTLSServer(c.IncomingGRPCConfig())
|
||||
if client == nil {
|
||||
t.Fatalf("startTLSServer err: %v", <-errc)
|
||||
}
|
||||
|
||||
tlsClient := tls.Client(client, &tls.Config{
|
||||
// ServerName: peeringServerName,
|
||||
InsecureSkipVerify: true,
|
||||
})
|
||||
require.NoError(t, tlsClient.Handshake())
|
||||
|
||||
certificates := tlsClient.ConnectionState().PeerCertificates
|
||||
require.NotEmpty(t, certificates)
|
||||
|
||||
// Should default to presenting the manually configured certificates.
|
||||
require.Equal(t, "Alice", certificates[0].Subject.CommonName)
|
||||
|
||||
// Check the server side of the handshake succeded.
|
||||
require.NoError(t, <-errc)
|
||||
})
|
||||
}
|
||||
func TestConfigurator_IncomingInsecureRPCConfig(t *testing.T) {
|
||||
// if this test is failing because of expired certificates
|
||||
// use the procedure in test/CA-GENERATION.md
|
||||
|
|
Loading…
Reference in New Issue