Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option for TLS enabled etcd server connections. #5496

Merged
merged 22 commits into from
Dec 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
8d6a921
Added functionality for etcd tls support, and included tests.
PrismaPhonic Dec 3, 2019
4dc8c68
Almost got tests working for tls etcd
PrismaPhonic Dec 6, 2019
f2a458b
Changed to pass by value per review suggestion.
PrismaPhonic Dec 10, 2019
158465e
Removed extra safety checks per review suggestion.
PrismaPhonic Dec 10, 2019
82d1ddd
Changed error return per review suggestion.
PrismaPhonic Dec 10, 2019
9881546
Update comments per review suggestion.
PrismaPhonic Dec 10, 2019
dbc614e
Moved common test logic into main tlstest file for access by other te…
PrismaPhonic Dec 11, 2019
d169ff6
Updated etcd2 flag names to etcd per convention as pointed out by rev…
PrismaPhonic Dec 11, 2019
1cdde0a
Update go/vt/topo/etcd2topo/server.go
PrismaPhonic Dec 11, 2019
4a014a3
Bring todo inside func so it doesn't get added into auto-generated docs
PrismaPhonic Dec 11, 2019
1aad001
Removed client.close() from defer as this should get called automatic…
PrismaPhonic Dec 11, 2019
343ac9c
Fixed up defers per review suggestions.
PrismaPhonic Dec 11, 2019
542b81a
Switched over to using server public api instead of pulling client ou…
PrismaPhonic Dec 11, 2019
27d33f3
Made sure that we retry until we establish an initial client, and clo…
PrismaPhonic Dec 11, 2019
4df14d8
Adding logging to try to figure out why tests are failing
PrismaPhonic Dec 11, 2019
9c059e2
Setup stderr and stdout for debugging in cicd
PrismaPhonic Dec 12, 2019
526f98f
Updating helper function to use DNS compatible common name
PrismaPhonic Dec 12, 2019
f2c4f47
Corrected log for accuracy
PrismaPhonic Dec 12, 2019
581131a
Corrected fatals message formatting
PrismaPhonic Dec 12, 2019
52fd6b4
Adding dns compliant server common name
PrismaPhonic Dec 12, 2019
7ae6664
Changing these back so we break with logging in CICD. :-(
PrismaPhonic Dec 12, 2019
1fe2abb
Pin unit test job to a specific version of etcd.
enisoc Dec 12, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/unit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ jobs:
- name: Get dependencies
run: |
sudo apt-get update
sudo apt-get install -y mysql-server mysql-client make unzip g++ etcd curl git wget ant openjdk-8-jdk
sudo apt-get install -y mysql-server mysql-client make unzip g++ curl git wget ant openjdk-8-jdk
sudo service mysql stop
sudo service etcd stop
sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/
sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld
mkdir -p dist bin
curl -L https://github.com/coreos/etcd/releases/download/v3.3.10/etcd-v3.3.10-linux-amd64.tar.gz | tar -zxC dist
mv dist/etcd-v3.3.10-linux-amd64/{etcd,etcdctl} bin/
go mod download

- name: Run make tools
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ require (
github.com/golang/mock v1.3.1
github.com/golang/protobuf v1.3.2
github.com/golang/snappy v0.0.0-20170215233205-553a64147049
github.com/google/btree v1.0.0 // indirect
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf // indirect
github.com/gorilla/websocket v0.0.0-20160912153041-2d1e4548da23
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0
Expand All @@ -49,6 +50,8 @@ require (
github.com/minio/minio-go v0.0.0-20190131015406-c8a261de75c1
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.1.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/olekukonko/tablewriter v0.0.0-20160115111002-cca8bbc07984
github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02
github.com/opentracing/opentracing-go v1.1.0
Expand Down
48 changes: 48 additions & 0 deletions go/vt/tlstest/tlstest.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,51 @@ func CreateSignedCert(root, parent, serial, name, commonName string) {
"-extfile", config,
"-out", cert)
}

type ClientServerKeyPairs struct {
ServerCert string
ServerKey string
ServerCA string
ServerName string
ClientCert string
ClientKey string
ClientCA string
}

var serialCounter = 0

func CreateClientServerCertPairs(root string) ClientServerKeyPairs {
// Create the certs and configs.
CreateCA(root)

serverSerial := fmt.Sprintf("%03d", serialCounter*2+1)
clientSerial := fmt.Sprintf("%03d", serialCounter*2+2)

serialCounter = serialCounter + 1

serverName := fmt.Sprintf("server-%s", serverSerial)
serverCACommonName := fmt.Sprintf("Server %s CA", serverSerial)
serverCertName := fmt.Sprintf("server-instance-%s", serverSerial)
serverCertCommonName := fmt.Sprintf("server%s.example.com", serverSerial)

clientName := fmt.Sprintf("clients-%s", serverSerial)
clientCACommonName := fmt.Sprintf("Clients %s CA", serverSerial)
clientCertName := fmt.Sprintf("client-instance-%s", serverSerial)
clientCertCommonName := fmt.Sprintf("Client Instance %s", serverSerial)

CreateSignedCert(root, CA, serverSerial, serverName, serverCACommonName)
CreateSignedCert(root, serverName, serverSerial, serverCertName, serverCertCommonName)

CreateSignedCert(root, CA, clientSerial, clientName, clientCACommonName)
CreateSignedCert(root, clientName, serverSerial, clientCertName, clientCertCommonName)

return ClientServerKeyPairs{
ServerCert: path.Join(root, fmt.Sprintf("%s-cert.pem", serverCertName)),
ServerKey: path.Join(root, fmt.Sprintf("%s-key.pem", serverCertName)),
ServerCA: path.Join(root, fmt.Sprintf("%s-cert.pem", serverName)),
ClientCert: path.Join(root, fmt.Sprintf("%s-cert.pem", clientCertName)),
ClientKey: path.Join(root, fmt.Sprintf("%s-key.pem", clientCertName)),
ClientCA: path.Join(root, fmt.Sprintf("%s-cert.pem", clientName)),
ServerName: serverCertCommonName,
}
}
99 changes: 24 additions & 75 deletions go/vt/tlstest/tlstest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"io/ioutil"
"net"
"os"
"path"
"strings"
"sync"
"testing"
Expand All @@ -47,20 +46,20 @@ func TestClientServer(t *testing.T) {
}
defer os.RemoveAll(root)

clientServerKeyPairs := createClientServerCertPairs(root)
clientServerKeyPairs := CreateClientServerCertPairs(root)

serverConfig, err := vttls.ServerConfig(
clientServerKeyPairs.serverCert,
clientServerKeyPairs.serverKey,
clientServerKeyPairs.clientCA)
clientServerKeyPairs.ServerCert,
clientServerKeyPairs.ServerKey,
clientServerKeyPairs.ClientCA)
if err != nil {
t.Fatalf("TLSServerConfig failed: %v", err)
}
clientConfig, err := vttls.ClientConfig(
clientServerKeyPairs.clientCert,
clientServerKeyPairs.clientKey,
clientServerKeyPairs.serverCA,
clientServerKeyPairs.serverName)
clientServerKeyPairs.ClientCert,
clientServerKeyPairs.ClientKey,
clientServerKeyPairs.ServerCA,
clientServerKeyPairs.ServerName)
if err != nil {
t.Fatalf("TLSClientConfig failed: %v", err)
}
Expand Down Expand Up @@ -117,10 +116,10 @@ func TestClientServer(t *testing.T) {
//

badClientConfig, err := vttls.ClientConfig(
clientServerKeyPairs.serverCert,
clientServerKeyPairs.serverKey,
clientServerKeyPairs.serverCA,
clientServerKeyPairs.serverName)
clientServerKeyPairs.ServerCert,
clientServerKeyPairs.ServerKey,
clientServerKeyPairs.ServerCA,
clientServerKeyPairs.ServerName)
if err != nil {
t.Fatalf("TLSClientConfig failed: %v", err)
}
Expand Down Expand Up @@ -165,69 +164,19 @@ func TestClientServer(t *testing.T) {
}
}

