From bf6f8bc708cda8ff46cf3f7f975401c8b6dbc794 Mon Sep 17 00:00:00 2001 From: tstromberg Date: Wed, 12 Feb 2020 13:31:17 -0800 Subject: [PATCH 1/3] Use SHA256 for Kubernetes release checksums --- pkg/minikube/machine/cache_binaries.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/pkg/minikube/machine/cache_binaries.go b/pkg/minikube/machine/cache_binaries.go index 86102647ff..05ad06a5c6 100644 --- a/pkg/minikube/machine/cache_binaries.go +++ b/pkg/minikube/machine/cache_binaries.go @@ -51,14 +51,14 @@ func CacheBinariesForBootstrapper(version string, clusterBootstrapper string) er return g.Wait() } -// KubernetesReleaseURL gets the location of a kubernetes client -func KubernetesReleaseURL(binaryName, version, osName, archName string) string { +// releaseURL gets the location of a Kubernetes binary +func releaseURL(binaryName, version, osName, archName string) string { return fmt.Sprintf("https://storage.googleapis.com/kubernetes-release/release/%s/bin/%s/%s/%s", version, osName, archName, binaryName) } -// KubernetesReleaseURLSHA1 gets the location of a kubernetes client checksum -func KubernetesReleaseURLSHA1(binaryName, version, osName, archName string) string { - return fmt.Sprintf("%s.sha1", KubernetesReleaseURL(binaryName, version, osName, archName)) +// checksumURL gets the location of a kubernetes client checksum +func checksumURL(binaryName, version, osName, archName string) string { + return fmt.Sprintf("%s.sha256", releaseURL(binaryName, version, osName, archName)) } // CacheBinary will cache a binary on the host @@ -66,7 +66,7 @@ func CacheBinary(binary, version, osName, archName string) (string, error) { targetDir := localpath.MakeMiniPath("cache", version) targetFilepath := path.Join(targetDir, binary) - url := KubernetesReleaseURL(binary, version, osName, archName) + url := releaseURL(binary, version, osName, archName) _, err := os.Stat(targetFilepath) // If it exists, do no verification and continue @@ -86,12 +86,14 @@ func CacheBinary(binary, version, osName, archName string) (string, error) { Mkdirs: download.MkdirAll, } - options.Checksum = KubernetesReleaseURLSHA1(binary, version, osName, archName) - options.ChecksumHash = crypto.SHA1 + options.Checksum = checksumURL(binary, version, osName, archName) + options.ChecksumHash = crypto.SHA256 + + glog.Infof("Downloading %s: options: %+v", url, options) out.T(out.FileDownload, "Downloading {{.name}} {{.version}}", out.V{"name": binary, "version": version}) if err := download.ToFile(url, targetFilepath, options); err != nil { - return "", errors.Wrapf(err, "Error downloading %s %s", binary, version) + return "", errors.Wrapf(err, url) } if osName == runtime.GOOS && archName == runtime.GOARCH { if err = os.Chmod(targetFilepath, 0755); err != nil { From 250e00564be91d428dfa4686fe3fac952816a741 Mon Sep 17 00:00:00 2001 From: tstromberg Date: Thu, 13 Feb 2020 14:57:03 -0800 Subject: [PATCH 2/3] Select the checksum algorithm based on Kubernetes version --- pkg/minikube/machine/cache_binaries.go | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/pkg/minikube/machine/cache_binaries.go b/pkg/minikube/machine/cache_binaries.go index 9f247a7995..70bb61fa48 100644 --- a/pkg/minikube/machine/cache_binaries.go +++ b/pkg/minikube/machine/cache_binaries.go @@ -23,6 +23,7 @@ import ( "path" "runtime" + "github.com/blang/semver" "github.com/golang/glog" "github.com/jimmidyson/go-download" "github.com/pkg/errors" @@ -56,13 +57,24 @@ func releaseURL(binaryName, version, osName, archName string) string { return fmt.Sprintf("https://storage.googleapis.com/kubernetes-release/release/%s/bin/%s/%s/%s", version, osName, archName, binaryName) } -// checksumURL gets the location of a kubernetes client checksum -func checksumURL(binaryName, version, osName, archName string) string { - return fmt.Sprintf("%s.sha256", releaseURL(binaryName, version, osName, archName)) +// checksumVerifier returns the binary checksum URL and hash method +func checksumVerifier(binaryName, version, osName, archName string) (string, crypto.Hash, error) { + binURL := releaseURL(binaryName, version, osName, archName) + + v, err := semver.Make(version[1:]) + if err != nil { + return "", 0, err + } + + if v.GTE(semver.MustParse("1.17.0")) { + return binURL + ".sha256", crypto.SHA256, nil + } + return binURL + ".sha1", crypto.SHA1, nil } // CacheBinary will cache a binary on the host func CacheBinary(binary, version, osName, archName string) (string, error) { + targetDir := localpath.MakeMiniPath("cache", osName, version) targetFilepath := path.Join(targetDir, binary) @@ -86,8 +98,12 @@ func CacheBinary(binary, version, osName, archName string) (string, error) { Mkdirs: download.MkdirAll, } - options.Checksum = checksumURL(binary, version, osName, archName) - options.ChecksumHash = crypto.SHA256 + ckURL, ckAlgo, err := checksumVerifier(binary, version, osName, archName) + if err != nil { + return "", errors.Wrap(err, "verifier") + } + options.Checksum = ckURL + options.ChecksumHash = ckAlgo glog.Infof("Downloading %s: options: %+v", url, options) From 9b1d2da4786f131bbbf038333ffcfd649409cde4 Mon Sep 17 00:00:00 2001 From: tstromberg Date: Thu, 13 Feb 2020 16:50:53 -0800 Subject: [PATCH 3/3] Return an entire options struct --- pkg/minikube/machine/cache_binaries.go | 30 +++++------ pkg/minikube/machine/cache_binaries_test.go | 57 +++++++++++++++++++++ 2 files changed, 72 insertions(+), 15 deletions(-) diff --git a/pkg/minikube/machine/cache_binaries.go b/pkg/minikube/machine/cache_binaries.go index 70bb61fa48..898540eab3 100644 --- a/pkg/minikube/machine/cache_binaries.go +++ b/pkg/minikube/machine/cache_binaries.go @@ -57,19 +57,26 @@ func releaseURL(binaryName, version, osName, archName string) string { return fmt.Sprintf("https://storage.googleapis.com/kubernetes-release/release/%s/bin/%s/%s/%s", version, osName, archName, binaryName) } -// checksumVerifier returns the binary checksum URL and hash method -func checksumVerifier(binaryName, version, osName, archName string) (string, crypto.Hash, error) { - binURL := releaseURL(binaryName, version, osName, archName) +// downloadOptions returns appropriate download options for a +func downloadOptions(url string, version string) (download.FileOptions, error) { + fo := download.FileOptions{ + Mkdirs: download.MkdirAll, + Options: download.Options{ + ChecksumHash: crypto.SHA1, + Checksum: url + ".sha1", + }, + } v, err := semver.Make(version[1:]) if err != nil { - return "", 0, err + return fo, err } if v.GTE(semver.MustParse("1.17.0")) { - return binURL + ".sha256", crypto.SHA256, nil + fo.ChecksumHash = crypto.SHA256 + fo.Checksum = url + ".sha256" } - return binURL + ".sha1", crypto.SHA1, nil + return fo, nil } // CacheBinary will cache a binary on the host @@ -94,17 +101,10 @@ func CacheBinary(binary, version, osName, archName string) (string, error) { return "", errors.Wrapf(err, "mkdir %s", targetDir) } - options := download.FileOptions{ - Mkdirs: download.MkdirAll, - } - - ckURL, ckAlgo, err := checksumVerifier(binary, version, osName, archName) + options, err := downloadOptions(url, version) if err != nil { - return "", errors.Wrap(err, "verifier") + return "", errors.Wrap(err, "options") } - options.Checksum = ckURL - options.ChecksumHash = ckAlgo - glog.Infof("Downloading %s: options: %+v", url, options) out.T(out.FileDownload, "Downloading {{.name}} {{.version}}", out.V{"name": binary, "version": version}) diff --git a/pkg/minikube/machine/cache_binaries_test.go b/pkg/minikube/machine/cache_binaries_test.go index a0ad859662..8b250cafcf 100644 --- a/pkg/minikube/machine/cache_binaries_test.go +++ b/pkg/minikube/machine/cache_binaries_test.go @@ -17,12 +17,15 @@ limitations under the License. package machine import ( + "crypto" "fmt" "io/ioutil" "os" "runtime" "testing" + "github.com/google/go-cmp/cmp" + "github.com/jimmidyson/go-download" "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/bootstrapper" "k8s.io/minikube/pkg/minikube/command" @@ -215,3 +218,57 @@ func TestCacheBinary(t *testing.T) { }) } } + +func TestDownloadOptions(t *testing.T) { + var tc = []struct { + url string + version string + want download.FileOptions + }{ + { + url: "https://s/kubernetes-release/release/v1.16.0/bin/amd64/kubectl", + version: "v1.16.0", + want: download.FileOptions{ + download.Options{ + Checksum: "https://s/kubernetes-release/release/v1.16.0/bin/amd64/kubectl.sha1", + ChecksumHash: crypto.SHA1, + }, + download.MkdirAll, + }, + }, + { + url: "https://s/kubernetes-release/release/v1.10.0/bin/hp9k/kubeadm", + version: "v1.10.0", + want: download.FileOptions{ + download.Options{ + Checksum: "https://s/kubernetes-release/release/v1.10.0/bin/hp9k/kubeadm.sha1", + ChecksumHash: crypto.SHA1, + }, + download.MkdirAll, + }, + }, + { + url: "https://s/kubernetes-release/release/v1.18.0/bin/arm64/kubelet", + version: "v1.18.0", + want: download.FileOptions{ + download.Options{ + Checksum: "https://s/kubernetes-release/release/v1.18.0/bin/arm64/kubelet.sha256", + ChecksumHash: crypto.SHA256, + }, + download.MkdirAll, + }, + }, + } + for _, test := range tc { + t.Run(test.version, func(t *testing.T) { + got, err := downloadOptions(test.url, test.version) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("unexpected options(-want +got):\n%s", diff) + } + }) + } +}