diff --git a/command/server/config.go b/command/server/config.go index 8f78ac0ad..32ee8c177 100644 --- a/command/server/config.go +++ b/command/server/config.go @@ -707,6 +707,7 @@ func parseListeners(result *Config, list *ast.ObjectList) error { "tls_cipher_suites", "tls_prefer_server_cipher_suites", "tls_require_and_verify_client_cert", + "tls_disable_client_certs", "tls_client_ca_file", "token", } diff --git a/command/server/config_test.go b/command/server/config_test.go index bdc9128e5..17f4ec7eb 100644 --- a/command/server/config_test.go +++ b/command/server/config_test.go @@ -269,7 +269,8 @@ listener "tcp" { tls_key_file = "./certs/server.key" tls_client_ca_file = "./certs/rootca.crt" tls_min_version = "tls12" - tls_require_and_verify_client_cert = true + tls_require_and_verify_client_cert = true + tls_disable_client_certs = true }`)) var config Config @@ -298,6 +299,7 @@ listener "tcp" { "tls_client_ca_file": "./certs/rootca.crt", "tls_min_version": "tls12", "tls_require_and_verify_client_cert": true, + "tls_disable_client_certs": true, }, }, }, diff --git a/command/server/listener.go b/command/server/listener.go index 4f9aedf7d..be83cba95 100644 --- a/command/server/listener.go +++ b/command/server/listener.go @@ -130,12 +130,14 @@ func listenerWrapTLS( } tlsConf.PreferServerCipherSuites = preferServer } + var requireVerifyCerts bool + var err error if v, ok := config["tls_require_and_verify_client_cert"]; ok { - requireClient, err := parseutil.ParseBool(v) + requireVerifyCerts, err = parseutil.ParseBool(v) if err != nil { return nil, nil, nil, fmt.Errorf("invalid value for 'tls_require_and_verify_client_cert': %v", err) } - if requireClient { + if requireVerifyCerts { tlsConf.ClientAuth = tls.RequireAndVerifyClientCert } if tlsClientCaFile, ok := config["tls_client_ca_file"]; ok { @@ -151,6 +153,16 @@ func listenerWrapTLS( tlsConf.ClientCAs = caPool } } + if v, ok := config["tls_disable_client_certs"]; ok { + disableClientCerts, err := parseutil.ParseBool(v) + if err != nil { + return nil, nil, nil, fmt.Errorf("invalid value for 'tls_disable_client_certs': %v", err) + } + if disableClientCerts && requireVerifyCerts { + return nil, nil, nil, fmt.Errorf("'tls_disable_client_certs' and 'tls_require_and_verify_client_cert' are mutually exclusive") + } + tlsConf.ClientAuth = tls.NoClientCert + } ln = tls.NewListener(ln, tlsConf) props["tls"] = "enabled" diff --git a/command/server/listener_tcp_test.go b/command/server/listener_tcp_test.go index 4da12b371..ff28afa4c 100644 --- a/command/server/listener_tcp_test.go +++ b/command/server/listener_tcp_test.go @@ -64,20 +64,50 @@ func TestTCPListener_tls(t *testing.T) { cwd+"/test-fixtures/reload/reload_foo.pem", cwd+"/test-fixtures/reload/reload_foo.key") - connFn := func(lnReal net.Listener) (net.Conn, error) { - conn, err := tls.Dial("tcp", ln.Addr().String(), &tls.Config{ - RootCAs: certPool, - Certificates: []tls.Certificate{clientCert}, - }) + connFn := func(clientCerts bool) func(net.Listener) (net.Conn, error) { + return func(lnReal net.Listener) (net.Conn, error) { + conf := &tls.Config{ + RootCAs: certPool, + } + if clientCerts { + conf.Certificates = []tls.Certificate{clientCert} + } + conn, err := tls.Dial("tcp", ln.Addr().String(), conf) - if err != nil { - return nil, err + if err != nil { + return nil, err + } + if err = conn.Handshake(); err != nil { + return nil, err + } + return conn, nil } - if err = conn.Handshake(); err != nil { - return nil, err - } - return conn, nil } - testListenerImpl(t, ln, connFn, "foo.example.com") + testListenerImpl(t, ln, connFn(true), "foo.example.com") + + ln, _, _, err = tcpListenerFactory(map[string]interface{}{ + "address": "127.0.0.1:0", + "tls_cert_file": wd + "reload_foo.pem", + "tls_key_file": wd + "reload_foo.key", + "tls_require_and_verify_client_cert": "true", + "tls_disable_client_certs": "true", + "tls_client_ca_file": wd + "reload_ca.pem", + }, nil) + if err == nil { + t.Fatal("expected error due to mutually exclusive client cert options") + } + + ln, _, _, err = tcpListenerFactory(map[string]interface{}{ + "address": "127.0.0.1:0", + "tls_cert_file": wd + "reload_foo.pem", + "tls_key_file": wd + "reload_foo.key", + "tls_disable_client_certs": "true", + "tls_client_ca_file": wd + "reload_ca.pem", + }, nil) + if err != nil { + t.Fatalf("err: %s", err) + } + + testListenerImpl(t, ln, connFn(false), "foo.example.com") } diff --git a/website/source/docs/configuration/listener/tcp.html.md b/website/source/docs/configuration/listener/tcp.html.md index 5c20a04fe..2605b4614 100644 --- a/website/source/docs/configuration/listener/tcp.html.md +++ b/website/source/docs/configuration/listener/tcp.html.md @@ -74,6 +74,10 @@ listener "tcp" { - `tls_client_ca_file` `(string: "")` – PEM-encoded Certificate Authority file used for checking the authenticity of client. +- `tls_disable_client_certs` `(string: "false")` – Turns off client + authentication for this listener. The default behavior (when this is false) + is for Vault to request client certificates when available. + ## `tcp` Listener Examples ### Configuring TLS