From 40ac4bcd27ba2a0c8a0763c11348e78567d8281c Mon Sep 17 00:00:00 2001 From: Steven Chung Date: Wed, 31 Jul 2019 21:29:21 -0400 Subject: [PATCH] patch velero to handle self-signed certs on client you'll get this error otherwise: x509: certificate signed by unknown authority --- pkg/cmd/cli/backup/describe.go | 8 +++++--- pkg/cmd/cli/backup/download.go | 14 ++++++++------ pkg/cmd/cli/backup/logs.go | 4 +++- pkg/cmd/cli/restore/describe.go | 8 +++++--- pkg/cmd/cli/restore/logs.go | 4 +++- pkg/cmd/util/downloadrequest/downloadrequest.go | 15 ++++++++++++++- .../util/downloadrequest/downloadrequest_test.go | 2 +- pkg/cmd/util/output/backup_describer.go | 7 ++++--- pkg/cmd/util/output/restore_describer.go | 8 ++++---- 9 files changed, 47 insertions(+), 23 deletions(-) diff --git a/pkg/cmd/cli/backup/describe.go b/pkg/cmd/cli/backup/describe.go index ecc040d458..2b9080254b 100644 --- a/pkg/cmd/cli/backup/describe.go +++ b/pkg/cmd/cli/backup/describe.go @@ -33,8 +33,9 @@ import ( func NewDescribeCommand(f client.Factory, use string) *cobra.Command { var ( - listOptions metav1.ListOptions - details bool + listOptions metav1.ListOptions + details bool + insecureSkipVerify bool ) c := &cobra.Command{ @@ -71,7 +72,7 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command { fmt.Fprintf(os.Stderr, "error getting PodVolumeBackups for backup %s: %v\n", backup.Name, err) } - s := output.DescribeBackup(&backup, deleteRequestList.Items, podVolumeBackupList.Items, details, veleroClient) + s := output.DescribeBackup(&backup, deleteRequestList.Items, podVolumeBackupList.Items, details, veleroClient, insecureSkipVerify) if first { first = false fmt.Print(s) @@ -85,6 +86,7 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command { c.Flags().StringVarP(&listOptions.LabelSelector, "selector", "l", listOptions.LabelSelector, "only show items matching this label selector") c.Flags().BoolVar(&details, "details", details, "display additional detail in the command output") + c.Flags().BoolVar(&insecureSkipVerify, "insecureskipverify", insecureSkipVerify, "accept any TLS certificate presented by the storage service") return c } diff --git a/pkg/cmd/cli/backup/download.go b/pkg/cmd/cli/backup/download.go index e1d99e50b7..8dff5c3390 100644 --- a/pkg/cmd/cli/backup/download.go +++ b/pkg/cmd/cli/backup/download.go @@ -52,11 +52,12 @@ func NewDownloadCommand(f client.Factory) *cobra.Command { } type DownloadOptions struct { - Name string - Output string - Force bool - Timeout time.Duration - writeOptions int + Name string + Output string + Force bool + Timeout time.Duration + InsecureSkipVerify bool + writeOptions int } func NewDownloadOptions() *DownloadOptions { @@ -69,6 +70,7 @@ func (o *DownloadOptions) BindFlags(flags *pflag.FlagSet) { flags.StringVarP(&o.Output, "output", "o", o.Output, "path to output file. Defaults to -data.tar.gz in the current directory") flags.BoolVar(&o.Force, "force", o.Force, "forces the download and will overwrite file if it exists already") flags.DurationVar(&o.Timeout, "timeout", o.Timeout, "maximum time to wait to process download request") + flags.BoolVar(&o.InsecureSkipVerify, "insecureskipverify", o.InsecureSkipVerify, "accept any TLS certificate presented by the storage service") } func (o *DownloadOptions) Validate(c *cobra.Command, args []string, f client.Factory) error { @@ -111,7 +113,7 @@ func (o *DownloadOptions) Run(c *cobra.Command, f client.Factory) error { } defer backupDest.Close() - err = downloadrequest.Stream(veleroClient.VeleroV1(), f.Namespace(), o.Name, v1.DownloadTargetKindBackupContents, backupDest, o.Timeout) + err = downloadrequest.Stream(veleroClient.VeleroV1(), f.Namespace(), o.Name, v1.DownloadTargetKindBackupContents, backupDest, o.Timeout, o.InsecureSkipVerify) if err != nil { os.Remove(o.Output) cmd.CheckError(err) diff --git a/pkg/cmd/cli/backup/logs.go b/pkg/cmd/cli/backup/logs.go index 16753536da..a7bed08362 100644 --- a/pkg/cmd/cli/backup/logs.go +++ b/pkg/cmd/cli/backup/logs.go @@ -32,6 +32,7 @@ import ( func NewLogsCommand(f client.Factory) *cobra.Command { timeout := time.Minute + insecureSkipVerify := false c := &cobra.Command{ Use: "logs BACKUP", @@ -58,12 +59,13 @@ func NewLogsCommand(f client.Factory) *cobra.Command { "until the backup has a phase of Completed or Failed and try again.", backupName) } - err = downloadrequest.Stream(veleroClient.VeleroV1(), f.Namespace(), backupName, v1.DownloadTargetKindBackupLog, os.Stdout, timeout) + err = downloadrequest.Stream(veleroClient.VeleroV1(), f.Namespace(), backupName, v1.DownloadTargetKindBackupLog, os.Stdout, timeout, insecureSkipVerify) cmd.CheckError(err) }, } c.Flags().DurationVar(&timeout, "timeout", timeout, "how long to wait to receive logs") + c.Flags().BoolVar(&insecureSkipVerify, "insecureskipverify", insecureSkipVerify, "accept any TLS certificate presented by the storage service") return c } diff --git a/pkg/cmd/cli/restore/describe.go b/pkg/cmd/cli/restore/describe.go index e58f1e1468..ff20df5e3d 100644 --- a/pkg/cmd/cli/restore/describe.go +++ b/pkg/cmd/cli/restore/describe.go @@ -32,8 +32,9 @@ import ( func NewDescribeCommand(f client.Factory, use string) *cobra.Command { var ( - listOptions metav1.ListOptions - details bool + listOptions metav1.ListOptions + details bool + insecureSkipVerify bool ) c := &cobra.Command{ @@ -64,7 +65,7 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command { fmt.Fprintf(os.Stderr, "error getting PodVolumeRestores for restore %s: %v\n", restore.Name, err) } - s := output.DescribeRestore(&restore, podvolumeRestoreList.Items, details, veleroClient) + s := output.DescribeRestore(&restore, podvolumeRestoreList.Items, details, veleroClient, insecureSkipVerify) if first { first = false fmt.Print(s) @@ -78,6 +79,7 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command { c.Flags().StringVarP(&listOptions.LabelSelector, "selector", "l", listOptions.LabelSelector, "only show items matching this label selector") c.Flags().BoolVar(&details, "details", details, "display additional detail in the command output") + c.Flags().BoolVar(&insecureSkipVerify, "insecureskipverify", insecureSkipVerify, "accept any TLS certificate presented by the storage service") return c } diff --git a/pkg/cmd/cli/restore/logs.go b/pkg/cmd/cli/restore/logs.go index 2b6f6a14e7..9432a7a4e1 100644 --- a/pkg/cmd/cli/restore/logs.go +++ b/pkg/cmd/cli/restore/logs.go @@ -32,6 +32,7 @@ import ( func NewLogsCommand(f client.Factory) *cobra.Command { timeout := time.Minute + insecureSkipVerify := false c := &cobra.Command{ Use: "logs RESTORE", @@ -58,12 +59,13 @@ func NewLogsCommand(f client.Factory) *cobra.Command { "until the restore has a phase of Completed or Failed and try again.", restoreName) } - err = downloadrequest.Stream(veleroClient.VeleroV1(), f.Namespace(), restoreName, v1.DownloadTargetKindRestoreLog, os.Stdout, timeout) + err = downloadrequest.Stream(veleroClient.VeleroV1(), f.Namespace(), restoreName, v1.DownloadTargetKindRestoreLog, os.Stdout, timeout, insecureSkipVerify) cmd.CheckError(err) }, } c.Flags().DurationVar(&timeout, "timeout", timeout, "how long to wait to receive logs") + c.Flags().BoolVar(&insecureSkipVerify, "insecureskipverify", insecureSkipVerify, "accept any TLS certificate presented by the storage service") return c } diff --git a/pkg/cmd/util/downloadrequest/downloadrequest.go b/pkg/cmd/util/downloadrequest/downloadrequest.go index c5eb61a232..e62765f9b2 100644 --- a/pkg/cmd/util/downloadrequest/downloadrequest.go +++ b/pkg/cmd/util/downloadrequest/downloadrequest.go @@ -18,10 +18,13 @@ package downloadrequest import ( "compress/gzip" + "crypto/tls" + "crypto/x509" "fmt" "io" "io/ioutil" "net/http" + "net/url" "time" "github.com/pkg/errors" @@ -32,7 +35,7 @@ import ( velerov1client "github.com/heptio/velero/pkg/generated/clientset/versioned/typed/velero/v1" ) -func Stream(client velerov1client.DownloadRequestsGetter, namespace, name string, kind v1.DownloadTargetKind, w io.Writer, timeout time.Duration) error { +func Stream(client velerov1client.DownloadRequestsGetter, namespace, name string, kind v1.DownloadTargetKind, w io.Writer, timeout time.Duration, insecureSkipVerify bool) error { req := &v1.DownloadRequest{ ObjectMeta: metav1.ObjectMeta{ Namespace: namespace, @@ -101,6 +104,11 @@ Loop: } httpClient := new(http.Client) + if insecureSkipVerify { + httpClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + } httpReq, err := http.NewRequest("GET", req.Status.DownloadURL, nil) if err != nil { @@ -114,6 +122,11 @@ Loop: resp, err := httpClient.Do(httpReq) if err != nil { + if urlErr, ok := err.(*url.Error); ok { + if _, ok := urlErr.Err.(x509.UnknownAuthorityError); ok { + return fmt.Errorf(err.Error() + "\n\nThe --insecureskipverify flag can also be used to accept any TLS certificate for the download, but it is susceptible to man-in-the-middle attacks.") + } + } return err } defer resp.Body.Close() diff --git a/pkg/cmd/util/downloadrequest/downloadrequest_test.go b/pkg/cmd/util/downloadrequest/downloadrequest_test.go index 278b54c695..49094a5c24 100644 --- a/pkg/cmd/util/downloadrequest/downloadrequest_test.go +++ b/pkg/cmd/util/downloadrequest/downloadrequest_test.go @@ -151,7 +151,7 @@ func TestStream(t *testing.T) { output := new(bytes.Buffer) errCh := make(chan error) go func() { - err := Stream(client.VeleroV1(), "namespace", "name", test.kind, output, timeout) + err := Stream(client.VeleroV1(), "namespace", "name", test.kind, output, timeout, false) errCh <- err }() diff --git a/pkg/cmd/util/output/backup_describer.go b/pkg/cmd/util/output/backup_describer.go index 0bfdb2be5c..aa48223f7c 100644 --- a/pkg/cmd/util/output/backup_describer.go +++ b/pkg/cmd/util/output/backup_describer.go @@ -38,6 +38,7 @@ func DescribeBackup( podVolumeBackups []velerov1api.PodVolumeBackup, details bool, veleroClient clientset.Interface, + insecureSkipVerify bool, ) string { return Describe(func(d *Describer) { d.DescribeMetadata(backup.ObjectMeta) @@ -74,7 +75,7 @@ func DescribeBackup( DescribeBackupSpec(d, backup.Spec) d.Println() - DescribeBackupStatus(d, backup, details, veleroClient) + DescribeBackupStatus(d, backup, details, veleroClient, insecureSkipVerify) if len(deleteRequests) > 0 { d.Println() @@ -211,7 +212,7 @@ func DescribeBackupSpec(d *Describer, spec velerov1api.BackupSpec) { } // DescribeBackupStatus describes a backup status in human-readable format. -func DescribeBackupStatus(d *Describer, backup *velerov1api.Backup, details bool, veleroClient clientset.Interface) { +func DescribeBackupStatus(d *Describer, backup *velerov1api.Backup, details bool, veleroClient clientset.Interface, insecureSkipVerify bool) { status := backup.Status d.Printf("Backup Format Version:\t%d\n", status.Version) @@ -240,7 +241,7 @@ func DescribeBackupStatus(d *Describer, backup *velerov1api.Backup, details bool } buf := new(bytes.Buffer) - if err := downloadrequest.Stream(veleroClient.VeleroV1(), backup.Namespace, backup.Name, velerov1api.DownloadTargetKindBackupVolumeSnapshots, buf, downloadRequestTimeout); err != nil { + if err := downloadrequest.Stream(veleroClient.VeleroV1(), backup.Namespace, backup.Name, velerov1api.DownloadTargetKindBackupVolumeSnapshots, buf, downloadRequestTimeout, insecureSkipVerify); err != nil { d.Printf("Persistent Volumes:\t\n", err) return } diff --git a/pkg/cmd/util/output/restore_describer.go b/pkg/cmd/util/output/restore_describer.go index dada2aca4d..6e2454f6d6 100644 --- a/pkg/cmd/util/output/restore_describer.go +++ b/pkg/cmd/util/output/restore_describer.go @@ -31,7 +31,7 @@ import ( pkgrestore "github.com/heptio/velero/pkg/restore" ) -func DescribeRestore(restore *v1.Restore, podVolumeRestores []v1.PodVolumeRestore, details bool, veleroClient clientset.Interface) string { +func DescribeRestore(restore *v1.Restore, podVolumeRestores []v1.PodVolumeRestore, details bool, veleroClient clientset.Interface, insecureSkipVerify bool) string { return Describe(func(d *Describer) { d.DescribeMetadata(restore.ObjectMeta) @@ -56,7 +56,7 @@ func DescribeRestore(restore *v1.Restore, podVolumeRestores []v1.PodVolumeRestor } } - describeRestoreResults(d, restore, veleroClient) + describeRestoreResults(d, restore, veleroClient, insecureSkipVerify) d.Println() d.Printf("Backup:\t%s\n", restore.Spec.BackupName) @@ -114,7 +114,7 @@ func DescribeRestore(restore *v1.Restore, podVolumeRestores []v1.PodVolumeRestor }) } -func describeRestoreResults(d *Describer, restore *v1.Restore, veleroClient clientset.Interface) { +func describeRestoreResults(d *Describer, restore *v1.Restore, veleroClient clientset.Interface, insecureSkipVerify bool) { if restore.Status.Warnings == 0 && restore.Status.Errors == 0 { return } @@ -122,7 +122,7 @@ func describeRestoreResults(d *Describer, restore *v1.Restore, veleroClient clie var buf bytes.Buffer var resultMap map[string]pkgrestore.Result - if err := downloadrequest.Stream(veleroClient.VeleroV1(), restore.Namespace, restore.Name, v1.DownloadTargetKindRestoreResults, &buf, downloadRequestTimeout); err != nil { + if err := downloadrequest.Stream(veleroClient.VeleroV1(), restore.Namespace, restore.Name, v1.DownloadTargetKindRestoreResults, &buf, downloadRequestTimeout, insecureSkipVerify); err != nil { d.Printf("Warnings:\t\n\nErrors:\t\n", err, err) return }