From 434501c3ed9d86f04f465c47f5f1babe50777fd2 Mon Sep 17 00:00:00 2001 From: Ivan Kozlovic Date: Thu, 2 May 2019 15:06:08 -0600 Subject: [PATCH] Fixed LeafNode failed to create TLS connection when CA needed If server solicits leaf node TLS connection and needs to verify the server certificate, it did not have the root CAs set in its config. Signed-off-by: Ivan Kozlovic --- server/leafnode_test.go | 63 +++++++++++++++++++++++++++++++++++++++++ server/opts.go | 4 +++ 2 files changed, 67 insertions(+) diff --git a/server/leafnode_test.go b/server/leafnode_test.go index be954f8399..b2a1761ab3 100644 --- a/server/leafnode_test.go +++ b/server/leafnode_test.go @@ -14,8 +14,10 @@ package server import ( + "context" "fmt" "net/url" + "os" "strings" "testing" "time" @@ -73,3 +75,64 @@ func TestLeafNodeRandomIP(t *testing.T) { t.Fatalf("Does not seem to have used random IPs") } } + +type testLoopbackResolver struct{} + +func (r *testLoopbackResolver) LookupHost(ctx context.Context, host string) ([]string, error) { + return []string{"127.0.0.1"}, nil +} + +func TestLeafNodeTLSWithCerts(t *testing.T) { + conf1 := createConfFile(t, []byte(` + port: -1 + leaf { + listen: "127.0.0.1:-1" + tls { + ca_file: "../test/configs/certs/tlsauth/ca.pem" + cert_file: "../test/configs/certs/tlsauth/server.pem" + key_file: "../test/configs/certs/tlsauth/server-key.pem" + timeout: 2 + } + } + `)) + defer os.Remove(conf1) + s1, o1 := RunServerWithConfig(conf1) + defer s1.Shutdown() + + u, err := url.Parse(fmt.Sprintf("nats://localhost:%d", o1.LeafNode.Port)) + if err != nil { + t.Fatalf("Error parsing url: %v", err) + } + conf2 := createConfFile(t, []byte(fmt.Sprintf(` + port: -1 + leaf { + remotes [ + { + url: "%s" + tls { + ca_file: "../test/configs/certs/tlsauth/ca.pem" + cert_file: "../test/configs/certs/tlsauth/client.pem" + key_file: "../test/configs/certs/tlsauth/client-key.pem" + timeout: 2 + } + } + ] + } + `, u.String()))) + defer os.Remove(conf2) + o2, err := ProcessConfigFile(conf2) + if err != nil { + t.Fatalf("Error processing config file: %v", err) + } + o2.NoLog, o2.NoSigs = true, true + o2.LeafNode.resolver = &testLoopbackResolver{} + s2 := RunServer(o2) + defer s2.Shutdown() + + checkFor(t, 3*time.Second, 10*time.Millisecond, func() error { + if nln := s1.NumLeafNodes(); nln != 1 { + return fmt.Errorf("Number of leaf nodes is %d", nln) + } + return nil + }) +} diff --git a/server/opts.go b/server/opts.go index 04a9de2e1c..44864ca3ac 100644 --- a/server/opts.go +++ b/server/opts.go @@ -1050,6 +1050,10 @@ func parseRemoteLeafNodes(v interface{}, errors *[]error, warnings *[]error) ([] *errors = append(*errors, &configErr{tk, err.Error()}) continue } + // If ca_file is defined, GenTLSConfig() sets TLSConfig.ClientCAs. + // Set RootCAs since this tls.Config is used when soliciting + // a connection (therefore behaves as a client). + remote.TLSConfig.RootCAs = remote.TLSConfig.ClientCAs remote.TLSTimeout = tc.Timeout default: if !tk.IsUsedVariable() {