pull/3496/merge
Keith Burdis 7 years ago committed by GitHub
commit d4f1928a96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -72,9 +72,9 @@ func newGetCmd(client helm.Interface, out io.Writer) *cobra.Command {
cmd.Flags().Int32Var(&get.version, "revision", 0, "get the named release with revision") cmd.Flags().Int32Var(&get.version, "revision", 0, "get the named release with revision")
cmd.AddCommand(addFlagsTLS(newGetValuesCmd(nil, out))) cmd.AddCommand(newGetValuesCmd(nil, out))
cmd.AddCommand(addFlagsTLS(newGetManifestCmd(nil, out))) cmd.AddCommand(newGetManifestCmd(nil, out))
cmd.AddCommand(addFlagsTLS(newGetHooksCmd(nil, out))) cmd.AddCommand(newGetHooksCmd(nil, out))
return cmd return cmd
} }

@ -40,16 +40,6 @@ import (
) )
var ( var (
tlsCaCertFile string // path to TLS CA certificate file
tlsCertFile string // path to TLS certificate file
tlsKeyFile string // path to TLS key file
tlsVerify bool // enable TLS and verify remote certificates
tlsEnable bool // enable TLS
tlsCaCertDefault = "$HELM_HOME/ca.pem"
tlsCertDefault = "$HELM_HOME/cert.pem"
tlsKeyDefault = "$HELM_HOME/key.pem"
tillerTunnel *kube.Tunnel tillerTunnel *kube.Tunnel
settings helm_env.EnvSettings settings helm_env.EnvSettings
) )
@ -76,6 +66,11 @@ Environment:
$HELM_NO_PLUGINS disable plugins. Set HELM_NO_PLUGINS=1 to disable plugins. $HELM_NO_PLUGINS disable plugins. Set HELM_NO_PLUGINS=1 to disable plugins.
$TILLER_NAMESPACE set an alternative Tiller namespace (default "kube-system") $TILLER_NAMESPACE set an alternative Tiller namespace (default "kube-system")
$KUBECONFIG set an alternative Kubernetes configuration file (default "~/.kube/config") $KUBECONFIG set an alternative Kubernetes configuration file (default "~/.kube/config")
$HELM_TLS_CA_CERT path to TLS CA certificate used to verify the Helm client and Tiller server certificates (default "$HELM_HOME/ca.pem")
$HELM_TLS_CERT path to TLS client certificate file for authenticating to Tiller (default "$HELM_HOME/cert.pem")
$HELM_TLS_KEY path to TLS client key file for authenticating to Tiller (default "$HELM_HOME/key.pem")
$HELM_TLS_VERIFY enable TLS connection between Helm and Tiller and verify Tiller server certificate (default "false")
$HELM_TLS_ENABLE enable TLS connection between Helm and Tiller (default "false")
` `
func newRootCmd(args []string) *cobra.Command { func newRootCmd(args []string) *cobra.Command {
@ -84,11 +79,6 @@ func newRootCmd(args []string) *cobra.Command {
Short: "The Helm package manager for Kubernetes.", Short: "The Helm package manager for Kubernetes.",
Long: globalUsage, Long: globalUsage,
SilenceUsage: true, SilenceUsage: true,
PersistentPreRun: func(*cobra.Command, []string) {
tlsCaCertFile = os.ExpandEnv(tlsCaCertFile)
tlsCertFile = os.ExpandEnv(tlsCertFile)
tlsKeyFile = os.ExpandEnv(tlsKeyFile)
},
PersistentPostRun: func(*cobra.Command, []string) { PersistentPostRun: func(*cobra.Command, []string) {
teardown() teardown()
}, },
@ -113,18 +103,18 @@ func newRootCmd(args []string) *cobra.Command {
newVerifyCmd(out), newVerifyCmd(out),
// release commands // release commands
addFlagsTLS(newDeleteCmd(nil, out)), newDeleteCmd(nil, out),
addFlagsTLS(newGetCmd(nil, out)), newGetCmd(nil, out),
addFlagsTLS(newHistoryCmd(nil, out)), newHistoryCmd(nil, out),
addFlagsTLS(newInstallCmd(nil, out)), newInstallCmd(nil, out),
addFlagsTLS(newListCmd(nil, out)), newListCmd(nil, out),
addFlagsTLS(newRollbackCmd(nil, out)), newRollbackCmd(nil, out),
addFlagsTLS(newStatusCmd(nil, out)), newStatusCmd(nil, out),
addFlagsTLS(newUpgradeCmd(nil, out)), newUpgradeCmd(nil, out),
addFlagsTLS(newReleaseTestCmd(nil, out)), newReleaseTestCmd(nil, out),
addFlagsTLS(newResetCmd(nil, out)), newResetCmd(nil, out),
addFlagsTLS(newVersionCmd(nil, out)), newVersionCmd(nil, out),
newCompletionCmd(out), newCompletionCmd(out),
newHomeCmd(out), newHomeCmd(out),
@ -270,20 +260,11 @@ func ensureHelmClient(h helm.Interface) helm.Interface {
func newClient() helm.Interface { func newClient() helm.Interface {
options := []helm.Option{helm.Host(settings.TillerHost), helm.ConnectTimeout(settings.TillerConnectionTimeout)} options := []helm.Option{helm.Host(settings.TillerHost), helm.ConnectTimeout(settings.TillerConnectionTimeout)}
if tlsVerify || tlsEnable { if settings.TLSVerify || settings.TLSEnable {
if tlsCaCertFile == "" { debug("Key=%q, Cert=%q, CA=%q\n", settings.TLSKeyFile, settings.TLSCertFile, settings.TLSCaCertFile)
tlsCaCertFile = settings.Home.TLSCaCert() tlsopts := tlsutil.Options{KeyFile: settings.TLSKeyFile, CertFile: settings.TLSCertFile, InsecureSkipVerify: true}
} if settings.TLSVerify {
if tlsCertFile == "" { tlsopts.CaCertFile = settings.TLSCaCertFile
tlsCertFile = settings.Home.TLSCert()
}
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}
if tlsVerify {
tlsopts.CaCertFile = tlsCaCertFile
tlsopts.InsecureSkipVerify = false tlsopts.InsecureSkipVerify = false
} }
tlscfg, err := tlsutil.ClientConfig(tlsopts) tlscfg, err := tlsutil.ClientConfig(tlsopts)
@ -295,16 +276,3 @@ func newClient() helm.Interface {
} }
return helm.NewClient(options...) return helm.NewClient(options...)
} }
// addFlagsTLS adds the flags for supporting client side TLS to the
// helm command (only those that invoke communicate to Tiller.)
func addFlagsTLS(cmd *cobra.Command) *cobra.Command {
// add flags
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")
cmd.Flags().BoolVar(&tlsVerify, "tls-verify", false, "enable TLS for request and verify remote")
cmd.Flags().BoolVar(&tlsEnable, "tls", false, "enable TLS for request")
return cmd
}

@ -90,6 +90,11 @@ type initCmd struct {
maxHistory int maxHistory int
replicas int replicas int
wait bool wait bool
tlsEnable bool
tlsVerify bool
tlsKeyFile string
tlsCertFile string
tlsCaCertFile string
} }
func newInitCmd(out io.Writer) *cobra.Command { func newInitCmd(out io.Writer) *cobra.Command {
@ -105,6 +110,7 @@ func newInitCmd(out io.Writer) *cobra.Command {
} }
i.namespace = settings.TillerNamespace i.namespace = settings.TillerNamespace
i.home = settings.Home i.home = settings.Home
i.tlsCaCertFile = settings.TLSCaCertFile
i.client = ensureHelmClient(i.client) i.client = ensureHelmClient(i.client)
return i.run() return i.run()
@ -121,11 +127,10 @@ func newInitCmd(out io.Writer) *cobra.Command {
f.BoolVar(&i.skipRefresh, "skip-refresh", false, "do not refresh (download) the local repository cache") f.BoolVar(&i.skipRefresh, "skip-refresh", false, "do not refresh (download) the local repository cache")
f.BoolVar(&i.wait, "wait", false, "block until Tiller is running and ready to receive requests") f.BoolVar(&i.wait, "wait", false, "block until Tiller is running and ready to receive requests")
f.BoolVar(&tlsEnable, "tiller-tls", false, "install Tiller with TLS enabled") f.BoolVar(&i.tlsEnable, "tiller-tls", false, "install Tiller with TLS enabled")
f.BoolVar(&tlsVerify, "tiller-tls-verify", false, "install Tiller with TLS enabled and to verify remote certificates") f.BoolVar(&i.tlsVerify, "tiller-tls-verify", false, "install Tiller with TLS and Helm client certificate verification enabled")
f.StringVar(&tlsKeyFile, "tiller-tls-key", "", "path to TLS key file to install with Tiller") f.StringVar(&i.tlsKeyFile, "tiller-tls-key", "", "path to Tiller TLS server key file")
f.StringVar(&tlsCertFile, "tiller-tls-cert", "", "path to TLS certificate file to install with Tiller") f.StringVar(&i.tlsCertFile, "tiller-tls-cert", "", "path to Tiller TLS server certificate file")
f.StringVar(&tlsCaCertFile, "tls-ca-cert", "", "path to CA root certificate")
f.StringVar(&stableRepositoryURL, "stable-repo-url", stableRepositoryURL, "URL for stable repository") f.StringVar(&stableRepositoryURL, "stable-repo-url", stableRepositoryURL, "URL for stable repository")
f.StringVar(&localRepositoryURL, "local-repo-url", localRepositoryURL, "URL for local repository") f.StringVar(&localRepositoryURL, "local-repo-url", localRepositoryURL, "URL for local repository")
@ -145,22 +150,22 @@ func newInitCmd(out io.Writer) *cobra.Command {
// tlsOptions sanitizes the tls flags as well as checks for the existence of required // tlsOptions sanitizes the tls flags as well as checks for the existence of required
// tls files indicated by those flags, if any. // tls files indicated by those flags, if any.
func (i *initCmd) tlsOptions() error { func (i *initCmd) tlsOptions() error {
i.opts.EnableTLS = tlsEnable || tlsVerify i.opts.EnableTLS = i.tlsEnable || i.tlsVerify
i.opts.VerifyTLS = tlsVerify i.opts.VerifyTLS = i.tlsVerify
if i.opts.EnableTLS { if i.opts.EnableTLS {
missing := func(file string) bool { missing := func(file string) bool {
_, err := os.Stat(file) _, err := os.Stat(file)
return os.IsNotExist(err) return os.IsNotExist(err)
} }
if i.opts.TLSKeyFile = tlsKeyFile; i.opts.TLSKeyFile == "" || missing(i.opts.TLSKeyFile) { if i.opts.TLSKeyFile = i.tlsKeyFile; i.opts.TLSKeyFile == "" || missing(i.opts.TLSKeyFile) {
return errors.New("missing required TLS key file") return errors.New("missing required TLS server key file")
} }
if i.opts.TLSCertFile = tlsCertFile; i.opts.TLSCertFile == "" || missing(i.opts.TLSCertFile) { if i.opts.TLSCertFile = i.tlsCertFile; i.opts.TLSCertFile == "" || missing(i.opts.TLSCertFile) {
return errors.New("missing required TLS certificate file") return errors.New("missing required TLS server certificate file")
} }
if i.opts.VerifyTLS { if i.opts.VerifyTLS {
if i.opts.TLSCaCertFile = tlsCaCertFile; i.opts.TLSCaCertFile == "" || missing(i.opts.TLSCaCertFile) { if i.opts.TLSCaCertFile = i.tlsCaCertFile; i.opts.TLSCaCertFile == "" || missing(i.opts.TLSCaCertFile) {
return errors.New("missing required TLS CA file") return errors.New("missing required TLS CA file")
} }
} }

@ -280,13 +280,14 @@ func TestInitCmd_tlsOptions(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
// emulate tls file specific flags // emulate tls flags
tlsCaCertFile, tlsCertFile, tlsKeyFile = tt.caFile, tt.certFile, tt.keyFile cmd := &initCmd{
tlsCaCertFile: tt.caFile,
// emulate tls enable/verify flags tlsCertFile: tt.certFile,
tlsEnable, tlsVerify = tt.enable, tt.verify tlsKeyFile: tt.keyFile,
tlsVerify: tt.verify,
cmd := &initCmd{} tlsEnable: tt.enable,
}
if err := cmd.tlsOptions(); err != nil { if err := cmd.tlsOptions(); err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }

@ -49,6 +49,16 @@ type EnvSettings struct {
Debug bool Debug bool
// KubeContext is the name of the kubeconfig context. // KubeContext is the name of the kubeconfig context.
KubeContext string KubeContext string
// TLSCaCertFile is the path to TLS CA certificate file used to verify the Helm client and Tiller server certificates
TLSCaCertFile string
// TLSCertFile is the path to Helm TLS client certificate file for authenticating to Tiller
TLSCertFile string
// TLSKeyFile is the path to Helm TLS client key file for authenticating to Tiller
TLSKeyFile string
// TLSVerify enables TLS between Helm and Tiller and verification of the Tiller server certificate
TLSVerify bool
// TLSEnable enables TLS between Helm and Tiller
TLSEnable bool
} }
// AddFlags binds flags to the given flagset. // AddFlags binds flags to the given flagset.
@ -59,6 +69,11 @@ func (s *EnvSettings) AddFlags(fs *pflag.FlagSet) {
fs.BoolVar(&s.Debug, "debug", false, "enable verbose output") fs.BoolVar(&s.Debug, "debug", false, "enable verbose output")
fs.StringVar(&s.TillerNamespace, "tiller-namespace", "kube-system", "namespace of Tiller") fs.StringVar(&s.TillerNamespace, "tiller-namespace", "kube-system", "namespace of Tiller")
fs.Int64Var(&s.TillerConnectionTimeout, "tiller-connection-timeout", int64(300), "the duration (in seconds) Helm will wait to establish a connection to tiller") fs.Int64Var(&s.TillerConnectionTimeout, "tiller-connection-timeout", int64(300), "the duration (in seconds) Helm will wait to establish a connection to tiller")
fs.StringVar(&s.TLSCaCertFile, "tls-ca-cert", "", "path to TLS CA certificate file used to verify the Helm client and Tiller server certificates")
fs.StringVar(&s.TLSCertFile, "tls-cert", "", "path to Helm TLS client certificate file for authenticating to Tiller")
fs.StringVar(&s.TLSKeyFile, "tls-key", "", "path to Helm TLS client key file for authenticating to Tiller")
fs.BoolVar(&s.TLSVerify, "tls-verify", false, "enable TLS connection between Helm and Tiller and verify Tiller server certificate")
fs.BoolVar(&s.TLSEnable, "tls", false, "enable TLS connection between Helm and Tiller")
} }
// Init sets values from the environment. // Init sets values from the environment.
@ -66,6 +81,16 @@ func (s *EnvSettings) Init(fs *pflag.FlagSet) {
for name, envar := range envMap { for name, envar := range envMap {
setFlagFromEnv(name, envar, fs) setFlagFromEnv(name, envar, fs)
} }
// TLS defaults that depend on Home value
if s.TLSCaCertFile == "" {
s.TLSCaCertFile = s.Home.TLSCaCert()
}
if s.TLSCertFile == "" {
s.TLSCertFile = s.Home.TLSCert()
}
if s.TLSKeyFile == "" {
s.TLSKeyFile = s.Home.TLSKey()
}
} }
// PluginDirs is the path to the plugin directories. // PluginDirs is the path to the plugin directories.
@ -82,6 +107,11 @@ var envMap = map[string]string{
"home": "HELM_HOME", "home": "HELM_HOME",
"host": "HELM_HOST", "host": "HELM_HOST",
"tiller-namespace": "TILLER_NAMESPACE", "tiller-namespace": "TILLER_NAMESPACE",
"tls-ca-cert": "HELM_TLS_CA_CERT",
"tls-cert": "HELM_TLS_CERT",
"tls-key": "HELM_TLS_KEY",
"tls-verify": "HELM_TLS_VERIFY",
"tls": "HELM_TLS_ENABLE",
} }
func setFlagFromEnv(name, envar string, fs *pflag.FlagSet) { func setFlagFromEnv(name, envar string, fs *pflag.FlagSet) {
@ -89,7 +119,7 @@ func setFlagFromEnv(name, envar string, fs *pflag.FlagSet) {
return return
} }
if v, ok := os.LookupEnv(envar); ok { if v, ok := os.LookupEnv(envar); ok {
fs.Set(name, v) fs.Set(name, os.ExpandEnv(v))
} }
} }

@ -37,6 +37,8 @@ func TestEnvSettings(t *testing.T) {
// expected values // expected values
home, host, ns, kcontext, plugins string home, host, ns, kcontext, plugins string
debug bool debug bool
tlsca, tlscert, tlskey string
tlsenable, tlsverify bool
}{ }{
{ {
name: "defaults", name: "defaults",
@ -44,6 +46,11 @@ func TestEnvSettings(t *testing.T) {
home: DefaultHelmHome, home: DefaultHelmHome,
plugins: helmpath.Home(DefaultHelmHome).Plugins(), plugins: helmpath.Home(DefaultHelmHome).Plugins(),
ns: "kube-system", ns: "kube-system",
tlsca: helmpath.Home(DefaultHelmHome).TLSCaCert(),
tlscert: helmpath.Home(DefaultHelmHome).TLSCert(),
tlskey: helmpath.Home(DefaultHelmHome).TLSKey(),
tlsenable: false,
tlsverify: false,
}, },
{ {
name: "with flags set", name: "with flags set",
@ -53,6 +60,11 @@ func TestEnvSettings(t *testing.T) {
host: "here", host: "here",
ns: "myns", ns: "myns",
debug: true, debug: true,
tlsca: helmpath.Home("/foo").TLSCaCert(),
tlscert: helmpath.Home("/foo").TLSCert(),
tlskey: helmpath.Home("/foo").TLSKey(),
tlsenable: false,
tlsverify: false,
}, },
{ {
name: "with envvars set", name: "with envvars set",
@ -63,6 +75,11 @@ func TestEnvSettings(t *testing.T) {
host: "there", host: "there",
ns: "yourns", ns: "yourns",
debug: true, debug: true,
tlsca: helmpath.Home("/bar").TLSCaCert(),
tlscert: helmpath.Home("/bar").TLSCert(),
tlskey: helmpath.Home("/bar").TLSKey(),
tlsenable: false,
tlsverify: false,
}, },
{ {
name: "with flags and envvars set", name: "with flags and envvars set",
@ -73,6 +90,50 @@ func TestEnvSettings(t *testing.T) {
host: "here", host: "here",
ns: "myns", ns: "myns",
debug: true, debug: true,
tlsca: helmpath.Home("/foo").TLSCaCert(),
tlscert: helmpath.Home("/foo").TLSCert(),
tlskey: helmpath.Home("/foo").TLSKey(),
tlsenable: false,
tlsverify: false,
},
{
name: "with TLS flags set",
args: []string{"--home", "/bar", "--tls-ca-cert", "/a/ca.crt", "--tls-cert=/a/client.crt", "--tls-key", "/a/client.key", "--tls-verify", "--tls"},
home: "/bar",
plugins: helmpath.Home("/bar").Plugins(),
ns: "kube-system",
debug: false,
tlsca: "/a/ca.crt",
tlscert: "/a/client.crt",
tlskey: "/a/client.key",
tlsenable: true,
tlsverify: true,
},
{
name: "with TLS envvars set",
args: []string{},
envars: map[string]string{"HELM_HOME": "/bar", "HELM_TLS_CA_CERT": "/e/ca.crt", "HELM_TLS_CERT": "/e/client.crt", "HELM_TLS_KEY": "/e/client.key", "HELM_TLS_VERIFY": "true", "HELM_TLS_ENABLE": "true"},
home: "/bar",
plugins: helmpath.Home("/bar").Plugins(),
ns: "kube-system",
tlsca: "/e/ca.crt",
tlscert: "/e/client.crt",
tlskey: "/e/client.key",
tlsenable: true,
tlsverify: true,
},
{
name: "with TLS flags and envvars set",
args: []string{"--tls-ca-cert", "/a/ca.crt", "--tls-cert=/a/client.crt", "--tls-key", "/a/client.key", "--tls-verify"},
envars: map[string]string{"HELM_HOME": "/bar", "HELM_TLS_CA_CERT": "/e/ca.crt", "HELM_TLS_CERT": "/e/client.crt", "HELM_TLS_KEY": "/e/client.key", "HELM_TLS_VERIFY": "true", "HELM_TLS_ENABLE": "true"},
home: "/bar",
plugins: helmpath.Home("/bar").Plugins(),
ns: "kube-system",
tlsca: "/a/ca.crt",
tlscert: "/a/client.crt",
tlskey: "/a/client.key",
tlsenable: true,
tlsverify: true,
}, },
} }
@ -111,7 +172,25 @@ func TestEnvSettings(t *testing.T) {
if settings.KubeContext != tt.kcontext { if settings.KubeContext != tt.kcontext {
t.Errorf("expected kube-context %q, got %q", tt.kcontext, settings.KubeContext) t.Errorf("expected kube-context %q, got %q", tt.kcontext, settings.KubeContext)
} }
if settings.TLSCaCertFile != tt.tlsca {
t.Errorf("expected tls-ca-cert %q, got %q", tt.tlsca, settings.TLSCaCertFile)
}
if settings.TLSCertFile != tt.tlscert {
t.Errorf("expected tls-cert %q, got %q", tt.tlscert, settings.TLSCertFile)
}
if settings.TLSKeyFile != tt.tlskey {
t.Errorf("expected tls-key %q, got %q", tt.tlskey, settings.TLSKeyFile)
}
if settings.TLSEnable != tt.tlsenable {
t.Errorf("expected tls %t, got %t", tt.tlsenable, settings.TLSEnable)
}
if settings.TLSVerify != tt.tlsverify {
t.Errorf("expected tls-verify %t, got %t", tt.tlsverify, settings.TLSVerify)
}
for k := range tt.envars {
os.Unsetenv(k)
}
cleanup() cleanup()
}) })
} }

Loading…
Cancel
Save