[dev] Patch helm CVE-2021-32690 (#1424)
This commit is contained in:
Родитель
3a72afd634
Коммит
1b6d311434
|
@ -0,0 +1,697 @@
|
|||
From 61d8e8c4a6f95540c15c6a65f36a6dd0a45e7a2f Mon Sep 17 00:00:00 2001
|
||||
From: Matt Farina <matt.farina@suse.com>
|
||||
Date: Fri, 11 Jun 2021 14:36:55 -0400
|
||||
Subject: [PATCH] tweak basic handling
|
||||
|
||||
Backported to helm 3.4.1
|
||||
|
||||
Signed-off-by: Matt Farina <matt.farina@suse.com>
|
||||
Signed-off-by: Henry Beberman <henry.beberman@microsoft.com>
|
||||
|
||||
(cherry picked from commit 17ed9c4cd3c61290587a22953e5359af5ecccaa2)
|
||||
|
||||
diff -Naur a/cmd/helm/flags.go b/cmd/helm/flags.go
|
||||
--- a/cmd/helm/flags.go 2020-11-11 11:44:01.000000000 -0800
|
||||
+++ b/cmd/helm/flags.go 2021-09-20 15:58:38.405158596 -0700
|
||||
@@ -56,6 +56,7 @@
|
||||
f.StringVar(&c.KeyFile, "key-file", "", "identify HTTPS client using this SSL key file")
|
||||
f.BoolVar(&c.InsecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart download")
|
||||
f.StringVar(&c.CaFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
|
||||
+ f.BoolVar(&c.PassCredentialsAll, "pass-credentials", false, "pass credentials to all domains")
|
||||
}
|
||||
|
||||
// bindOutputFlag will add the output flag to the given command and bind the
|
||||
diff -Naur a/cmd/helm/install_test.go b/cmd/helm/install_test.go
|
||||
--- a/cmd/helm/install_test.go 2020-11-11 11:44:01.000000000 -0800
|
||||
+++ b/cmd/helm/install_test.go 2021-09-20 15:58:38.405158596 -0700
|
||||
@@ -18,10 +18,36 @@
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
+ "net/http"
|
||||
+ "net/http/httptest"
|
||||
"testing"
|
||||
+
|
||||
+ "helm.sh/helm/v3/pkg/repo/repotest"
|
||||
)
|
||||
|
||||
func TestInstall(t *testing.T) {
|
||||
+ srv, err := repotest.NewTempServerWithCleanup(t, "testdata/testcharts/*.tgz*")
|
||||
+ if err != nil {
|
||||
+ t.Fatal(err)
|
||||
+ }
|
||||
+ defer srv.Stop()
|
||||
+
|
||||
+ srv.WithMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
+ username, password, ok := r.BasicAuth()
|
||||
+ if !ok || username != "username" || password != "password" {
|
||||
+ t.Errorf("Expected request to use basic auth and for username == 'username' and password == 'password', got '%v', '%s', '%s'", ok, username, password)
|
||||
+ }
|
||||
+ }))
|
||||
+
|
||||
+ srv2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
+ http.FileServer(http.Dir(srv.Root())).ServeHTTP(w, r)
|
||||
+ }))
|
||||
+ defer srv2.Close()
|
||||
+
|
||||
+ if err := srv.LinkIndices(); err != nil {
|
||||
+ t.Fatal(err)
|
||||
+ }
|
||||
+
|
||||
tests := []cmdTestCase{
|
||||
// Install, base case
|
||||
{
|
||||
@@ -201,6 +227,17 @@
|
||||
name: "install chart with only crds",
|
||||
cmd: "install crd-test testdata/testcharts/chart-with-only-crds --namespace default",
|
||||
},
|
||||
+ // Verify the user/pass works
|
||||
+ {
|
||||
+ name: "basic install with credentials",
|
||||
+ cmd: "install aeneas reqtest --namespace default --repo " + srv.URL() + " --username username --password password",
|
||||
+ golden: "output/install.txt",
|
||||
+ },
|
||||
+ {
|
||||
+ name: "basic install with credentials",
|
||||
+ cmd: "install aeneas reqtest --namespace default --repo " + srv2.URL + " --username username --password password --pass-credentials",
|
||||
+ golden: "output/install.txt",
|
||||
+ },
|
||||
}
|
||||
|
||||
runTestActionCmd(t, tests)
|
||||
diff -Naur a/cmd/helm/pull_test.go b/cmd/helm/pull_test.go
|
||||
--- a/cmd/helm/pull_test.go 2020-11-11 11:44:01.000000000 -0800
|
||||
+++ b/cmd/helm/pull_test.go 2021-09-20 15:58:38.405158596 -0700
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
+ "net/http"
|
||||
+ "net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@@ -185,6 +187,115 @@
|
||||
}
|
||||
|
||||
ef := filepath.Join(outdir, tt.expectFile)
|
||||
+ fi, err := os.Stat(ef)
|
||||
+ if err != nil {
|
||||
+ t.Errorf("%q: expected a file at %s. %s", tt.name, ef, err)
|
||||
+ }
|
||||
+ if fi.IsDir() != tt.expectDir {
|
||||
+ t.Errorf("%q: expected directory=%t, but it's not.", tt.name, tt.expectDir)
|
||||
+ }
|
||||
+ })
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+func TestPullWithCredentialsCmd(t *testing.T) {
|
||||
+ srv, err := repotest.NewTempServerWithCleanup(t, "testdata/testcharts/*.tgz*")
|
||||
+ if err != nil {
|
||||
+ t.Fatal(err)
|
||||
+ }
|
||||
+ defer srv.Stop()
|
||||
+
|
||||
+ srv.WithMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
+ username, password, ok := r.BasicAuth()
|
||||
+ if !ok || username != "username" || password != "password" {
|
||||
+ t.Errorf("Expected request to use basic auth and for username == 'username' and password == 'password', got '%v', '%s', '%s'", ok, username, password)
|
||||
+ }
|
||||
+ }))
|
||||
+
|
||||
+ srv2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
+ http.FileServer(http.Dir(srv.Root())).ServeHTTP(w, r)
|
||||
+ }))
|
||||
+ defer srv2.Close()
|
||||
+
|
||||
+ if err := srv.LinkIndices(); err != nil {
|
||||
+ t.Fatal(err)
|
||||
+ }
|
||||
+
|
||||
+ // all flags will get "-d outdir" appended.
|
||||
+ tests := []struct {
|
||||
+ name string
|
||||
+ args string
|
||||
+ existFile string
|
||||
+ existDir string
|
||||
+ wantError bool
|
||||
+ wantErrorMsg string
|
||||
+ expectFile string
|
||||
+ expectDir bool
|
||||
+ }{
|
||||
+ {
|
||||
+ name: "Chart fetch using repo URL",
|
||||
+ expectFile: "./signtest-0.1.0.tgz",
|
||||
+ args: "signtest --repo " + srv.URL() + " --username username --password password",
|
||||
+ },
|
||||
+ {
|
||||
+ name: "Fail fetching non-existent chart on repo URL",
|
||||
+ args: "someChart --repo " + srv.URL() + " --username username --password password",
|
||||
+ wantError: true,
|
||||
+ },
|
||||
+ {
|
||||
+ name: "Specific version chart fetch using repo URL",
|
||||
+ expectFile: "./signtest-0.1.0.tgz",
|
||||
+ args: "signtest --version=0.1.0 --repo " + srv.URL() + " --username username --password password",
|
||||
+ },
|
||||
+ {
|
||||
+ name: "Specific version chart fetch using repo URL",
|
||||
+ args: "signtest --version=0.2.0 --repo " + srv.URL() + " --username username --password password",
|
||||
+ wantError: true,
|
||||
+ },
|
||||
+ {
|
||||
+ name: "Chart located on different domain with credentials passed",
|
||||
+ args: "reqtest --repo " + srv2.URL + " --username username --password password --pass-credentials",
|
||||
+ expectFile: "./reqtest-0.1.0.tgz",
|
||||
+ },
|
||||
+ }
|
||||
+
|
||||
+ for _, tt := range tests {
|
||||
+ t.Run(tt.name, func(t *testing.T) {
|
||||
+ outdir := srv.Root()
|
||||
+ cmd := fmt.Sprintf("pull %s -d '%s' --repository-config %s --repository-cache %s --registry-config %s",
|
||||
+ tt.args,
|
||||
+ outdir,
|
||||
+ filepath.Join(outdir, "repositories.yaml"),
|
||||
+ outdir,
|
||||
+ filepath.Join(outdir, "config.json"),
|
||||
+ )
|
||||
+ // Create file or Dir before helm pull --untar, see: https://github.com/helm/helm/issues/7182
|
||||
+ if tt.existFile != "" {
|
||||
+ file := filepath.Join(outdir, tt.existFile)
|
||||
+ _, err := os.Create(file)
|
||||
+ if err != nil {
|
||||
+ t.Fatal(err)
|
||||
+ }
|
||||
+ }
|
||||
+ if tt.existDir != "" {
|
||||
+ file := filepath.Join(outdir, tt.existDir)
|
||||
+ err := os.Mkdir(file, 0755)
|
||||
+ if err != nil {
|
||||
+ t.Fatal(err)
|
||||
+ }
|
||||
+ }
|
||||
+ _, _, err := executeActionCommand(cmd)
|
||||
+ if err != nil {
|
||||
+ if tt.wantError {
|
||||
+ if tt.wantErrorMsg != "" && tt.wantErrorMsg == err.Error() {
|
||||
+ t.Fatalf("Actual error %s, not equal to expected error %s", err, tt.wantErrorMsg)
|
||||
+ }
|
||||
+ return
|
||||
+ }
|
||||
+ t.Fatalf("%q reported error: %s", tt.name, err)
|
||||
+ }
|
||||
+
|
||||
+ ef := filepath.Join(outdir, tt.expectFile)
|
||||
fi, err := os.Stat(ef)
|
||||
if err != nil {
|
||||
t.Errorf("%q: expected a file at %s. %s", tt.name, ef, err)
|
||||
diff -Naur a/cmd/helm/repo_add.go b/cmd/helm/repo_add.go
|
||||
--- a/cmd/helm/repo_add.go 2020-11-11 11:44:01.000000000 -0800
|
||||
+++ b/cmd/helm/repo_add.go 2021-09-20 15:58:38.405158596 -0700
|
||||
@@ -48,6 +48,7 @@
|
||||
url string
|
||||
username string
|
||||
password string
|
||||
+ passCredentialsAll bool
|
||||
forceUpdate bool
|
||||
allowDeprecatedRepos bool
|
||||
|
||||
@@ -91,6 +92,7 @@
|
||||
f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
|
||||
f.BoolVar(&o.insecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the repository")
|
||||
f.BoolVar(&o.allowDeprecatedRepos, "allow-deprecated-repos", false, "by default, this command will not allow adding official repos that have been permanently deleted. This disables that behavior")
|
||||
+ f.BoolVar(&o.passCredentialsAll, "pass-credentials", false, "pass credentials to all domains")
|
||||
|
||||
return cmd
|
||||
}
|
||||
@@ -149,6 +151,7 @@
|
||||
URL: o.url,
|
||||
Username: o.username,
|
||||
Password: o.password,
|
||||
+ PassCredentialsAll: o.passCredentialsAll,
|
||||
CertFile: o.certFile,
|
||||
KeyFile: o.keyFile,
|
||||
CAFile: o.caFile,
|
||||
diff -Naur a/pkg/action/install.go b/pkg/action/install.go
|
||||
--- a/pkg/action/install.go 2020-11-11 11:44:01.000000000 -0800
|
||||
+++ b/pkg/action/install.go 2021-09-20 15:58:38.405158596 -0700
|
||||
@@ -20,6 +20,7 @@
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
+ "net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -110,6 +111,7 @@
|
||||
InsecureSkipTLSverify bool // --insecure-skip-verify
|
||||
Keyring string // --keyring
|
||||
Password string // --password
|
||||
+ PassCredentialsAll bool // --pass-credentials
|
||||
RepoURL string // --repo
|
||||
Username string // --username
|
||||
Verify bool // --verify
|
||||
@@ -643,7 +645,7 @@
|
||||
Keyring: c.Keyring,
|
||||
Getters: getter.All(settings),
|
||||
Options: []getter.Option{
|
||||
- getter.WithBasicAuth(c.Username, c.Password),
|
||||
+ getter.WithPassCredentialsAll(c.PassCredentialsAll),
|
||||
getter.WithTLSClientConfig(c.CertFile, c.KeyFile, c.CaFile),
|
||||
getter.WithInsecureSkipVerifyTLS(c.InsecureSkipTLSverify),
|
||||
},
|
||||
@@ -654,12 +656,34 @@
|
||||
dl.Verify = downloader.VerifyAlways
|
||||
}
|
||||
if c.RepoURL != "" {
|
||||
- chartURL, err := repo.FindChartInAuthAndTLSRepoURL(c.RepoURL, c.Username, c.Password, name, version,
|
||||
- c.CertFile, c.KeyFile, c.CaFile, c.InsecureSkipTLSverify, getter.All(settings))
|
||||
+ chartURL, err := repo.FindChartInAuthAndTLSAndPassRepoURL(c.RepoURL, c.Username, c.Password, name, version,
|
||||
+ c.CertFile, c.KeyFile, c.CaFile, c.InsecureSkipTLSverify, c.PassCredentialsAll, getter.All(settings))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
name = chartURL
|
||||
+
|
||||
+ // Only pass the user/pass on when the user has said to or when the
|
||||
+ // location of the chart repo and the chart are the same domain.
|
||||
+ u1, err := url.Parse(c.RepoURL)
|
||||
+ if err != nil {
|
||||
+ return "", err
|
||||
+ }
|
||||
+ u2, err := url.Parse(chartURL)
|
||||
+ if err != nil {
|
||||
+ return "", err
|
||||
+ }
|
||||
+
|
||||
+ // Host on URL (returned from url.Parse) contains the port if present.
|
||||
+ // This check ensures credentials are not passed between different
|
||||
+ // services on different ports.
|
||||
+ if c.PassCredentialsAll || (u1.Scheme == u2.Scheme && u1.Host == u2.Host) {
|
||||
+ dl.Options = append(dl.Options, getter.WithBasicAuth(c.Username, c.Password))
|
||||
+ } else {
|
||||
+ dl.Options = append(dl.Options, getter.WithBasicAuth("", ""))
|
||||
+ }
|
||||
+ } else {
|
||||
+ dl.Options = append(dl.Options, getter.WithBasicAuth(c.Username, c.Password))
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(settings.RepositoryCache, 0755); err != nil {
|
||||
diff -Naur a/pkg/action/pull.go b/pkg/action/pull.go
|
||||
--- a/pkg/action/pull.go 2020-11-11 11:44:01.000000000 -0800
|
||||
+++ b/pkg/action/pull.go 2021-09-20 15:58:38.405158596 -0700
|
||||
@@ -63,6 +63,7 @@
|
||||
Getters: getter.All(p.Settings),
|
||||
Options: []getter.Option{
|
||||
getter.WithBasicAuth(p.Username, p.Password),
|
||||
+ getter.WithPassCredentialsAll(p.PassCredentialsAll),
|
||||
getter.WithTLSClientConfig(p.CertFile, p.KeyFile, p.CaFile),
|
||||
getter.WithInsecureSkipVerifyTLS(p.InsecureSkipTLSverify),
|
||||
},
|
||||
@@ -89,7 +90,7 @@
|
||||
}
|
||||
|
||||
if p.RepoURL != "" {
|
||||
- chartURL, err := repo.FindChartInAuthAndTLSRepoURL(p.RepoURL, p.Username, p.Password, chartRef, p.Version, p.CertFile, p.KeyFile, p.CaFile, p.InsecureSkipTLSverify, getter.All(p.Settings))
|
||||
+ chartURL, err := repo.FindChartInAuthAndTLSAndPassRepoURL(p.RepoURL, p.Username, p.Password, chartRef, p.Version, p.CertFile, p.KeyFile, p.CaFile, p.InsecureSkipTLSverify, p.PassCredentialsAll, getter.All(p.Settings))
|
||||
if err != nil {
|
||||
return out.String(), err
|
||||
}
|
||||
diff -Naur a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go
|
||||
--- a/pkg/downloader/chart_downloader.go 2020-11-11 11:44:01.000000000 -0800
|
||||
+++ b/pkg/downloader/chart_downloader.go 2021-09-20 15:58:38.405158596 -0700
|
||||
@@ -189,6 +189,7 @@
|
||||
c.Options = append(
|
||||
c.Options,
|
||||
getter.WithBasicAuth(rc.Username, rc.Password),
|
||||
+ getter.WithPassCredentialsAll(rc.PassCredentialsAll),
|
||||
)
|
||||
}
|
||||
return u, nil
|
||||
@@ -218,7 +219,10 @@
|
||||
c.Options = append(c.Options, getter.WithTLSClientConfig(r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile))
|
||||
}
|
||||
if r.Config.Username != "" && r.Config.Password != "" {
|
||||
- c.Options = append(c.Options, getter.WithBasicAuth(r.Config.Username, r.Config.Password))
|
||||
+ c.Options = append(c.Options,
|
||||
+ getter.WithBasicAuth(r.Config.Username, r.Config.Password),
|
||||
+ getter.WithPassCredentialsAll(r.Config.PassCredentialsAll),
|
||||
+ )
|
||||
}
|
||||
}
|
||||
|
||||
diff -Naur a/pkg/downloader/chart_downloader_test.go b/pkg/downloader/chart_downloader_test.go
|
||||
--- a/pkg/downloader/chart_downloader_test.go 2020-11-11 11:44:01.000000000 -0800
|
||||
+++ b/pkg/downloader/chart_downloader_test.go 2021-09-20 15:58:38.405158596 -0700
|
||||
@@ -205,6 +205,7 @@
|
||||
}),
|
||||
Options: []getter.Option{
|
||||
getter.WithBasicAuth("username", "password"),
|
||||
+ getter.WithPassCredentialsAll(false),
|
||||
},
|
||||
}
|
||||
cname := "/signtest-0.1.0.tgz"
|
||||
diff -Naur a/pkg/downloader/manager.go b/pkg/downloader/manager.go
|
||||
--- a/pkg/downloader/manager.go 2020-11-11 11:44:01.000000000 -0800
|
||||
+++ b/pkg/downloader/manager.go 2021-09-20 16:04:28.201715831 -0700
|
||||
@@ -307,7 +307,7 @@
|
||||
|
||||
// Any failure to resolve/download a chart should fail:
|
||||
// https://github.com/helm/helm/issues/1439
|
||||
- churl, username, password, err := m.findChartURL(dep.Name, dep.Version, dep.Repository, repos)
|
||||
+ churl, username, password, passcredentialsall, err := m.findChartURL(dep.Name, dep.Version, dep.Repository, repos)
|
||||
if err != nil {
|
||||
saveError = errors.Wrapf(err, "could not find %s", churl)
|
||||
break
|
||||
@@ -329,6 +329,7 @@
|
||||
Getters: m.Getters,
|
||||
Options: []getter.Option{
|
||||
getter.WithBasicAuth(username, password),
|
||||
+ getter.WithPassCredentialsAll(passcredentialsall),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -647,7 +648,8 @@
|
||||
// repoURL is the repository to search
|
||||
//
|
||||
// If it finds a URL that is "relative", it will prepend the repoURL.
|
||||
-func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRepository) (url, username, password string, err error) {
|
||||
+func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRepository) (url, username, password string, passcredentialsall bool, err error) {
|
||||
+
|
||||
for _, cr := range repos {
|
||||
if urlutil.Equal(repoURL, cr.Config.URL) {
|
||||
var entry repo.ChartVersions
|
||||
@@ -666,15 +668,16 @@
|
||||
}
|
||||
username = cr.Config.Username
|
||||
password = cr.Config.Password
|
||||
+ passcredentialsall = cr.Config.PassCredentialsAll
|
||||
return
|
||||
}
|
||||
}
|
||||
url, err = repo.FindChartInRepoURL(repoURL, name, version, "", "", "", m.Getters)
|
||||
if err == nil {
|
||||
- return
|
||||
+ return url, username, password, false, err
|
||||
}
|
||||
err = errors.Errorf("chart %s not found in %s: %s", name, repoURL, err)
|
||||
- return
|
||||
+ return url, username, password, false, err
|
||||
}
|
||||
|
||||
// findEntryByName finds an entry in the chart repository whose name matches the given name.
|
||||
diff -Naur a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go
|
||||
--- a/pkg/downloader/manager_test.go 2020-11-11 11:44:01.000000000 -0800
|
||||
+++ b/pkg/downloader/manager_test.go 2021-09-20 15:58:38.405158596 -0700
|
||||
@@ -81,7 +81,7 @@
|
||||
version := "0.1.0"
|
||||
repoURL := "http://example.com/charts"
|
||||
|
||||
- churl, username, password, err := m.findChartURL(name, version, repoURL, repos)
|
||||
+ churl, username, password, passcredentialsall, err := m.findChartURL(name, version, repoURL, repos)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -94,6 +94,9 @@
|
||||
if password != "" {
|
||||
t.Errorf("Unexpected password %q", password)
|
||||
}
|
||||
+ if passcredentialsall != false {
|
||||
+ t.Errorf("Unexpected passcredentialsall %t", passcredentialsall)
|
||||
+ }
|
||||
}
|
||||
|
||||
func TestGetRepoNames(t *testing.T) {
|
||||
diff -Naur a/pkg/getter/getter.go b/pkg/getter/getter.go
|
||||
--- a/pkg/getter/getter.go 2020-11-11 11:44:01.000000000 -0800
|
||||
+++ b/pkg/getter/getter.go 2021-09-20 15:58:38.405158596 -0700
|
||||
@@ -36,6 +36,7 @@
|
||||
insecureSkipVerifyTLS bool
|
||||
username string
|
||||
password string
|
||||
+ passCredentialsAll bool
|
||||
userAgent string
|
||||
timeout time.Duration
|
||||
}
|
||||
@@ -60,6 +61,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
+func WithPassCredentialsAll(pass bool) Option {
|
||||
+ return func(opts *options) {
|
||||
+ opts.passCredentialsAll = pass
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
// WithUserAgent sets the request's User-Agent header to use the provided agent name.
|
||||
func WithUserAgent(userAgent string) Option {
|
||||
return func(opts *options) {
|
||||
diff -Naur a/pkg/getter/httpgetter.go b/pkg/getter/httpgetter.go
|
||||
--- a/pkg/getter/httpgetter.go 2020-11-11 11:44:01.000000000 -0800
|
||||
+++ b/pkg/getter/httpgetter.go 2021-09-20 15:58:38.405158596 -0700
|
||||
@@ -20,6 +20,7 @@
|
||||
"crypto/tls"
|
||||
"io"
|
||||
"net/http"
|
||||
+ "net/url"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
@@ -56,8 +57,24 @@
|
||||
req.Header.Set("User-Agent", g.opts.userAgent)
|
||||
}
|
||||
|
||||
- if g.opts.username != "" && g.opts.password != "" {
|
||||
- req.SetBasicAuth(g.opts.username, g.opts.password)
|
||||
+ // Before setting the basic auth credentials, make sure the URL associated
|
||||
+ // with the basic auth is the one being fetched.
|
||||
+ u1, err := url.Parse(g.opts.url)
|
||||
+ if err != nil {
|
||||
+ return buf, errors.Wrap(err, "Unable to parse getter URL")
|
||||
+ }
|
||||
+ u2, err := url.Parse(href)
|
||||
+ if err != nil {
|
||||
+ return buf, errors.Wrap(err, "Unable to parse URL getting from")
|
||||
+ }
|
||||
+
|
||||
+ // Host on URL (returned from url.Parse) contains the port if present.
|
||||
+ // This check ensures credentials are not passed between different
|
||||
+ // services on different ports.
|
||||
+ if g.opts.passCredentialsAll || (u1.Scheme == u2.Scheme && u1.Host == u2.Host) {
|
||||
+ if g.opts.username != "" && g.opts.password != "" {
|
||||
+ req.SetBasicAuth(g.opts.username, g.opts.password)
|
||||
+ }
|
||||
}
|
||||
|
||||
client, err := g.httpClient()
|
||||
diff -Naur a/pkg/getter/httpgetter_test.go b/pkg/getter/httpgetter_test.go
|
||||
--- a/pkg/getter/httpgetter_test.go 2020-11-11 11:44:01.000000000 -0800
|
||||
+++ b/pkg/getter/httpgetter_test.go 2021-09-20 15:58:38.405158596 -0700
|
||||
@@ -54,6 +54,7 @@
|
||||
// Test with options
|
||||
g, err = NewHTTPGetter(
|
||||
WithBasicAuth("I", "Am"),
|
||||
+ WithPassCredentialsAll(false),
|
||||
WithUserAgent("Groot"),
|
||||
WithTLSClientConfig(pub, priv, ca),
|
||||
WithInsecureSkipVerifyTLS(insecure),
|
||||
@@ -76,6 +77,10 @@
|
||||
t.Errorf("Expected NewHTTPGetter to contain %q as the password, got %q", "Am", hg.opts.password)
|
||||
}
|
||||
|
||||
+ if hg.opts.passCredentialsAll != false {
|
||||
+ t.Errorf("Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", false, hg.opts.passCredentialsAll)
|
||||
+ }
|
||||
+
|
||||
if hg.opts.userAgent != "Groot" {
|
||||
t.Errorf("Expected NewHTTPGetter to contain %q as the user agent, got %q", "Groot", hg.opts.userAgent)
|
||||
}
|
||||
@@ -118,6 +123,28 @@
|
||||
if hg.opts.insecureSkipVerifyTLS != insecure {
|
||||
t.Errorf("Expected NewHTTPGetter to contain %t as InsecureSkipVerifyTLs flag, got %t", insecure, hg.opts.insecureSkipVerifyTLS)
|
||||
}
|
||||
+
|
||||
+ // Checking false by default
|
||||
+ if hg.opts.passCredentialsAll != false {
|
||||
+ t.Errorf("Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", false, hg.opts.passCredentialsAll)
|
||||
+ }
|
||||
+
|
||||
+ // Test setting PassCredentialsAll
|
||||
+ g, err = NewHTTPGetter(
|
||||
+ WithBasicAuth("I", "Am"),
|
||||
+ WithPassCredentialsAll(true),
|
||||
+ )
|
||||
+ if err != nil {
|
||||
+ t.Fatal(err)
|
||||
+ }
|
||||
+
|
||||
+ hg, ok = g.(*HTTPGetter)
|
||||
+ if !ok {
|
||||
+ t.Fatal("expected NewHTTPGetter to produce an *HTTPGetter")
|
||||
+ }
|
||||
+ if hg.opts.passCredentialsAll != true {
|
||||
+ t.Errorf("Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", true, hg.opts.passCredentialsAll)
|
||||
+ }
|
||||
}
|
||||
|
||||
func TestDownload(t *testing.T) {
|
||||
@@ -163,10 +190,81 @@
|
||||
httpgetter, err := NewHTTPGetter(
|
||||
WithURL(u.String()),
|
||||
WithBasicAuth("username", "password"),
|
||||
+ WithPassCredentialsAll(false),
|
||||
WithUserAgent(expectedUserAgent),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
+ }
|
||||
+ got, err = httpgetter.Get(u.String())
|
||||
+ if err != nil {
|
||||
+ t.Fatal(err)
|
||||
+ }
|
||||
+
|
||||
+ if got.String() != expect {
|
||||
+ t.Errorf("Expected %q, got %q", expect, got.String())
|
||||
+ }
|
||||
+
|
||||
+ // test with Get URL differing from withURL
|
||||
+ crossAuthSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
+ username, password, ok := r.BasicAuth()
|
||||
+ if ok || username == "username" || password == "password" {
|
||||
+ t.Errorf("Expected request to not include but got '%v', '%s', '%s'", ok, username, password)
|
||||
+ }
|
||||
+ fmt.Fprint(w, expect)
|
||||
+ }))
|
||||
+
|
||||
+ defer crossAuthSrv.Close()
|
||||
+
|
||||
+ u, _ = url.ParseRequestURI(crossAuthSrv.URL)
|
||||
+
|
||||
+ // A different host is provided for the WithURL from the one used for Get
|
||||
+ u2, _ := url.ParseRequestURI(crossAuthSrv.URL)
|
||||
+ host := strings.Split(u2.Host, ":")
|
||||
+ host[0] = host[0] + "a"
|
||||
+ u2.Host = strings.Join(host, ":")
|
||||
+ httpgetter, err = NewHTTPGetter(
|
||||
+ WithURL(u2.String()),
|
||||
+ WithBasicAuth("username", "password"),
|
||||
+ WithPassCredentialsAll(false),
|
||||
+ )
|
||||
+ if err != nil {
|
||||
+ t.Fatal(err)
|
||||
+ }
|
||||
+ got, err = httpgetter.Get(u.String())
|
||||
+ if err != nil {
|
||||
+ t.Fatal(err)
|
||||
+ }
|
||||
+
|
||||
+ if got.String() != expect {
|
||||
+ t.Errorf("Expected %q, got %q", expect, got.String())
|
||||
+ }
|
||||
+
|
||||
+ // test with Get URL differing from withURL and should pass creds
|
||||
+ crossAuthSrv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
+ username, password, ok := r.BasicAuth()
|
||||
+ if !ok || username != "username" || password != "password" {
|
||||
+ t.Errorf("Expected request to use basic auth and for username == 'username' and password == 'password', got '%v', '%s', '%s'", ok, username, password)
|
||||
+ }
|
||||
+ fmt.Fprint(w, expect)
|
||||
+ }))
|
||||
+
|
||||
+ defer crossAuthSrv.Close()
|
||||
+
|
||||
+ u, _ = url.ParseRequestURI(crossAuthSrv.URL)
|
||||
+
|
||||
+ // A different host is provided for the WithURL from the one used for Get
|
||||
+ u2, _ = url.ParseRequestURI(crossAuthSrv.URL)
|
||||
+ host = strings.Split(u2.Host, ":")
|
||||
+ host[0] = host[0] + "a"
|
||||
+ u2.Host = strings.Join(host, ":")
|
||||
+ httpgetter, err = NewHTTPGetter(
|
||||
+ WithURL(u2.String()),
|
||||
+ WithBasicAuth("username", "password"),
|
||||
+ WithPassCredentialsAll(true),
|
||||
+ )
|
||||
+ if err != nil {
|
||||
+ t.Fatal(err)
|
||||
}
|
||||
got, err = httpgetter.Get(u.String())
|
||||
if err != nil {
|
||||
diff -Naur a/pkg/repo/chartrepo.go b/pkg/repo/chartrepo.go
|
||||
--- a/pkg/repo/chartrepo.go 2020-11-11 11:44:01.000000000 -0800
|
||||
+++ b/pkg/repo/chartrepo.go 2021-09-20 15:58:38.405158596 -0700
|
||||
@@ -48,6 +48,7 @@
|
||||
KeyFile string `json:"keyFile"`
|
||||
CAFile string `json:"caFile"`
|
||||
InsecureSkipTLSverify bool `json:"insecure_skip_tls_verify"`
|
||||
+ PassCredentialsAll bool `json:"pass_credentials_all"`
|
||||
}
|
||||
|
||||
// ChartRepository represents a chart repository
|
||||
@@ -127,6 +128,7 @@
|
||||
getter.WithInsecureSkipVerifyTLS(r.Config.InsecureSkipTLSverify),
|
||||
getter.WithTLSClientConfig(r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile),
|
||||
getter.WithBasicAuth(r.Config.Username, r.Config.Password),
|
||||
+ getter.WithPassCredentialsAll(r.Config.PassCredentialsAll),
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -213,6 +215,15 @@
|
||||
// but it also receives credentials and TLS verify flag for the chart repository.
|
||||
// TODO Helm 4, FindChartInAuthAndTLSRepoURL should be integrated into FindChartInAuthRepoURL.
|
||||
func FindChartInAuthAndTLSRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile string, insecureSkipTLSverify bool, getters getter.Providers) (string, error) {
|
||||
+ return FindChartInAuthAndTLSAndPassRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile, false, false, getters)
|
||||
+}
|
||||
+
|
||||
+// FindChartInAuthAndTLSAndPassRepoURL finds chart in chart repository pointed by repoURL
|
||||
+// without adding repo to repositories, like FindChartInRepoURL,
|
||||
+// but it also receives credentials, TLS verify flag, and if credentials should
|
||||
+// be passed on to other domains.
|
||||
+// TODO Helm 4, FindChartInAuthAndTLSAndPassRepoURL should be integrated into FindChartInAuthRepoURL.
|
||||
+func FindChartInAuthAndTLSAndPassRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile string, insecureSkipTLSverify, passCredentialsAll bool, getters getter.Providers) (string, error) {
|
||||
|
||||
// Download and write the index file to a temporary location
|
||||
buf := make([]byte, 20)
|
||||
@@ -223,6 +234,7 @@
|
||||
URL: repoURL,
|
||||
Username: username,
|
||||
Password: password,
|
||||
+ PassCredentialsAll: passCredentialsAll,
|
||||
CertFile: certFile,
|
||||
KeyFile: keyFile,
|
||||
CAFile: caFile,
|
||||
diff -Naur a/pkg/repo/chartrepo_test.go b/pkg/repo/chartrepo_test.go
|
||||
--- a/pkg/repo/chartrepo_test.go 2020-11-11 11:44:01.000000000 -0800
|
||||
+++ b/pkg/repo/chartrepo_test.go 2021-09-20 15:58:38.405158596 -0700
|
||||
@@ -291,14 +291,14 @@
|
||||
return httptest.NewTLSServer(handler), nil
|
||||
}
|
||||
|
||||
-func TestFindChartInAuthAndTLSRepoURL(t *testing.T) {
|
||||
+func TestFindChartInAuthAndTLSAndPassRepoURL(t *testing.T) {
|
||||
srv, err := startLocalTLSServerForTests(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
- chartURL, err := FindChartInAuthAndTLSRepoURL(srv.URL, "", "", "nginx", "", "", "", "", true, getter.All(&cli.EnvSettings{}))
|
||||
+ chartURL, err := FindChartInAuthAndTLSAndPassRepoURL(srv.URL, "", "", "nginx", "", "", "", "", true, false, getter.All(&cli.EnvSettings{}))
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
@@ -307,10 +307,10 @@
|
||||
}
|
||||
|
||||
// If the insecureSkipTLsverify is false, it will return an error that contains "x509: certificate signed by unknown authority".
|
||||
- _, err = FindChartInAuthAndTLSRepoURL(srv.URL, "", "", "nginx", "0.1.0", "", "", "", false, getter.All(&cli.EnvSettings{}))
|
||||
+ _, err = FindChartInAuthAndTLSAndPassRepoURL(srv.URL, "", "", "nginx", "0.1.0", "", "", "", false, false, getter.All(&cli.EnvSettings{}))
|
||||
|
||||
if !strings.Contains(err.Error(), "x509: certificate signed by unknown authority") {
|
||||
- t.Errorf("Expected TLS error for function FindChartInAuthAndTLSRepoURL not found, but got a different error (%v)", err)
|
||||
+ t.Errorf("Expected TLS error for function FindChartInAuthAndTLSAndPassRepoURL not found, but got a different error (%v)", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Name: helm
|
||||
Version: 3.4.1
|
||||
Release: 3%{?dist}
|
||||
Release: 4%{?dist}
|
||||
Summary: The Kubernetes Package Manager
|
||||
Group: Applications/Networking
|
||||
License: Apache 2.0
|
||||
|
@ -26,6 +26,7 @@ Source0: %{name}-%{version}.tar.gz
|
|||
#
|
||||
Source1: %{name}-%{version}-vendor.tar.gz
|
||||
Patch0: CVE-2021-21303.patch
|
||||
Patch1: CVE-2021-32690.patch
|
||||
BuildRequires: golang >= 1.15.5
|
||||
|
||||
%description
|
||||
|
@ -53,6 +54,9 @@ install -m 755 ./helm %{buildroot}%{_bindir}
|
|||
|
||||
|
||||
%changelog
|
||||
* Mon Sep 20 2021 Henry Beberman <henry.beberman@microsoft.com> - 3.4.1-4
|
||||
- Patch CVE-2021-32690
|
||||
|
||||
* Mon Sep 20 2021 Henry Beberman <henry.beberman@microsoft.com> - 3.4.1-3
|
||||
- Patch CVE-2021-21303
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче