From 0865688c276d6ec79e8ca3b0ef1a4e7655148a0a Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Thu, 24 Mar 2016 16:29:33 -0700 Subject: [PATCH] etcdctlv3: support secure connection without key/cert --- etcdctlv3/command/ep_health_command.go | 4 +- etcdctlv3/command/global.go | 68 ++++++++++++++++++------ etcdctlv3/command/make_mirror_command.go | 19 +++++-- etcdctlv3/main.go | 2 + 4 files changed, 70 insertions(+), 23 deletions(-) diff --git a/etcdctlv3/command/ep_health_command.go b/etcdctlv3/command/ep_health_command.go index d5b4de446..2627f0c5c 100644 --- a/etcdctlv3/command/ep_health_command.go +++ b/etcdctlv3/command/ep_health_command.go @@ -41,11 +41,11 @@ func epHealthCommandFunc(cmd *cobra.Command, args []string) { ExitWithError(ExitError, err) } - cert, key, cacert := keyAndCertFromCmd(cmd) + sec := secureCfgFromCmd(cmd) dt := dialTimeoutFromCmd(cmd) cfgs := []*clientv3.Config{} for _, ep := range endpoints { - cfg, err := newClientCfg([]string{ep}, dt, cert, key, cacert) + cfg, err := newClientCfg([]string{ep}, dt, sec) if err != nil { ExitWithError(ExitBadArgs, err) } diff --git a/etcdctlv3/command/global.go b/etcdctlv3/command/global.go index 23f45beba..46d2b6b4d 100644 --- a/etcdctlv3/command/global.go +++ b/etcdctlv3/command/global.go @@ -15,6 +15,7 @@ package command import ( + "crypto/tls" "errors" "io" "io/ioutil" @@ -28,6 +29,7 @@ import ( // GlobalFlags are flags that defined globally // and are inherited to all sub-commands. type GlobalFlags struct { + Insecure bool Endpoints []string DialTimeout time.Duration @@ -37,6 +39,14 @@ type GlobalFlags struct { IsHex bool } +type secureCfg struct { + cert string + key string + cacert string + + insecureTransport bool +} + var display printer = &simplePrinter{} func mustClientFromCmd(cmd *cobra.Command) *clientv3.Client { @@ -45,13 +55,13 @@ func mustClientFromCmd(cmd *cobra.Command) *clientv3.Client { ExitWithError(ExitError, err) } dialTimeout := dialTimeoutFromCmd(cmd) - cert, key, cacert := keyAndCertFromCmd(cmd) + sec := secureCfgFromCmd(cmd) - return mustClient(endpoints, dialTimeout, cert, key, cacert) + return mustClient(endpoints, dialTimeout, sec) } -func mustClient(endpoints []string, dialTimeout time.Duration, cert, key, cacert string) *clientv3.Client { - cfg, err := newClientCfg(endpoints, dialTimeout, cert, key, cacert) +func mustClient(endpoints []string, dialTimeout time.Duration, scfg *secureCfg) *clientv3.Client { + cfg, err := newClientCfg(endpoints, dialTimeout, scfg) if err != nil { ExitWithError(ExitBadArgs, err) } @@ -64,24 +74,23 @@ func mustClient(endpoints []string, dialTimeout time.Duration, cert, key, cacert return client } -func newClientCfg(endpoints []string, dialTimeout time.Duration, cert, key, cacert string) (*clientv3.Config, error) { +func newClientCfg(endpoints []string, dialTimeout time.Duration, scfg *secureCfg) (*clientv3.Config, error) { // set tls if any one tls option set var cfgtls *transport.TLSInfo - tls := transport.TLSInfo{} - var file string - if cert != "" { - tls.CertFile = cert - cfgtls = &tls + tlsinfo := transport.TLSInfo{} + if scfg.cert != "" { + tlsinfo.CertFile = scfg.cert + cfgtls = &tlsinfo } - if key != "" { - tls.KeyFile = key - cfgtls = &tls + if scfg.key != "" { + tlsinfo.KeyFile = scfg.key + cfgtls = &tlsinfo } - if cacert != "" { - tls.CAFile = file - cfgtls = &tls + if scfg.cacert != "" { + tlsinfo.CAFile = scfg.cacert + cfgtls = &tlsinfo } cfg := &clientv3.Config{ @@ -95,6 +104,12 @@ func newClientCfg(endpoints []string, dialTimeout time.Duration, cert, key, cace } cfg.TLS = clientTLS } + // if key/cert is not given but user wants secure connection, we + // should still setup an empty tls configuration for gRPC to setup + // secure connection. + if cfg.TLS == nil && !scfg.insecureTransport { + cfg.TLS = &tls.Config{} + } return cfg, nil } @@ -118,6 +133,27 @@ func dialTimeoutFromCmd(cmd *cobra.Command) time.Duration { return dialTimeout } +func secureCfgFromCmd(cmd *cobra.Command) *secureCfg { + cert, key, cacert := keyAndCertFromCmd(cmd) + insecureTr := insecureTransportFromCmd(cmd) + + return &secureCfg{ + cert: cert, + key: key, + cacert: cacert, + + insecureTransport: insecureTr, + } +} + +func insecureTransportFromCmd(cmd *cobra.Command) bool { + insecureTr, err := cmd.Flags().GetBool("insecure-transport") + if err != nil { + ExitWithError(ExitError, err) + } + return insecureTr +} + func keyAndCertFromCmd(cmd *cobra.Command) (cert, key, cacert string) { var err error if cert, err = cmd.Flags().GetString("cert"); err != nil { diff --git a/etcdctlv3/command/make_mirror_command.go b/etcdctlv3/command/make_mirror_command.go index 37e9d6473..571ca3fc5 100644 --- a/etcdctlv3/command/make_mirror_command.go +++ b/etcdctlv3/command/make_mirror_command.go @@ -29,10 +29,11 @@ import ( ) var ( - mmcert string - mmkey string - mmcacert string - mmprefix string + mminsecureTr bool + mmcert string + mmkey string + mmcacert string + mmprefix string ) // NewMakeMirrorCommand returns the cobra command for "makeMirror". @@ -48,6 +49,8 @@ func NewMakeMirrorCommand() *cobra.Command { c.Flags().StringVar(&mmcert, "dest-cert", "", "identify secure client using this TLS certificate file for the destination cluster") c.Flags().StringVar(&mmkey, "dest-key", "", "identify secure client using this TLS key file") c.Flags().StringVar(&mmcacert, "dest-cacert", "", "verify certificates of TLS enabled secure servers using this CA bundle") + // TODO: secure by default when etcd enables secure gRPC by default. + c.Flags().BoolVar(&mminsecureTr, "dest-insecure-transport", true, "disable transport security for client connections") return c } @@ -58,8 +61,14 @@ func makeMirrorCommandFunc(cmd *cobra.Command, args []string) { } dialTimeout := dialTimeoutFromCmd(cmd) + sec := &secureCfg{ + cert: mmcert, + key: mmkey, + cacert: mmcacert, + insecureTransport: mminsecureTr, + } - dc := mustClient([]string{args[0]}, dialTimeout, mmcert, mmkey, mmcacert) + dc := mustClient([]string{args[0]}, dialTimeout, sec) c := mustClientFromCmd(cmd) err := makeMirror(context.TODO(), c, dc) diff --git a/etcdctlv3/main.go b/etcdctlv3/main.go index 985fc93a1..5f73f60e7 100644 --- a/etcdctlv3/main.go +++ b/etcdctlv3/main.go @@ -51,6 +51,8 @@ func init() { rootCmd.PersistentFlags().DurationVar(&globalFlags.DialTimeout, "dial-timeout", defaultDialTimeout, "dial timeout for client connections") + // TODO: secure by default when etcd enables secure gRPC by default. + rootCmd.PersistentFlags().BoolVar(&globalFlags.Insecure, "insecure-transport", true, "disable transport security for client connections") rootCmd.PersistentFlags().StringVar(&globalFlags.TLS.CertFile, "cert", "", "identify secure client using this TLS certificate file") rootCmd.PersistentFlags().StringVar(&globalFlags.TLS.KeyFile, "key", "", "identify secure client using this TLS key file") rootCmd.PersistentFlags().StringVar(&globalFlags.TLS.CAFile, "cacert", "", "verify certificates of TLS-enabled secure servers using this CA bundle")