From aa8cbe8ae3be7b8fc2520bf3735e601b77fe9ad0 Mon Sep 17 00:00:00 2001 From: Yuce Tekol Date: Wed, 11 Oct 2017 08:30:11 +0300 Subject: [PATCH] Add TLS support for commands --- cmd/backup.go | 4 ++-- cmd/bench.go | 1 + cmd/export.go | 1 + cmd/import.go | 1 + cmd/restore.go | 1 + ctl/backup.go | 10 +++++++++- ctl/bench.go | 12 +++++++++++- ctl/common.go | 42 ++++++++++++++++++++++++++++++++++++++++++ ctl/export.go | 12 +++++++++++- ctl/import.go | 12 +++++++++++- ctl/restore.go | 12 +++++++++++- ctl/server.go | 4 +--- 12 files changed, 102 insertions(+), 10 deletions(-) create mode 100644 ctl/common.go diff --git a/cmd/backup.go b/cmd/backup.go index 1dd3a50d6..4bbbf70c2 100644 --- a/cmd/backup.go +++ b/cmd/backup.go @@ -19,9 +19,8 @@ import ( "io" "os" - "github.com/spf13/cobra" - "github.com/pilosa/pilosa/ctl" + "github.com/spf13/cobra" ) var Backuper *ctl.BackupCommand @@ -47,6 +46,7 @@ Backs up the view from across the cluster into a single file. flags.StringVarP(&Backuper.Frame, "frame", "f", "", "Frame to backup.") flags.StringVarP(&Backuper.View, "view", "v", "", "View to backup.") flags.StringVarP(&Backuper.Path, "output-file", "o", "", "File to write backup to - default stdout") + ctl.SetTLSConfig(flags, &Backuper.TLS.CertificatePath, &Backuper.TLS.CertificateKeyPath, &Backuper.TLS.SkipVerify) return backupCmd } diff --git a/cmd/bench.go b/cmd/bench.go index 0ea32d22a..d4b2b8580 100644 --- a/cmd/bench.go +++ b/cmd/bench.go @@ -47,6 +47,7 @@ Executes a benchmark for a given operation against the index. flags.StringVarP(&Bencher.Frame, "frame", "f", "", "Frame to benchmark.") flags.StringVarP(&Bencher.Op, "operation", "o", "set-bit", "Operation to perform: choose from [set-bit]") flags.IntVarP(&Bencher.N, "num", "n", 0, "Number of operations to perform.") + ctl.SetTLSConfig(flags, &Bencher.TLS.CertificatePath, &Bencher.TLS.CertificateKeyPath, &Bencher.TLS.SkipVerify) return benchCmd } diff --git a/cmd/export.go b/cmd/export.go index e55f84e59..c5907fbea 100644 --- a/cmd/export.go +++ b/cmd/export.go @@ -55,6 +55,7 @@ The file does not contain any headers. flags.StringVarP(&Exporter.Frame, "frame", "f", "", "Frame to export") flags.StringVarP(&Exporter.View, "view", "v", "standard", "View to export - default standard") flags.StringVarP(&Exporter.Path, "output-file", "o", "", "File to write export to - default stdout") + ctl.SetTLSConfig(flags, &Exporter.TLS.CertificatePath, &Exporter.TLS.CertificateKeyPath, &Exporter.TLS.SkipVerify) return exportCmd } diff --git a/cmd/import.go b/cmd/import.go index 6832480a3..f998bd4b3 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -65,6 +65,7 @@ omitted. If it is present then its format should be YYYY-MM-DDTHH:MM. flags.BoolVar(&Importer.FrameOptions.RangeEnabled, "frame-range-enabled", false, "Enabled range encoded frame") flags.StringVar(&Importer.FrameOptions.CacheType, "frame-cache-type", pilosa.CacheTypeRanked, "Cache type for the frame; valid values: none, lru, ranked") flags.Uint32Var(&Importer.FrameOptions.CacheSize, "frame-cache-size", 50000, "Cache size for the frame") + ctl.SetTLSConfig(flags, &Importer.TLS.CertificatePath, &Importer.TLS.CertificateKeyPath, &Importer.TLS.SkipVerify) return importCmd } diff --git a/cmd/restore.go b/cmd/restore.go index 80f0bdd74..e5169be12 100644 --- a/cmd/restore.go +++ b/cmd/restore.go @@ -48,6 +48,7 @@ Restores a view to the cluster from a backup file. flags.StringVarP(&Restorer.Frame, "frame", "f", "", "Frame to restore into.") flags.StringVarP(&Restorer.View, "view", "v", "", "View to restore into.") flags.StringVarP(&Restorer.Path, "input-file", "d", "", "File to restore data from.") + ctl.SetTLSConfig(flags, &Restorer.TLS.CertificatePath, &Restorer.TLS.CertificateKeyPath, &Restorer.TLS.SkipVerify) return restoreCmd } diff --git a/ctl/backup.go b/ctl/backup.go index 784011b05..8e725b41e 100644 --- a/ctl/backup.go +++ b/ctl/backup.go @@ -57,7 +57,7 @@ func (cmd *BackupCommand) Run(ctx context.Context) error { } // Create a client to the server. - client, err := pilosa.NewClient(cmd.Host, nil) + client, err := CommandClient(cmd) if err != nil { return err } @@ -83,3 +83,11 @@ func (cmd *BackupCommand) Run(ctx context.Context) error { return nil } + +func (cmd *BackupCommand) TLSHost() string { + return cmd.Host +} + +func (cmd *BackupCommand) TLSConfiguration() pilosa.TLSConfig { + return cmd.TLS +} diff --git a/ctl/bench.go b/ctl/bench.go index 96324e019..24e6e7658 100644 --- a/ctl/bench.go +++ b/ctl/bench.go @@ -40,6 +40,8 @@ type BenchCommand struct { // Standard input/output *pilosa.CmdIO + + TLS pilosa.TLSConfig } // NewBenchCommand returns a new instance of BenchCommand. @@ -52,7 +54,7 @@ func NewBenchCommand(stdin io.Reader, stdout, stderr io.Writer) *BenchCommand { // Run executes the bench command. func (cmd *BenchCommand) Run(ctx context.Context) error { // Create a client to the server. - client, err := pilosa.NewClient(cmd.Host, nil) + client, err := CommandClient(cmd) if err != nil { return err } @@ -100,3 +102,11 @@ func (cmd *BenchCommand) runSetBit(ctx context.Context, client *pilosa.Client) e return nil } + +func (cmd *BenchCommand) TLSHost() string { + return cmd.Host +} + +func (cmd *BenchCommand) TLSConfiguration() pilosa.TLSConfig { + return cmd.TLS +} diff --git a/ctl/common.go b/ctl/common.go new file mode 100644 index 000000000..975f19898 --- /dev/null +++ b/ctl/common.go @@ -0,0 +1,42 @@ +package ctl + +import ( + "crypto/tls" + "github.com/pilosa/pilosa" + "github.com/spf13/pflag" +) + +// CommandWithTLSSupport is the interface for commands which has TLS settings +type CommandWithTLSSupport interface { + TLSHost() string + TLSConfiguration() pilosa.TLSConfig +} + +// SetTLSConfig creates common TLS flags +func SetTLSConfig(flags *pflag.FlagSet, certificatePath *string, certificateKeyPath *string, skipVerify *bool) { + flags.StringVarP(certificatePath, "tls.certificate", "", "", "TLS certificate path (usually has the .crt or .pem extension") + flags.StringVarP(certificateKeyPath, "tls.key", "", "", "TLS certificate key path (usually has the .key extension") + flags.BoolVarP(skipVerify, "tls.skip-verify", "", false, "Skip TLS certificate verification (not secure)") +} + +// CommandClient returns a pilosa.Client for the command +func CommandClient(cmd CommandWithTLSSupport) (*pilosa.Client, error) { + tlsConfig := cmd.TLSConfiguration() + var clientOptions *pilosa.ClientOptions + if tlsConfig.CertificatePath != "" && tlsConfig.CertificateKeyPath != "" { + cert, err := tls.LoadX509KeyPair(tlsConfig.CertificatePath, tlsConfig.CertificateKeyPath) + if err != nil { + return nil, err + } + TLSConfig := &tls.Config{ + Certificates: []tls.Certificate{cert}, + InsecureSkipVerify: tlsConfig.SkipVerify, + } + clientOptions = &pilosa.ClientOptions{TLS: TLSConfig} + } + client, err := pilosa.NewClient(cmd.TLSHost(), clientOptions) + if err != nil { + return nil, err + } + return client, err +} diff --git a/ctl/export.go b/ctl/export.go index 4cfb5c963..84b91edec 100644 --- a/ctl/export.go +++ b/ctl/export.go @@ -37,6 +37,8 @@ type ExportCommand struct { // Standard input/output *pilosa.CmdIO + + TLS pilosa.TLSConfig } // NewExportCommand returns a new instance of ExportCommand. @@ -73,7 +75,7 @@ func (cmd *ExportCommand) Run(ctx context.Context) error { } // Create a client to the server. - client, err := pilosa.NewClient(cmd.Host, nil) + client, err := CommandClient(cmd) if err != nil { return err } @@ -107,3 +109,11 @@ func (cmd *ExportCommand) Run(ctx context.Context) error { return nil } + +func (cmd *ExportCommand) TLSHost() string { + return cmd.Host +} + +func (cmd *ExportCommand) TLSConfiguration() pilosa.TLSConfig { + return cmd.TLS +} diff --git a/ctl/import.go b/ctl/import.go index 0bf1d9727..e3eda260e 100644 --- a/ctl/import.go +++ b/ctl/import.go @@ -62,6 +62,8 @@ type ImportCommand struct { // Standard input/output *pilosa.CmdIO + + TLS pilosa.TLSConfig } // NewImportCommand returns a new instance of ImportCommand. @@ -86,7 +88,7 @@ func (cmd *ImportCommand) Run(ctx context.Context) error { return errors.New("path required") } // Create a client to the server. - client, err := pilosa.NewClient(cmd.Host, nil) + client, err := CommandClient(cmd) if err != nil { return err } @@ -338,3 +340,11 @@ func (cmd *ImportCommand) importFieldValues(ctx context.Context, vals []pilosa.F return nil } + +func (cmd *ImportCommand) TLSHost() string { + return cmd.Host +} + +func (cmd *ImportCommand) TLSConfiguration() pilosa.TLSConfig { + return cmd.TLS +} diff --git a/ctl/restore.go b/ctl/restore.go index 3c357a883..38528c2b5 100644 --- a/ctl/restore.go +++ b/ctl/restore.go @@ -38,6 +38,8 @@ type RestoreCommand struct { // Standard input/output *pilosa.CmdIO + + TLS pilosa.TLSConfig } // NewRestoreCommand returns a new instance of RestoreCommand. @@ -55,7 +57,7 @@ func (cmd *RestoreCommand) Run(ctx context.Context) error { } // Create a client to the server. - client, err := pilosa.NewClient(cmd.Host, nil) + client, err := CommandClient(cmd) if err != nil { return err } @@ -74,3 +76,11 @@ func (cmd *RestoreCommand) Run(ctx context.Context) error { return nil } + +func (cmd *RestoreCommand) TLSHost() string { + return cmd.Host +} + +func (cmd *RestoreCommand) TLSConfiguration() pilosa.TLSConfig { + return cmd.TLS +} diff --git a/ctl/server.go b/ctl/server.go index 1c1711391..a0c080729 100644 --- a/ctl/server.go +++ b/ctl/server.go @@ -42,7 +42,5 @@ func BuildServerFlags(cmd *cobra.Command, srv *server.Command) { flags.StringVarP(&srv.Config.Metric.Service, "metric.service", "", "nop", "Default URI on which pilosa should listen.") flags.StringVarP(&srv.Config.Metric.Host, "metric.host", "", "", "Default URI to send metrics.") flags.DurationVarP((*time.Duration)(&srv.Config.Metric.PollInterval), "metric.poll-interval", "", time.Minute*0, "Polling interval metrics.") - flags.StringVarP(&srv.Config.TLS.CertificatePath, "tls.certificate", "", "", "TLS certificate path (usually has the .crt or .pem extension") - flags.StringVarP(&srv.Config.TLS.CertificateKeyPath, "tls.key", "", "", "TLS certificate key path (usually has the .key extension") - flags.BoolVarP(&srv.Config.TLS.SkipVerify, "tls.skip-verify", "", false, "Skip TLS certificate verification (not secure)") + SetTLSConfig(flags, &srv.Config.TLS.CertificatePath, &srv.Config.TLS.CertificateKeyPath, &srv.Config.TLS.SkipVerify) }