var serialCounter = 0

type clientServerKeyPairs struct {
serverCert string
serverKey string
serverCA string
serverName string
clientCert string
clientKey string
clientCA string
}

func createClientServerCertPairs(root string) clientServerKeyPairs {

// Create the certs and configs.
CreateCA(root)

serverSerial := fmt.Sprintf("%03d", serialCounter*2+1)
clientSerial := fmt.Sprintf("%03d", serialCounter*2+2)

serialCounter = serialCounter + 1

serverName := fmt.Sprintf("server-%s", serverSerial)
serverCACommonName := fmt.Sprintf("Server %s CA", serverSerial)
serverCertName := fmt.Sprintf("server-instance-%s", serverSerial)
serverCertCommonName := fmt.Sprintf("server%s.example.com", serverSerial)

clientName := fmt.Sprintf("clients-%s", serverSerial)
clientCACommonName := fmt.Sprintf("Clients %s CA", serverSerial)
clientCertName := fmt.Sprintf("client-instance-%s", serverSerial)
clientCertCommonName := fmt.Sprintf("Client Instance %s", serverSerial)

CreateSignedCert(root, CA, serverSerial, serverName, serverCACommonName)
CreateSignedCert(root, serverName, serverSerial, serverCertName, serverCertCommonName)

CreateSignedCert(root, CA, clientSerial, clientName, clientCACommonName)
CreateSignedCert(root, clientName, serverSerial, clientCertName, clientCertCommonName)

return clientServerKeyPairs{
serverCert: path.Join(root, fmt.Sprintf("%s-cert.pem", serverCertName)),
serverKey: path.Join(root, fmt.Sprintf("%s-key.pem", serverCertName)),
serverCA: path.Join(root, fmt.Sprintf("%s-cert.pem", serverName)),
clientCert: path.Join(root, fmt.Sprintf("%s-cert.pem", clientCertName)),
clientKey: path.Join(root, fmt.Sprintf("%s-key.pem", clientCertName)),
clientCA: path.Join(root, fmt.Sprintf("%s-cert.pem", clientName)),
serverName: serverCertCommonName,
}

}

