[dev] Patch helm CVE-2021-32690 (#1424)

This commit is contained in:
Henry Beberman 2021-09-20 17:16:49 -07:00 committed by GitHub
parent 3a72afd634
commit 1b6d311434
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 702 additions and 1 deletions

View File

@ -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)
}
}

View File

@ -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