From aaf1c6a35218c40d9facc7b8fe1060226cae5fc6 Mon Sep 17 00:00:00 2001 From: fibonacci1729 Date: Thu, 12 Jul 2018 13:26:07 -0600 Subject: [PATCH 1/2] docs(*): update tiller_ssl docs to reflect IP SAN usage. When using helm/tiller in tls-verify mode, 127.0.0.1 should be listed as an IP SAN in the tiller certificate to pass hostname verficiation of the TLS handshake. Closes #4149 --- docs/tiller_ssl.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/tiller_ssl.md b/docs/tiller_ssl.md index 6db195507..963e36e40 100644 --- a/docs/tiller_ssl.md +++ b/docs/tiller_ssl.md @@ -284,6 +284,21 @@ the host name that Helm connects to matches the host name on the certificate. In some cases this is awkward, since Helm will connect over localhost, or the FQDN is not available for public resolution. +*If I use `--tls-verify` on the client, I get `Error: x509: cannot validate certificate for 127.0.0.1 because it doesn't contain any IP SANs`* + +By default, the Helm client connects to Tiller via tunnel (i.e. kube proxy) at 127.0.0.1. During the TLS handshake, +a target, usually provided as a hostname (e.g. example.com), is checked against the subject and subject alternative +names of the certificate (i.e. hostname verficiation). However, because of the tunnel, the target is an IP address. +Therefore, to validate the certificate, the IP address 127.0.0.1 must be listed as an IP subject alternative name +(IP SAN) in the Tiller certificate. + +For example, to list 127.0.0.1 as an IP SAN when generating the Tiller certificate: + +```console +$ echo subjectAltName=IP:127.0.0.1 > extfile.cnf +$ openssl x509 -req -CA ca.cert.pem -CAkey ca.key.pem -CAcreateserial -in tiller.csr.pem -out tiller.cert.pem -days 365 -extfile extfile.cnf +``` + *If I use `--tls-verify` on the client, I get `Error: x509: certificate has expired or is not yet valid`* Your helm certificate has expired, you need to sign a new certificate using your private key and the CA (and consider increasing the number of days) From 7faf62a209e91bfae17522e4a63c750a3482f6f3 Mon Sep 17 00:00:00 2001 From: fibonacci1729 Date: Mon, 16 Jul 2018 13:40:42 -0600 Subject: [PATCH 2/2] fix(helm): add --tls-hostname flag to tls-flags --- cmd/helm/helm.go | 11 +++++++++-- pkg/tlsutil/cfg.go | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 4c7ca9290..99075b8ab 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -40,6 +40,7 @@ import ( ) var ( + tlsServerName string // overrides the server name used to verify the hostname on the returned certificates from the server. tlsCaCertFile string // path to TLS CA certificate file tlsCertFile string // path to TLS certificate file tlsKeyFile string // path to TLS key file @@ -280,8 +281,13 @@ func newClient() helm.Interface { if tlsKeyFile == "" { tlsKeyFile = settings.Home.TLSKey() } - debug("Key=%q, Cert=%q, CA=%q\n", tlsKeyFile, tlsCertFile, tlsCaCertFile) - tlsopts := tlsutil.Options{KeyFile: tlsKeyFile, CertFile: tlsCertFile, InsecureSkipVerify: true} + debug("Host=%q, Key=%q, Cert=%q, CA=%q\n", tlsKeyFile, tlsCertFile, tlsCaCertFile) + tlsopts := tlsutil.Options{ + ServerName: tlsServerName, + KeyFile: tlsKeyFile, + CertFile: tlsCertFile, + InsecureSkipVerify: true, + } if tlsVerify { tlsopts.CaCertFile = tlsCaCertFile tlsopts.InsecureSkipVerify = false @@ -301,6 +307,7 @@ func newClient() helm.Interface { func addFlagsTLS(cmd *cobra.Command) *cobra.Command { // add flags + cmd.Flags().StringVar(&tlsServerName, "tls-hostname", settings.TillerHost, "the server name used to verify the hostname on the returned certificates from the server") cmd.Flags().StringVar(&tlsCaCertFile, "tls-ca-cert", tlsCaCertDefault, "path to TLS CA certificate file") cmd.Flags().StringVar(&tlsCertFile, "tls-cert", tlsCertDefault, "path to TLS certificate file") cmd.Flags().StringVar(&tlsKeyFile, "tls-key", tlsKeyDefault, "path to TLS key file") diff --git a/pkg/tlsutil/cfg.go b/pkg/tlsutil/cfg.go index 9ce3109e1..3cc18d3d2 100644 --- a/pkg/tlsutil/cfg.go +++ b/pkg/tlsutil/cfg.go @@ -33,6 +33,9 @@ type Options struct { CertFile string // Client-only options InsecureSkipVerify bool + // Overrides the server name used to verify the hostname on the returned + // certificates from the server. + ServerName string // Server-only options ClientAuth tls.ClientAuthType } @@ -55,8 +58,12 @@ func ClientConfig(opts Options) (cfg *tls.Config, err error) { return nil, err } } - - cfg = &tls.Config{InsecureSkipVerify: opts.InsecureSkipVerify, Certificates: []tls.Certificate{*cert}, RootCAs: pool} + cfg = &tls.Config{ + InsecureSkipVerify: opts.InsecureSkipVerify, + Certificates: []tls.Certificate{*cert}, + ServerName: opts.ServerName, + RootCAs: pool, + } return cfg, nil }