Add an AutoEncrypt “integration” test

Also fix a bug where Consul could segfault if TLS was enabled but no client certificate was provided. How no one has reported this as a problem I am not sure.
This commit is contained in:
Matt Keeler 2020-06-30 13:52:57 -04:00
parent 2ddcba00c6
commit 6e7acfa618
No known key found for this signature in database
GPG Key ID: 04DBAE1857E0081B
3 changed files with 85 additions and 2 deletions

View File

@ -4,6 +4,7 @@ import (
"bytes"
"context"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/json"
"fmt"
@ -4628,7 +4629,7 @@ func TestAutoConfig_Integration(t *testing.T) {
})
require.NoError(t, err)
client := StartTestAgent(t, TestAgent{Name: "test-client", HCL: TestACLConfigWithParams(nil) + `
client := StartTestAgent(t, TestAgent{Name: "test-client", HCL: `
bootstrap = false
server = false
ca_file = "` + caFile + `"
@ -4654,3 +4655,78 @@ func TestAutoConfig_Integration(t *testing.T) {
// spot check that we now have an ACL token
require.NotEmpty(t, client.tokens.AgentToken())
}
func TestAgent_AutoEncrypt(t *testing.T) {
// eventually this test should really live with integration tests
// the goal here is to have one test server and another test client
// spin up both agents and allow the server to authorize the auto encrypt
// request and then see the client get a TLS certificate
cfgDir := testutil.TempDir(t, "auto-encrypt")
// write some test TLS certificates out to the cfg dir
cert, key, cacert, err := testTLSCertificates("server.dc1.consul")
require.NoError(t, err)
certFile := filepath.Join(cfgDir, "cert.pem")
caFile := filepath.Join(cfgDir, "cacert.pem")
keyFile := filepath.Join(cfgDir, "key.pem")
require.NoError(t, ioutil.WriteFile(certFile, []byte(cert), 0600))
require.NoError(t, ioutil.WriteFile(caFile, []byte(cacert), 0600))
require.NoError(t, ioutil.WriteFile(keyFile, []byte(key), 0600))
hclConfig := TestACLConfigWithParams(nil) + `
verify_incoming = true
verify_outgoing = true
verify_server_hostname = true
ca_file = "` + caFile + `"
cert_file = "` + certFile + `"
key_file = "` + keyFile + `"
connect { enabled = true }
auto_encrypt { allow_tls = true }
`
srv := StartTestAgent(t, TestAgent{Name: "test-server", HCL: hclConfig})
defer srv.Shutdown()
testrpc.WaitForTestAgent(t, srv.RPC, "dc1", testrpc.WithToken(TestDefaultMasterToken))
client := StartTestAgent(t, TestAgent{Name: "test-client", HCL: TestACLConfigWithParams(nil) + `
bootstrap = false
server = false
ca_file = "` + caFile + `"
verify_outgoing = true
verify_server_hostname = true
node_name = "test-client"
auto_encrypt {
tls = true
}
ports {
server = ` + strconv.Itoa(srv.Config.RPCBindAddr.Port) + `
}
retry_join = ["` + srv.Config.SerfBindAddrLAN.String() + `"]`,
UseTLS: true,
})
defer client.Shutdown()
// when this is successful we managed to get a TLS certificate and are using it for
// encrypted RPC connections.
testrpc.WaitForTestAgent(t, client.RPC, "dc1", testrpc.WithToken(TestDefaultMasterToken))
// now we need to validate that our certificate has the correct CN
aeCert := client.tlsConfigurator.Cert()
require.NotNil(t, aeCert)
id := connect.SpiffeIDAgent{
Host: connect.TestClusterID + ".consul",
Datacenter: "dc1",
Agent: "test-client",
}
expectedCN := connect.AgentCN("test-client", connect.TestClusterID)
x509Cert, err := x509.ParseCertificate(aeCert.Certificate[0])
require.NoError(t, err)
require.Equal(t, expectedCN, x509Cert.Subject.CommonName)
require.Len(t, x509Cert.URIs, 1)
require.Equal(t, id.URI(), x509Cert.URIs[0])
}

View File

@ -505,6 +505,12 @@ func (c *Configurator) commonTLSConfig(verifyIncoming bool) *tls.Config {
cert = c.manual.cert
}
if cert == nil {
// the return value MUST not be nil but an empty certificate will be
// treated the same as having no client certificate
cert = &tls.Certificate{}
}
return cert, nil
}

View File

@ -649,7 +649,8 @@ func TestConfigurator_CommonTLSConfigGetClientCertificate(t *testing.T) {
cert, err := c.commonTLSConfig(false).GetClientCertificate(nil)
require.NoError(t, err)
require.Nil(t, cert)
require.NotNil(t, cert)
require.Empty(t, cert.Certificate)
c1, err := loadKeyPair("../test/key/something_expired.cer", "../test/key/something_expired.key")
require.NoError(t, err)