fix(helm): pass down username/password CLI parameters to OCI registry clients

When username/password parameters are passed in via the CLI
they are not passed down to the client handling requests to
OCI registries. This change ensures this happens

Signed-off-by: Evans Mungai <mbuevans@gmail.com>
pull/12769/head
Evans Mungai 2 years ago
parent e81f6140dd
commit dc158f6208
No known key found for this signature in database
GPG Key ID: BBEB812143DD14E1

@ -137,7 +137,7 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
}, },
RunE: func(_ *cobra.Command, args []string) error { RunE: func(_ *cobra.Command, args []string) error {
registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile,
client.InsecureSkipTLSverify, client.PlainHTTP) client.InsecureSkipTLSverify, client.PlainHTTP, client.Username, client.Password)
if err != nil { if err != nil {
return fmt.Errorf("missing registry client: %w", err) return fmt.Errorf("missing registry client: %w", err)
} }

@ -65,7 +65,7 @@ func newPullCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
} }
registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile,
client.InsecureSkipTLSverify, client.PlainHTTP) client.InsecureSkipTLSverify, client.PlainHTTP, client.Username, client.Password)
if err != nil { if err != nil {
return fmt.Errorf("missing registry client: %w", err) return fmt.Errorf("missing registry client: %w", err)
} }

@ -68,7 +68,9 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
return nil, cobra.ShellCompDirectiveNoFileComp return nil, cobra.ShellCompDirectiveNoFileComp
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
registryClient, err := newRegistryClient(o.certFile, o.keyFile, o.caFile, o.insecureSkipTLSverify, o.plainHTTP) registryClient, err := newRegistryClient(
o.certFile, o.keyFile, o.caFile, o.insecureSkipTLSverify, o.plainHTTP, "", "",
)
if err != nil { if err != nil {
return fmt.Errorf("missing registry client: %w", err) return fmt.Errorf("missing registry client: %w", err)
} }

@ -21,6 +21,7 @@ import (
"fmt" "fmt"
"io" "io"
"log" "log"
"net/http"
"os" "os"
"strings" "strings"
@ -29,6 +30,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
"helm.sh/helm/v3/internal/tlsutil"
"helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/registry" "helm.sh/helm/v3/pkg/registry"
"helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v3/pkg/repo"
@ -153,7 +155,7 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string
flags.ParseErrorsWhitelist.UnknownFlags = true flags.ParseErrorsWhitelist.UnknownFlags = true
flags.Parse(args) flags.Parse(args)
registryClient, err := newDefaultRegistryClient(false) registryClient, err := newDefaultRegistryClient(false, "", "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -258,27 +260,30 @@ func checkForExpiredRepos(repofile string) {
} }
func newRegistryClient(certFile, keyFile, caFile string, insecureSkipTLSverify, plainHTTP bool) (*registry.Client, error) { func newRegistryClient(
certFile, keyFile, caFile string, insecureSkipTLSverify, plainHTTP bool, username, password string,
) (*registry.Client, error) {
if certFile != "" && keyFile != "" || caFile != "" || insecureSkipTLSverify { if certFile != "" && keyFile != "" || caFile != "" || insecureSkipTLSverify {
registryClient, err := newRegistryClientWithTLS(certFile, keyFile, caFile, insecureSkipTLSverify) registryClient, err := newRegistryClientWithTLS(certFile, keyFile, caFile, insecureSkipTLSverify, username, password)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return registryClient, nil return registryClient, nil
} }
registryClient, err := newDefaultRegistryClient(plainHTTP) registryClient, err := newDefaultRegistryClient(plainHTTP, username, password)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return registryClient, nil return registryClient, nil
} }
func newDefaultRegistryClient(plainHTTP bool) (*registry.Client, error) { func newDefaultRegistryClient(plainHTTP bool, username, password string) (*registry.Client, error) {
opts := []registry.ClientOption{ opts := []registry.ClientOption{
registry.ClientOptDebug(settings.Debug), registry.ClientOptDebug(settings.Debug),
registry.ClientOptEnableCache(true), registry.ClientOptEnableCache(true),
registry.ClientOptWriter(os.Stderr), registry.ClientOptWriter(os.Stderr),
registry.ClientOptCredentialsFile(settings.RegistryConfig), registry.ClientOptCredentialsFile(settings.RegistryConfig),
registry.ClientOptBasicAuth(username, password),
} }
if plainHTTP { if plainHTTP {
opts = append(opts, registry.ClientOptPlainHTTP()) opts = append(opts, registry.ClientOptPlainHTTP())
@ -292,10 +297,26 @@ func newDefaultRegistryClient(plainHTTP bool) (*registry.Client, error) {
return registryClient, nil return registryClient, nil
} }
func newRegistryClientWithTLS(certFile, keyFile, caFile string, insecureSkipTLSverify bool) (*registry.Client, error) { func newRegistryClientWithTLS(
certFile, keyFile, caFile string, insecureSkipTLSverify bool, username, password string,
) (*registry.Client, error) {
tlsConf, err := tlsutil.NewClientTLS(certFile, keyFile, caFile, insecureSkipTLSverify)
if err != nil {
return nil, fmt.Errorf("can't create TLS config for client: %w", err)
}
// Create a new registry client // Create a new registry client
registryClient, err := registry.NewRegistryClientWithTLS(os.Stderr, certFile, keyFile, caFile, insecureSkipTLSverify, registryClient, err := registry.NewClient(
settings.RegistryConfig, settings.Debug, registry.ClientOptDebug(settings.Debug),
registry.ClientOptEnableCache(true),
registry.ClientOptWriter(os.Stderr),
registry.ClientOptCredentialsFile(settings.RegistryConfig),
registry.ClientOptHTTPClient(&http.Client{
Transport: &http.Transport{
TLSClientConfig: tlsConf,
},
}),
registry.ClientOptBasicAuth(username, password),
) )
if err != nil { if err != nil {
return nil, err return nil, err

@ -227,7 +227,7 @@ func runShow(args []string, client *action.Show) (string, error) {
func addRegistryClient(client *action.Show) error { func addRegistryClient(client *action.Show) error {
registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile,
client.InsecureSkipTLSverify, client.PlainHTTP) client.InsecureSkipTLSverify, client.PlainHTTP, client.Username, client.Password)
if err != nil { if err != nil {
return fmt.Errorf("missing registry client: %w", err) return fmt.Errorf("missing registry client: %w", err)
} }

@ -74,7 +74,7 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
} }
registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile,
client.InsecureSkipTLSverify, client.PlainHTTP) client.InsecureSkipTLSverify, client.PlainHTTP, client.Username, client.Password)
if err != nil { if err != nil {
return fmt.Errorf("missing registry client: %w", err) return fmt.Errorf("missing registry client: %w", err)
} }

@ -98,7 +98,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
client.Namespace = settings.Namespace() client.Namespace = settings.Namespace()
registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile,
client.InsecureSkipTLSverify, client.PlainHTTP) client.InsecureSkipTLSverify, client.PlainHTTP, client.Username, client.Password)
if err != nil { if err != nil {
return fmt.Errorf("missing registry client: %w", err) return fmt.Errorf("missing registry client: %w", err)
} }

@ -754,6 +754,7 @@ func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) (
getter.WithTLSClientConfig(c.CertFile, c.KeyFile, c.CaFile), getter.WithTLSClientConfig(c.CertFile, c.KeyFile, c.CaFile),
getter.WithInsecureSkipVerifyTLS(c.InsecureSkipTLSverify), getter.WithInsecureSkipVerifyTLS(c.InsecureSkipTLSverify),
getter.WithPlainHTTP(c.PlainHTTP), getter.WithPlainHTTP(c.PlainHTTP),
getter.WithBasicAuth(c.Username, c.Password),
}, },
RepositoryConfig: settings.RepositoryConfig, RepositoryConfig: settings.RepositoryConfig,
RepositoryCache: settings.RepositoryCache, RepositoryCache: settings.RepositoryCache,

