Skip to content

Commit a8e0983

Browse files
Merge pull request #2108 from fibonacci1729/feat/tls
feat/tls: Support optional TLS for helm / tiller
2 parents f958b3b + 735f4e3 commit a8e0983

File tree

8 files changed

+281
-40
lines changed

8 files changed

+281
-40
lines changed

cmd/helm/get.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,3 @@ func (g *getCmd) run() error {
8787
}
8888
return printRelease(g.out, res.Release)
8989
}
90-
91-
func ensureHelmClient(h helm.Interface) helm.Interface {
92-
if h != nil {
93-
return h
94-
}
95-
return helm.NewClient(helm.Host(tillerHost))
96-
}

cmd/helm/helm.go

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ import (
3232
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
3333
"k8s.io/kubernetes/pkg/client/restclient"
3434

35+
"k8s.io/helm/pkg/helm"
3536
"k8s.io/helm/pkg/helm/helmpath"
3637
"k8s.io/helm/pkg/helm/portforwarder"
3738
"k8s.io/helm/pkg/kube"
3839
"k8s.io/helm/pkg/tiller/environment"
40+
"k8s.io/helm/pkg/tlsutil"
3941
)
4042

4143
const (
@@ -95,6 +97,11 @@ func newRootCmd(out io.Writer) *cobra.Command {
9597
Short: "The Helm package manager for Kubernetes.",
9698
Long: globalUsage,
9799
SilenceUsage: true,
100+
PersistentPreRun: func(cmd *cobra.Command, args []string) {
101+
tlsCaCertFile = os.ExpandEnv(tlsCaCertFile)
102+
tlsCertFile = os.ExpandEnv(tlsCertFile)
103+
tlsKeyFile = os.ExpandEnv(tlsKeyFile)
104+
},
98105
PersistentPostRun: func(cmd *cobra.Command, args []string) {
99106
teardown()
100107
},
@@ -120,21 +127,21 @@ func newRootCmd(out io.Writer) *cobra.Command {
120127
newVerifyCmd(out),
121128

122129
// release commands
123-
newDeleteCmd(nil, out),
124-
newGetCmd(nil, out),
125-
newHistoryCmd(nil, out),
126-
newInstallCmd(nil, out),
127-
newListCmd(nil, out),
128-
newRollbackCmd(nil, out),
129-
newStatusCmd(nil, out),
130-
newUpgradeCmd(nil, out),
130+
addFlagsTLS(newDeleteCmd(nil, out)),
131+
addFlagsTLS(newGetCmd(nil, out)),
132+
addFlagsTLS(newHistoryCmd(nil, out)),
133+
addFlagsTLS(newInstallCmd(nil, out)),
134+
addFlagsTLS(newListCmd(nil, out)),
135+
addFlagsTLS(newRollbackCmd(nil, out)),
136+
addFlagsTLS(newStatusCmd(nil, out)),
137+
addFlagsTLS(newUpgradeCmd(nil, out)),
131138

132139
newCompletionCmd(out),
133140
newHomeCmd(out),
134141
newInitCmd(out),
135-
newResetCmd(nil, out),
136-
newVersionCmd(nil, out),
137-
newReleaseTestCmd(nil, out),
142+
addFlagsTLS(newResetCmd(nil, out)),
143+
addFlagsTLS(newVersionCmd(nil, out)),
144+
addFlagsTLS(newReleaseTestCmd(nil, out)),
138145

139146
// Hidden documentation generator command: 'helm docs'
140147
newDocsCmd(out),
@@ -229,7 +236,9 @@ func defaultHelmHome() string {
229236
}
230237

231238
func homePath() string {
232-
return os.ExpandEnv(helmHome)
239+
s := os.ExpandEnv(helmHome)
240+
os.Setenv(homeEnvVar, s)
241+
return s
233242
}
234243

235244
func defaultHelmHost() string {
@@ -262,3 +271,49 @@ func getKubeClient(context string) (*restclient.Config, *internalclientset.Clien
262271
func getKubeCmd(context string) *kube.Client {
263272
return kube.New(kube.GetConfig(context))
264273
}
274+
275+
// ensureHelmClient returns a new helm client impl. if h is not nil.
276+
func ensureHelmClient(h helm.Interface) helm.Interface {
277+
if h != nil {
278+
return h
279+
}
280+
return newClient()
281+
}
282+
283+
func newClient() helm.Interface {
284+
options := []helm.Option{helm.Host(tillerHost)}
285+
286+
if tlsVerify || tlsEnable {
287+
tlsopts := tlsutil.Options{KeyFile: tlsKeyFile, CertFile: tlsCertFile, InsecureSkipVerify: true}
288+
if tlsVerify {
289+
tlsopts.CaCertFile = tlsCaCertFile
290+
tlsopts.InsecureSkipVerify = false
291+
}
292+
tlscfg, err := tlsutil.ClientConfig(tlsopts)
293+
if err != nil {
294+
fmt.Fprintln(os.Stderr, err)
295+
os.Exit(2)
296+
}
297+
options = append(options, helm.WithTLS(tlscfg))
298+
}
299+
return helm.NewClient(options...)
300+
}
301+
302+
// addFlagsTLS adds the flags for supporting client side TLS to the
303+
// helm command (only those that invoke communicate to Tiller.)
304+
func addFlagsTLS(cmd *cobra.Command) *cobra.Command {
305+
// defaults
306+
var (
307+
tlsCaCertDefault = "$HELM_HOME/ca.pem"
308+
tlsCertDefault = "$HELM_HOME/cert.pem"
309+
tlsKeyDefault = "$HELM_HOME/key.pem"
310+
)
311+
312+
// add flags
313+
cmd.Flags().StringVar(&tlsCaCertFile, "tls-ca-cert", tlsCaCertDefault, "path to TLS CA certificate file")
314+
cmd.Flags().StringVar(&tlsCertFile, "tls-cert", tlsCertDefault, "path to TLS certificate file")
315+
cmd.Flags().StringVar(&tlsKeyFile, "tls-key", tlsKeyDefault, "path to TLS key file")
316+
cmd.Flags().BoolVar(&tlsVerify, "tls-verify", false, "enable TLS for request and verify remote")
317+
cmd.Flags().BoolVar(&tlsEnable, "tls", false, "enable TLS for request")
318+
return cmd
319+
}

cmd/helm/init.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,11 @@ func newInitCmd(out io.Writer) *cobra.Command {
102102
f.BoolVar(&i.dryRun, "dry-run", false, "do not install local or remote")
103103
f.BoolVar(&i.skipRefresh, "skip-refresh", false, "do not refresh (download) the local repository cache")
104104

105-
// f.BoolVar(&tlsEnable, "tiller-tls", false, "install tiller with TLS enabled")
106-
// f.BoolVar(&tlsVerify, "tiller-tls-verify", false, "install tiller with TLS enabled and to verify remote certificates")
107-
// f.StringVar(&tlsKeyFile, "tiller-tls-key", "", "path to TLS key file to install with tiller")
108-
// f.StringVar(&tlsCertFile, "tiller-tls-cert", "", "path to TLS certificate file to install with tiller")
109-
// f.StringVar(&tlsCaCertFile, "tls-ca-cert", "", "path to CA root certificate")
105+
f.BoolVar(&tlsEnable, "tiller-tls", false, "install tiller with TLS enabled")
106+
f.BoolVar(&tlsVerify, "tiller-tls-verify", false, "install tiller with TLS enabled and to verify remote certificates")
107+
f.StringVar(&tlsKeyFile, "tiller-tls-key", "", "path to TLS key file to install with tiller")
108+
f.StringVar(&tlsCertFile, "tiller-tls-cert", "", "path to TLS certificate file to install with tiller")
109+
f.StringVar(&tlsCaCertFile, "tls-ca-cert", "", "path to CA root certificate")
110110

111111
return cmd
112112
}

cmd/tiller/tiller.go

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,42 @@ limitations under the License.
1717
package main // import "k8s.io/helm/cmd/tiller"
1818

1919
import (
20+
"crypto/tls"
2021
"fmt"
2122
"io/ioutil"
2223
"log"
2324
"net"
2425
"net/http"
2526
"os"
27+
"path/filepath"
2628
"strings"
2729

2830
"github.com/spf13/cobra"
2931

32+
"google.golang.org/grpc"
33+
"google.golang.org/grpc/credentials"
34+
3035
"k8s.io/helm/pkg/kube"
3136
"k8s.io/helm/pkg/proto/hapi/services"
3237
"k8s.io/helm/pkg/storage"
3338
"k8s.io/helm/pkg/storage/driver"
3439
"k8s.io/helm/pkg/tiller"
3540
"k8s.io/helm/pkg/tiller/environment"
41+
"k8s.io/helm/pkg/tlsutil"
3642
"k8s.io/helm/pkg/version"
3743
)
3844

45+
const (
46+
// tlsEnableEnvVar names the environment variable that enables TLS.
47+
tlsEnableEnvVar = "TILLER_TLS_ENABLE"
48+
// tlsVerifyEnvVar names the environment variable that enables
49+
// TLS, as well as certificate verification of the remote.
50+
tlsVerifyEnvVar = "TILLER_TLS_VERIFY"
51+
// tlsCertsEnvVar names the environment variable that points to
52+
// the directory where Tiller's TLS certificates are located.
53+
tlsCertsEnvVar = "TILLER_TLS_CERTS"
54+
)
55+
3956
const (
4057
storageMemory = "memory"
4158
storageConfigMap = "configmap"
@@ -44,7 +61,7 @@ const (
4461
// rootServer is the root gRPC server.
4562
//
4663
// Each gRPC service registers itself to this server during init().
47-
var rootServer = tiller.NewServer()
64+
var rootServer *grpc.Server
4865

4966
// env is the default environment.
5067
//
@@ -59,6 +76,14 @@ var (
5976
store = storageConfigMap
6077
)
6178

79+
var (
80+
tlsEnable bool
81+
tlsVerify bool
82+
keyFile string
83+
certFile string
84+
caCertFile string
85+
)
86+
6287
const globalUsage = `The Kubernetes Helm server.
6388
6489
Tiller is the server for Helm. It provides in-cluster resource management.
@@ -83,6 +108,12 @@ func main() {
83108
p.StringVar(&store, "storage", storageConfigMap, "storage driver to use. One of 'configmap' or 'memory'")
84109
p.BoolVar(&enableTracing, "trace", false, "enable rpc tracing")
85110

111+
p.BoolVar(&tlsEnable, "tls", tlsEnableEnvVarDefault(), "enable TLS")
112+
p.BoolVar(&tlsVerify, "tls-verify", tlsVerifyEnvVarDefault(), "enable TLS and verify remote certificate")
113+
p.StringVar(&keyFile, "tls-key", tlsDefaultsFromEnv("tls-key"), "path to TLS private key file")
114+
p.StringVar(&certFile, "tls-cert", tlsDefaultsFromEnv("tls-cert"), "path to TLS certificate file")
115+
p.StringVar(&caCertFile, "tls-ca-cert", tlsDefaultsFromEnv("tls-ca-cert"), "trust certificates signed by this CA")
116+
86117
if err := rootCommand.Execute(); err != nil {
87118
fmt.Fprint(os.Stderr, err)
88119
os.Exit(1)
@@ -103,13 +134,33 @@ func start(c *cobra.Command, args []string) {
103134
env.Releases = storage.Init(driver.NewConfigMaps(clientset.Core().ConfigMaps(namespace())))
104135
}
105136

137+
if tlsEnable || tlsVerify {
138+
opts := tlsutil.Options{CertFile: certFile, KeyFile: keyFile}
139+
if tlsVerify {
140+
opts.CaCertFile = caCertFile
141+
}
142+
143+
}
144+
145+
var opts []grpc.ServerOption
146+
if tlsEnable || tlsVerify {
147+
cfg, err := tlsutil.ServerConfig(tlsOptions())
148+
if err != nil {
149+
fmt.Fprintf(os.Stderr, "Could not create server TLS configuration: %v\n", err)
150+
os.Exit(1)
151+
}
152+
opts = append(opts, grpc.Creds(credentials.NewTLS(cfg)))
153+
}
154+
155+
rootServer = tiller.NewServer(opts...)
156+
106157
lstn, err := net.Listen("tcp", grpcAddr)
107158
if err != nil {
108159
fmt.Fprintf(os.Stderr, "Server died: %s\n", err)
109160
os.Exit(1)
110161
}
111162

112-
fmt.Printf("Starting Tiller %s\n", version.GetVersion())
163+
fmt.Printf("Starting Tiller %s (tls=%t)\n", version.GetVersion(), tlsEnable || tlsVerify)
113164
fmt.Printf("GRPC listening on %s\n", grpcAddr)
114165
fmt.Printf("Probes listening on %s\n", probeAddr)
115166
fmt.Printf("Storage driver is %s\n", env.Releases.Name())
@@ -159,3 +210,27 @@ func namespace() string {
159210

160211
return environment.DefaultTillerNamespace
161212
}
213+
214+
func tlsOptions() tlsutil.Options {
215+
opts := tlsutil.Options{CertFile: certFile, KeyFile: keyFile}
216+
if tlsVerify {
217+
opts.CaCertFile = caCertFile
218+
opts.ClientAuth = tls.RequireAndVerifyClientCert
219+
}
220+
return opts
221+
}
222+
223+
func tlsDefaultsFromEnv(name string) (value string) {
224+
switch certsDir := os.Getenv(tlsCertsEnvVar); name {
225+
case "tls-key":
226+
return filepath.Join(certsDir, "tls.key")
227+
case "tls-cert":
228+
return filepath.Join(certsDir, "tls.crt")
229+
case "tls-ca-cert":
230+
return filepath.Join(certsDir, "ca.crt")
231+
}
232+
return ""
233+
}
234+
235+
func tlsEnableEnvVarDefault() bool { return os.Getenv(tlsEnableEnvVar) != "" }
236+
func tlsVerifyEnvVarDefault() bool { return os.Getenv(tlsVerifyEnvVar) != "" }

0 commit comments

Comments
 (0)