diff --git a/pkg/action/install.go b/pkg/action/install.go index e7b481d47..fa13bbade 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -744,6 +744,7 @@ func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) ( Getters: getter.All(settings), Options: []getter.Option{ getter.WithBasicAuth(c.Username, c.Password), + getter.WithTLSClientConfig(c.CertFile, c.KeyFile, c.CaFile), }, RepositoryConfig: settings.RepositoryConfig, RepositoryCache: settings.RepositoryCache, diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index f3d4321c5..340a65472 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -181,8 +181,10 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er c.Options = append( c.Options, getter.WithURL(rc.URL), - getter.WithTLSClientConfig(rc.CertFile, rc.KeyFile, rc.CAFile), ) + if rc.CertFile != "" || rc.KeyFile != "" || rc.CAFile != "" { + c.Options = append(c.Options, getter.WithTLSClientConfig(rc.CertFile, rc.KeyFile, rc.CAFile)) + } if rc.Username != "" && rc.Password != "" { c.Options = append( c.Options, @@ -210,12 +212,14 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er if err != nil { return u, err } - if r != nil && r.Config != nil && r.Config.Username != "" && r.Config.Password != "" { - c.Options = append(c.Options, getter.WithBasicAuth(r.Config.Username, r.Config.Password)) - } - if r.Config.CertFile != "" || r.Config.KeyFile != "" || r.Config.CAFile != "" { - c.Options = append(c.Options, getter.WithTLSClientConfig(r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile)) + if r != nil && r.Config != nil { + if r.Config.CertFile != "" || r.Config.KeyFile != "" || r.Config.CAFile != "" { + 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)) + } } // Next, we need to load the index, and actually look up the chart. @@ -255,9 +259,6 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er if _, err := getter.NewHTTPGetter(getter.WithURL(rc.URL)); err != nil { return repoURL, err } - if r != nil && r.Config != nil && r.Config.Username != "" && r.Config.Password != "" { - c.Options = append(c.Options, getter.WithBasicAuth(r.Config.Username, r.Config.Password)) - } return u, err } diff --git a/pkg/downloader/chart_downloader_test.go b/pkg/downloader/chart_downloader_test.go index e0692c8c8..abfb007ff 100644 --- a/pkg/downloader/chart_downloader_test.go +++ b/pkg/downloader/chart_downloader_test.go @@ -227,6 +227,58 @@ func TestDownloadTo(t *testing.T) { } } +func TestDownloadTo_TLS(t *testing.T) { + // Set up mock server w/ tls enabled + srv, err := repotest.NewTempServer("testdata/*.tgz*") + srv.Stop() + if err != nil { + t.Fatal(err) + } + srv.StartTLS() + defer srv.Stop() + if err := srv.CreateIndex(); err != nil { + t.Fatal(err) + } + if err := srv.LinkIndices(); err != nil { + t.Fatal(err) + } + + repoConfig := filepath.Join(srv.Root(), "repositories.yaml") + repoCache := srv.Root() + + c := ChartDownloader{ + Out: os.Stderr, + Verify: VerifyAlways, + Keyring: "testdata/helm-test-key.pub", + RepositoryConfig: repoConfig, + RepositoryCache: repoCache, + Getters: getter.All(&cli.EnvSettings{ + RepositoryConfig: repoConfig, + RepositoryCache: repoCache, + }), + Options: []getter.Option{}, + } + cname := "test/signtest" + dest := srv.Root() + where, v, err := c.DownloadTo(cname, "", dest) + if err != nil { + t.Fatal(err) + } + + target := filepath.Join(dest, "signtest-0.1.0.tgz") + if expect := target; where != expect { + t.Errorf("Expected download to %s, got %s", expect, where) + } + + if v.FileHash == "" { + t.Error("File hash was empty, but verification is required.") + } + + if _, err := os.Stat(target); err != nil { + t.Error(err) + } +} + func TestDownloadTo_VerifyLater(t *testing.T) { defer ensure.HelmHome(t)() diff --git a/pkg/repo/repotest/server.go b/pkg/repo/repotest/server.go index 96a8bbfcc..b18bce49c 100644 --- a/pkg/repo/repotest/server.go +++ b/pkg/repo/repotest/server.go @@ -22,6 +22,8 @@ import ( "os" "path/filepath" + "helm.sh/helm/v3/internal/tlsutil" + "sigs.k8s.io/yaml" "helm.sh/helm/v3/pkg/repo" @@ -143,6 +145,40 @@ func (s *Server) Start() { })) } +func (s *Server) StartTLS() { + cd := "../../testdata" + ca, pub, priv := filepath.Join(cd, "rootca.crt"), filepath.Join(cd, "crt.pem"), filepath.Join(cd, "key.pem") + + s.srv = httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if s.middleware != nil { + s.middleware.ServeHTTP(w, r) + } + http.FileServer(http.Dir(s.Root())).ServeHTTP(w, r) + })) + tlsConf, err := tlsutil.NewClientTLS(pub, priv, ca) + if err != nil { + panic(err) + } + tlsConf.BuildNameToCertificate() + tlsConf.ServerName = "helm.sh" + s.srv.TLS = tlsConf + s.srv.StartTLS() + + // Set up repositories config with ca file + repoConfig := filepath.Join(s.Root(), "repositories.yaml") + + r := repo.NewFile() + r.Add(&repo.Entry{ + Name: "test", + URL: s.URL(), + CAFile: filepath.Join("../../testdata", "rootca.crt"), + }) + + if err := r.WriteFile(repoConfig, 0644); err != nil { + panic(err) + } +} + // Stop stops the server and closes all connections. // // It should be called explicitly.