@ -18,6 +18,7 @@ package registry // import "helm.sh/helm/v3/pkg/registry"
import ( import (
"context" "context"
"encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
@ -56,6 +57,8 @@ type (
enableCache bool enableCache bool
// path to repository config file e.g. ~/.docker/config.json // path to repository config file e.g. ~/.docker/config.json
credentialsFile string credentialsFile string
username string
password string
out io.Writer out io.Writer
authorizer auth.Client authorizer auth.Client
registryAuthorizer *registryauth.Client registryAuthorizer *registryauth.Client
@ -105,6 +108,19 @@ func NewClient(options ...ClientOption) (*Client, error) {
if client.plainHTTP { if client.plainHTTP {
opts = append(opts, auth.WithResolverPlainHTTP()) opts = append(opts, auth.WithResolverPlainHTTP())
} }
// if username and password are set, use them for authentication
// by adding the basic auth Authorization header to the resolver
if client.username != "" && client.password != "" {
concat := client.username + ":" + client.password
encodedAuth := base64.StdEncoding.EncodeToString([]byte(concat))
opts = append(opts, auth.WithResolverHeaders(
http.Header{
"Authorization": []string{"Basic " + encodedAuth},
},
))
}
resolver, err := client.authorizer.ResolverWithOpts(opts...) resolver, err := client.authorizer.ResolverWithOpts(opts...)
if err != nil { if err != nil {
return nil, err return nil, err
@ -125,6 +141,13 @@ func NewClient(options ...ClientOption) (*Client, error) {
}, },
Cache: cache, Cache: cache,
Credential: func(ctx context.Context, reg string) (registryauth.Credential, error) { Credential: func(ctx context.Context, reg string) (registryauth.Credential, error) {
if client.username != "" && client.password != "" {
return registryauth.Credential{
Username: client.username,
Password: client.password,
}, nil
}
dockerClient, ok := client.authorizer.(*dockerauth.Client) dockerClient, ok := client.authorizer.(*dockerauth.Client)
if !ok { if !ok {
return registryauth.EmptyCredential, errors.New("unable to obtain docker client") return registryauth.EmptyCredential, errors.New("unable to obtain docker client")
@ -168,6 +191,14 @@ func ClientOptEnableCache(enableCache bool) ClientOption {
} }
} }
// ClientOptBasicAuth returns a function that sets the username and password setting on client options set
func ClientOptBasicAuth(username, password string) ClientOption {
return func(client *Client) {
client.username = username
client.password = password
}
}
// ClientOptWriter returns a function that sets the writer setting on client options set // ClientOptWriter returns a function that sets the writer setting on client options set
func ClientOptWriter(out io.Writer) ClientOption { func ClientOptWriter(out io.Writer) ClientOption {
return func(client *Client) { return func(client *Client) {

Loading…
Cancel
Save