func getServerConfig(keypairs clientServerKeyPairs) (*tls.Config, error) {
func getServerConfig(keypairs ClientServerKeyPairs) (*tls.Config, error) {
return vttls.ServerConfig(
keypairs.clientCert,
keypairs.clientKey,
keypairs.serverCA)
keypairs.ClientCert,
keypairs.ClientKey,
keypairs.ServerCA)
}

func getClientConfig(keypairs clientServerKeyPairs) (*tls.Config, error) {
func getClientConfig(keypairs ClientServerKeyPairs) (*tls.Config, error) {
return vttls.ClientConfig(
keypairs.clientCert,
keypairs.clientKey,
keypairs.serverCA,
keypairs.serverName)
keypairs.ClientCert,
keypairs.ClientKey,
keypairs.ServerCA,
keypairs.ServerName)
}

func TestServerTLSConfigCaching(t *testing.T) {
Expand All @@ -242,7 +191,7 @@ func TestClientTLSConfigCaching(t *testing.T) {
})
}

func testConfigGeneration(t *testing.T, rootPrefix string, generateConfig func(clientServerKeyPairs) (*tls.Config, error), getCertPool func(tlsConfig *tls.Config) *x509.CertPool) {
func testConfigGeneration(t *testing.T, rootPrefix string, generateConfig func(ClientServerKeyPairs) (*tls.Config, error), getCertPool func(tlsConfig *tls.Config) *x509.CertPool) {
// Our test root.
root, err := ioutil.TempDir("", rootPrefix)
if err != nil {
Expand All @@ -252,8 +201,8 @@ func testConfigGeneration(t *testing.T, rootPrefix string, generateConfig func(c

const configsToGenerate = 1

firstClientServerKeyPairs := createClientServerCertPairs(root)
secondClientServerKeyPairs := createClientServerCertPairs(root)
firstClientServerKeyPairs := CreateClientServerCertPairs(root)
secondClientServerKeyPairs := CreateClientServerCertPairs(root)

firstExpectedConfig, _ := generateConfig(firstClientServerKeyPairs)
secondExpectedConfig, _ := generateConfig(secondClientServerKeyPairs)
Expand Down
42 changes: 38 additions & 4 deletions go/vt/topo/etcd2topo/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,21 @@ We follow these conventions within this package:
package etcd2topo

import (
"flag"
"strings"
"time"

"github.com/coreos/etcd/clientv3"
"github.com/coreos/etcd/pkg/transport"
"vitess.io/vitess/go/vt/topo"
)

var (
clientCertPath = flag.String("topo_etcd_tls_cert", "", "path to the client cert to use to connect to the etcd topo server, requires topo_etcd_tls_key, enables TLS")
clientKeyPath = flag.String("topo_etcd_tls_key", "", "path to the client key to use to connect to the etcd topo server, enables TLS")
serverCaPath = flag.String("topo_etcd_tls_ca", "", "path to the ca to use to validate the server cert when connecting to the etcd topo server")
)

// Factory is the consul topo.Factory implementation.
type Factory struct{}

Expand Down Expand Up @@ -71,12 +79,31 @@ func (s *Server) Close() {
s.cli = nil
}

// NewServer returns a new etcdtopo.Server.
func NewServer(serverAddr, root string) (*Server, error) {
cli, err := clientv3.New(clientv3.Config{
func NewServerWithOpts(serverAddr, root, certPath, keyPath, caPath string) (*Server, error) {
// TODO: Rename this to NewServer and change NewServer to a name that signifies it uses the process-wide TLS settings.

config := clientv3.Config{
Endpoints: strings.Split(serverAddr, ","),
DialTimeout: 5 * time.Second,
})
}

// If TLS is enabled, attach TLS config info.
if certPath != "" && keyPath != "" {
// Safe now to build up TLS info.
tlsInfo := transport.TLSInfo{
CertFile: certPath,
KeyFile: keyPath,
TrustedCAFile: caPath,
}

tlsConfig, err := tlsInfo.ClientConfig()
if err != nil {
return nil, err
}
config.TLS = tlsConfig
}

cli, err := clientv3.New(config)
if err != nil {
return nil, err
}
Expand All @@ -87,6 +114,13 @@ func NewServer(serverAddr, root string) (*Server, error) {
}, nil
}

// NewServer returns a new etcdtopo.Server.
func NewServer(serverAddr, root string) (*Server, error) {
// TODO: Rename this to a name to signifies this function uses the process-wide TLS settings.

return NewServerWithOpts(serverAddr, root, *clientCertPath, *clientKeyPath, *serverCaPath)
}

func init() {
topo.RegisterFactory("etcd2", Factory{})
}
Loading