From e813d1397fe5d8658c828a94f6d8d7cf154484f3 Mon Sep 17 00:00:00 2001 From: suryatech27-cloud Date: Mon, 21 Mar 2022 15:29:41 +0530 Subject: [PATCH 01/11] handshake failure(2-way ssl support for oci pull) --- internal/tlsutil/cfg.go | 90 ++++++++++++++++++++++++++++++++++++++++ pkg/action/pull.go | 18 +++++++- pkg/registry/client.go | 92 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+), 1 deletion(-) diff --git a/internal/tlsutil/cfg.go b/internal/tlsutil/cfg.go index 8b9d4329f..ef0b8e18e 100644 --- a/internal/tlsutil/cfg.go +++ b/internal/tlsutil/cfg.go @@ -19,7 +19,11 @@ package tlsutil import ( "crypto/tls" "crypto/x509" + "fmt" + "io/ioutil" "os" + "path/filepath" + "runtime" "github.com/pkg/errors" ) @@ -56,3 +60,89 @@ func ClientConfig(opts Options) (cfg *tls.Config, err error) { cfg = &tls.Config{InsecureSkipVerify: opts.InsecureSkipVerify, Certificates: []tls.Certificate{*cert}, RootCAs: pool} return cfg, nil } + +func ReadCertFromSecDir(cfgFileBaseName string, host string) (opts Options, err error) { + if runtime.GOOS == "windows" || runtime.GOOS == "unix" { + fmt.Printf("%v OS not supported for this oci pull. Contact your administrator for more information !!!", runtime.GOOS) + } else { + var clientCertDir = "/etc/docker/certs.d/" + /* var fileName = helmpath.ConfigPath(cfgFileBaseName) + data, err := ioutil.ReadFile(fileName) + + if err != nil { + fmt.Printf("Config file not exist %v\n", err) + } + + var configDataMap map[string]map[string]interface{} + err = json.Unmarshal(data, &configDataMap) + + if err != nil { + fmt.Printf("Please do login before initiating the pull : %v", err) + } + + keys := reflect.ValueOf(configDataMap["auths"]).MapKeys() + strkeys := make([]string, len(keys)) + for i := 0; i < len(keys); i++ { + strkeys[i] = keys[i].String() + } + //fmt.Print(strings.Join(strkeys, ",")) + strkey := strings.Join(strkeys, "") */ + clientCertDir = clientCertDir + host + + if _, err := os.Stat(clientCertDir); err != nil { + if os.IsNotExist(err) { + os.MkdirAll(clientCertDir, os.ModePerm) + return opts, errors.Wrapf(err, "Client Certificate Directory Not Exist !! \n %v Directory created.", clientCertDir) + } + } else { + + if files, err := ioutil.ReadDir(clientCertDir); err == nil { + for _, file := range files { + if filepath.Ext(file.Name()) == ".crt" { + opts.CaCertFile = clientCertDir + "/" + file.Name() + //fmt.Printf("cafile: %v\n", opts.CaCertFile) + } else if filepath.Ext(file.Name()) == ".pem" { + opts.CertFile = clientCertDir + "/" + file.Name() + //fmt.Printf("certFile: %v\n", opts.CertFile) + } else if filepath.Ext(file.Name()) == ".key" { + opts.KeyFile = clientCertDir + "/" + file.Name() + //fmt.Printf("keyFile: %v\n", opts.KeyFile) + } + } + } else { + fmt.Printf(" Certificate not found in current directory - %v\n ", err) + os.Exit(1) + } + if opts.CaCertFile == "" && opts.CertFile == "" && opts.KeyFile == "" { + fmt.Printf("Error Certificate (cacerts.crt,client.pem,client.key) required : Client authentication failed due to certificate not present in cert directory !! \n") + os.Exit(1) + } + + if opts.CaCertFile == "" && opts.CertFile == "" { + fmt.Printf("Error Certificate Required : Root-CA and client certificate (cacerts.crt,client.pem) not found.\n") + os.Exit(1) + } + + if opts.CaCertFile == "" && opts.KeyFile == "" { + fmt.Printf("Error Certificate Required : Root-CA and and client keyfie (cacerts.crt,client.key) not found.\n") + os.Exit(1) + } + + if opts.CertFile == "" && opts.KeyFile == "" { + fmt.Printf("Error Certificate Required : Client certificate and client keyfile (client.pem,client.key) not found.\n") + os.Exit(1) + } + if opts.CaCertFile == "" { + fmt.Printf("Error Certificate Required : Client Root-CA (cacerts.crt) not found.\n") + os.Exit(1) + } else if opts.CertFile == "" { + fmt.Printf("Error Certificate Required : Client certificate(client.pem) not found.\n") + os.Exit(1) + } else if opts.KeyFile == "" { + fmt.Printf("Error Certificate Required : Client keyfile (client.key) not found.\n") + os.Exit(1) + } + } + } + return opts, nil +} diff --git a/pkg/action/pull.go b/pkg/action/pull.go index b4018869e..cf0a6ab40 100644 --- a/pkg/action/pull.go +++ b/pkg/action/pull.go @@ -125,7 +125,23 @@ func (p *Pull) Run(chartRef string) (string, error) { saved, v, err := c.DownloadTo(chartRef, p.Version, dest) if err != nil { - return out.String(), err + registryClient, err := registry.NewCrosClient(chartRef, + registry.ClientOptDebug(p.Settings.Debug), + registry.ClientOptCredentialsFile(p.Settings.RegistryConfig), + registry.ClientOptWriter(&out), + ) + if err != nil { + return out.String(), err + } + c.Options = append(c.Options, + getter.WithRegistryClient(registryClient), + getter.WithTagName(p.Version)) + + saved, v, err = c.DownloadTo(chartRef, p.Version, dest) + if err != nil { + return out.String(), err + } + } if p.Verify { diff --git a/pkg/registry/client.go b/pkg/registry/client.go index 0107136d3..89401a978 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -22,9 +22,11 @@ import ( "fmt" "io" "io/ioutil" + "net" "net/http" "sort" "strings" + "time" "github.com/Masterminds/semver/v3" "github.com/containerd/containerd/remotes" @@ -38,6 +40,8 @@ import ( registryremote "oras.land/oras-go/pkg/registry/remote" registryauth "oras.land/oras-go/pkg/registry/remote/auth" + "helm.sh/helm/v3/internal/tlsutil" + "helm.sh/helm/v3/internal/urlutil" "helm.sh/helm/v3/internal/version" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/helmpath" @@ -131,6 +135,94 @@ func NewClient(options ...ClientOption) (*Client, error) { return client, nil } +func NewCrosClient(chartref string, options ...ClientOption) (*Client, error) { + client := &Client{ + out: ioutil.Discard, + } + for _, option := range options { + option(client) + } + if client.credentialsFile == "" { + client.credentialsFile = helmpath.ConfigPath(CredentialsFileBasename) + } + if client.authorizer == nil { + authClient, err := dockerauth.NewClientWithDockerFallback(client.credentialsFile) + if err != nil { + return nil, err + } + client.authorizer = authClient + } + if client.resolver == nil { + host, err := urlutil.ExtractHostname(chartref) + if err != nil { + + } + clientOpts, err := tlsutil.ReadCertFromSecDir(CredentialsFileBasename, host) + if err != nil { + return client, errors.Wrapf(err, "Client certificate/directory Not Exist !!") + } + cfgtls, err := tlsutil.ClientConfig(clientOpts) + if err != nil { + fmt.Printf("error :%v\n", err) + + } + var rt http.RoundTripper = &http.Transport{ + Dial: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).Dial, + TLSHandshakeTimeout: 30 * time.Second, + TLSClientConfig: cfgtls, + ResponseHeaderTimeout: time.Duration(3 * time.Second), + DisableKeepAlives: true, + } + crosclient := http.Client{Transport: rt, Timeout: 30 * time.Second} + headers := http.Header{} + headers.Set("User-Agent", version.GetUserAgent()) + opts := []auth.ResolverOption{auth.WithResolverHeaders(headers), auth.WithResolverClient(&crosclient)} + resolver, err := client.authorizer.ResolverWithOpts(opts...) + if err != nil { + return nil, err + } + client.resolver = resolver + } + + if client.registryAuthorizer == nil { + client.registryAuthorizer = ®istryauth.Client{ + Header: http.Header{ + "User-Agent": {version.GetUserAgent()}, + }, + Cache: registryauth.DefaultCache, + Credential: func(ctx context.Context, reg string) (registryauth.Credential, error) { + dockerClient, ok := client.authorizer.(*dockerauth.Client) + if !ok { + return registryauth.EmptyCredential, errors.New("unable to obtain docker client") + } + + username, password, err := dockerClient.Credential(reg) + if err != nil { + return registryauth.EmptyCredential, errors.New("unable to retrieve credentials") + } + + // A blank returned username and password value is a bearer token + if username == "" && password != "" { + return registryauth.Credential{ + RefreshToken: password, + }, nil + } + + return registryauth.Credential{ + Username: username, + Password: password, + }, nil + + }, + } + + } + return client, nil +} + // ClientOptDebug returns a function that sets the debug setting on client options set func ClientOptDebug(debug bool) ClientOption { return func(client *Client) { From cfb5586af41af30bff6db697bfdb4af04b33f079 Mon Sep 17 00:00:00 2001 From: suryatech27-cloud Date: Mon, 21 Mar 2022 18:30:40 +0530 Subject: [PATCH 02/11] commented code deleted. --- internal/tlsutil/cfg.go | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/internal/tlsutil/cfg.go b/internal/tlsutil/cfg.go index ef0b8e18e..a53e18031 100644 --- a/internal/tlsutil/cfg.go +++ b/internal/tlsutil/cfg.go @@ -66,27 +66,6 @@ func ReadCertFromSecDir(cfgFileBaseName string, host string) (opts Options, err fmt.Printf("%v OS not supported for this oci pull. Contact your administrator for more information !!!", runtime.GOOS) } else { var clientCertDir = "/etc/docker/certs.d/" - /* var fileName = helmpath.ConfigPath(cfgFileBaseName) - data, err := ioutil.ReadFile(fileName) - - if err != nil { - fmt.Printf("Config file not exist %v\n", err) - } - - var configDataMap map[string]map[string]interface{} - err = json.Unmarshal(data, &configDataMap) - - if err != nil { - fmt.Printf("Please do login before initiating the pull : %v", err) - } - - keys := reflect.ValueOf(configDataMap["auths"]).MapKeys() - strkeys := make([]string, len(keys)) - for i := 0; i < len(keys); i++ { - strkeys[i] = keys[i].String() - } - //fmt.Print(strings.Join(strkeys, ",")) - strkey := strings.Join(strkeys, "") */ clientCertDir = clientCertDir + host if _, err := os.Stat(clientCertDir); err != nil { @@ -100,13 +79,10 @@ func ReadCertFromSecDir(cfgFileBaseName string, host string) (opts Options, err for _, file := range files { if filepath.Ext(file.Name()) == ".crt" { opts.CaCertFile = clientCertDir + "/" + file.Name() - //fmt.Printf("cafile: %v\n", opts.CaCertFile) } else if filepath.Ext(file.Name()) == ".pem" { opts.CertFile = clientCertDir + "/" + file.Name() - //fmt.Printf("certFile: %v\n", opts.CertFile) } else if filepath.Ext(file.Name()) == ".key" { opts.KeyFile = clientCertDir + "/" + file.Name() - //fmt.Printf("keyFile: %v\n", opts.KeyFile) } } } else { From 6684099057a6171ae108137300dcfadd0beba0e9 Mon Sep 17 00:00:00 2001 From: suryatech27-cloud Date: Tue, 22 Mar 2022 18:26:58 +0530 Subject: [PATCH 03/11] Signed-off-by: Sunil Kumar --- pkg/action/pull.go | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/pkg/action/pull.go b/pkg/action/pull.go index cf0a6ab40..1b3da1622 100644 --- a/pkg/action/pull.go +++ b/pkg/action/pull.go @@ -125,23 +125,27 @@ func (p *Pull) Run(chartRef string) (string, error) { saved, v, err := c.DownloadTo(chartRef, p.Version, dest) if err != nil { - registryClient, err := registry.NewCrosClient(chartRef, - registry.ClientOptDebug(p.Settings.Debug), - registry.ClientOptCredentialsFile(p.Settings.RegistryConfig), - registry.ClientOptWriter(&out), - ) - if err != nil { - return out.String(), err - } - c.Options = append(c.Options, - getter.WithRegistryClient(registryClient), - getter.WithTagName(p.Version)) + fmt.Printf("Error : %v\n", err) + if strings.Contains(fmt.Sprint(err), "remote error: tls: handshake failure") { + registryClient, err := registry.NewCrosClient(chartRef, + registry.ClientOptDebug(p.Settings.Debug), + registry.ClientOptCredentialsFile(p.Settings.RegistryConfig), + registry.ClientOptWriter(&out), + ) + if err != nil { + return out.String(), err + } + c.Options = append(c.Options, + getter.WithRegistryClient(registryClient), + getter.WithTagName(p.Version)) - saved, v, err = c.DownloadTo(chartRef, p.Version, dest) - if err != nil { + saved, v, err = c.DownloadTo(chartRef, p.Version, dest) + if err != nil { + return out.String(), err + } + } else { return out.String(), err } - } if p.Verify { From c0eba0470239bc9a21ccd518b4c65f4e29644bd6 Mon Sep 17 00:00:00 2001 From: suryatech27-cloud Date: Tue, 22 Mar 2022 18:28:33 +0530 Subject: [PATCH 04/11] Signed-off-by: Sunil Kumar --- pkg/action/pull.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/action/pull.go b/pkg/action/pull.go index 1b3da1622..9c91061ab 100644 --- a/pkg/action/pull.go +++ b/pkg/action/pull.go @@ -125,7 +125,7 @@ func (p *Pull) Run(chartRef string) (string, error) { saved, v, err := c.DownloadTo(chartRef, p.Version, dest) if err != nil { - fmt.Printf("Error : %v\n", err) + //fmt.Printf("Error : %v\n", err) if strings.Contains(fmt.Sprint(err), "remote error: tls: handshake failure") { registryClient, err := registry.NewCrosClient(chartRef, registry.ClientOptDebug(p.Settings.Debug), From 163af70daee12ae26f15ade6c06b6dc6a5d8cc60 Mon Sep 17 00:00:00 2001 From: suryatech27-cloud Date: Thu, 24 Mar 2022 18:19:00 +0530 Subject: [PATCH 05/11] Hardcoded value removed Signed-off-by: Sunil Kumar --- cmd/helm/root.go | 1 + cmd/helm/testdata/output/env-comp.txt | 1 + internal/tlsutil/cfg.go | 38 ++++++++++++++------ pkg/action/pull.go | 1 - pkg/cli/environment.go | 51 +++++++++++++++------------ pkg/registry/client.go | 4 +-- 6 files changed, 59 insertions(+), 37 deletions(-) diff --git a/cmd/helm/root.go b/cmd/helm/root.go index 394f241d5..1bd1d956a 100644 --- a/cmd/helm/root.go +++ b/cmd/helm/root.go @@ -67,6 +67,7 @@ Environment variables: | $HELM_KUBEASUSER | set the Username to impersonate for the operation. | | $HELM_KUBECONTEXT | set the name of the kubeconfig context. | | $HELM_KUBETOKEN | set the Bearer KubeToken used for authentication. | +| $HELM_SECONDARY_CERT_DIR | set the secondary certificate directory for 2-way ssl support for oci pull. | Helm stores cache, configuration, and data based on the following configuration order: diff --git a/cmd/helm/testdata/output/env-comp.txt b/cmd/helm/testdata/output/env-comp.txt index b7befd69e..7a1412b86 100644 --- a/cmd/helm/testdata/output/env-comp.txt +++ b/cmd/helm/testdata/output/env-comp.txt @@ -15,5 +15,6 @@ HELM_PLUGINS HELM_REGISTRY_CONFIG HELM_REPOSITORY_CACHE HELM_REPOSITORY_CONFIG +HELM_SECONDARY_CERT_DIR :4 Completion ended with directive: ShellCompDirectiveNoFileComp diff --git a/internal/tlsutil/cfg.go b/internal/tlsutil/cfg.go index a53e18031..a64fc29d3 100644 --- a/internal/tlsutil/cfg.go +++ b/internal/tlsutil/cfg.go @@ -22,8 +22,10 @@ import ( "fmt" "io/ioutil" "os" + "os/exec" "path/filepath" "runtime" + "strings" "github.com/pkg/errors" ) @@ -61,13 +63,27 @@ func ClientConfig(opts Options) (cfg *tls.Config, err error) { return cfg, nil } -func ReadCertFromSecDir(cfgFileBaseName string, host string) (opts Options, err error) { +func ReadCertFromSecDir(host string) (opts Options, err error) { if runtime.GOOS == "windows" || runtime.GOOS == "unix" { fmt.Printf("%v OS not supported for this oci pull. Contact your administrator for more information !!!", runtime.GOOS) + os.Exit(1) } else { - var clientCertDir = "/etc/docker/certs.d/" - clientCertDir = clientCertDir + host - + cmd, err := exec.Command("helm", "env", "HELM_SECONDARY_CERT_DIR").Output() + if err != nil { + fmt.Printf("Error : %s", err) + os.Exit(1) + } + clientCertDir := strings.TrimSuffix(string(cmd), "\n") + if clientCertDir == "" { + fmt.Printf("Please Configure secondary certificate directory for ssl connection set/export HELM_SECONDARY_CERT_DIR='/etc/docker/certs.d/'\n") + os.Exit(1) + } + lastIndex := strings.LastIndexByte(clientCertDir, '/') + if lastIndex < 19 { + clientCertDir = fmt.Sprintf("%s/%s", clientCertDir, host) + } else { + clientCertDir = fmt.Sprintf("%s%s", clientCertDir, host) + } if _, err := os.Stat(clientCertDir); err != nil { if os.IsNotExist(err) { os.MkdirAll(clientCertDir, os.ModePerm) @@ -78,11 +94,11 @@ func ReadCertFromSecDir(cfgFileBaseName string, host string) (opts Options, err if files, err := ioutil.ReadDir(clientCertDir); err == nil { for _, file := range files { if filepath.Ext(file.Name()) == ".crt" { - opts.CaCertFile = clientCertDir + "/" + file.Name() + opts.CaCertFile = fmt.Sprintf("%s/%s", clientCertDir, file.Name()) } else if filepath.Ext(file.Name()) == ".pem" { - opts.CertFile = clientCertDir + "/" + file.Name() + opts.CertFile = fmt.Sprintf("%s/%s", clientCertDir, file.Name()) } else if filepath.Ext(file.Name()) == ".key" { - opts.KeyFile = clientCertDir + "/" + file.Name() + opts.KeyFile = fmt.Sprintf("%s/%s", clientCertDir, file.Name()) } } } else { @@ -90,22 +106,22 @@ func ReadCertFromSecDir(cfgFileBaseName string, host string) (opts Options, err os.Exit(1) } if opts.CaCertFile == "" && opts.CertFile == "" && opts.KeyFile == "" { - fmt.Printf("Error Certificate (cacerts.crt,client.pem,client.key) required : Client authentication failed due to certificate not present in cert directory !! \n") + fmt.Printf("Error : Missing certificate (cacerts.crt,client.pem,client.key) required !!\n") os.Exit(1) } if opts.CaCertFile == "" && opts.CertFile == "" { - fmt.Printf("Error Certificate Required : Root-CA and client certificate (cacerts.crt,client.pem) not found.\n") + fmt.Printf("Error : Missing certificate : Root-CA and client certificate (cacerts.crt,client.pem) required !!\n") os.Exit(1) } if opts.CaCertFile == "" && opts.KeyFile == "" { - fmt.Printf("Error Certificate Required : Root-CA and and client keyfie (cacerts.crt,client.key) not found.\n") + fmt.Printf("Error Certificate Required : Root-CA and and client key (cacerts.crt,client.key) not found.\n") os.Exit(1) } if opts.CertFile == "" && opts.KeyFile == "" { - fmt.Printf("Error Certificate Required : Client certificate and client keyfile (client.pem,client.key) not found.\n") + fmt.Printf("Error Certificate Required : Client certificate and client key (client.pem,client.key) not found.\n") os.Exit(1) } if opts.CaCertFile == "" { diff --git a/pkg/action/pull.go b/pkg/action/pull.go index 9c91061ab..6f728ea9f 100644 --- a/pkg/action/pull.go +++ b/pkg/action/pull.go @@ -125,7 +125,6 @@ func (p *Pull) Run(chartRef string) (string, error) { saved, v, err := c.DownloadTo(chartRef, p.Version, dest) if err != nil { - //fmt.Printf("Error : %v\n", err) if strings.Contains(fmt.Sprint(err), "remote error: tls: handshake failure") { registryClient, err := registry.NewCrosClient(chartRef, registry.ClientOptDebug(p.Settings.Debug), diff --git a/pkg/cli/environment.go b/pkg/cli/environment.go index d5b208015..bf4bb6761 100644 --- a/pkg/cli/environment.go +++ b/pkg/cli/environment.go @@ -68,22 +68,25 @@ type EnvSettings struct { PluginsDirectory string // MaxHistory is the max release history maintained. MaxHistory int + // Secondary Certificate directory for helm oci pull + ClientSecCertDirectory string } func New() *EnvSettings { env := &EnvSettings{ - namespace: os.Getenv("HELM_NAMESPACE"), - MaxHistory: envIntOr("HELM_MAX_HISTORY", defaultMaxHistory), - KubeContext: os.Getenv("HELM_KUBECONTEXT"), - KubeToken: os.Getenv("HELM_KUBETOKEN"), - KubeAsUser: os.Getenv("HELM_KUBEASUSER"), - KubeAsGroups: envCSV("HELM_KUBEASGROUPS"), - KubeAPIServer: os.Getenv("HELM_KUBEAPISERVER"), - KubeCaFile: os.Getenv("HELM_KUBECAFILE"), - PluginsDirectory: envOr("HELM_PLUGINS", helmpath.DataPath("plugins")), - RegistryConfig: envOr("HELM_REGISTRY_CONFIG", helmpath.ConfigPath("registry/config.json")), - RepositoryConfig: envOr("HELM_REPOSITORY_CONFIG", helmpath.ConfigPath("repositories.yaml")), - RepositoryCache: envOr("HELM_REPOSITORY_CACHE", helmpath.CachePath("repository")), + namespace: os.Getenv("HELM_NAMESPACE"), + MaxHistory: envIntOr("HELM_MAX_HISTORY", defaultMaxHistory), + KubeContext: os.Getenv("HELM_KUBECONTEXT"), + KubeToken: os.Getenv("HELM_KUBETOKEN"), + KubeAsUser: os.Getenv("HELM_KUBEASUSER"), + KubeAsGroups: envCSV("HELM_KUBEASGROUPS"), + KubeAPIServer: os.Getenv("HELM_KUBEAPISERVER"), + KubeCaFile: os.Getenv("HELM_KUBECAFILE"), + ClientSecCertDirectory: envOr("HELM_SECONDARY_CERT_DIR", ""), + PluginsDirectory: envOr("HELM_PLUGINS", helmpath.DataPath("plugins")), + RegistryConfig: envOr("HELM_REGISTRY_CONFIG", helmpath.ConfigPath("registry/config.json")), + RepositoryConfig: envOr("HELM_REPOSITORY_CONFIG", helmpath.ConfigPath("repositories.yaml")), + RepositoryCache: envOr("HELM_REPOSITORY_CACHE", helmpath.CachePath("repository")), } env.Debug, _ = strconv.ParseBool(os.Getenv("HELM_DEBUG")) @@ -115,6 +118,7 @@ func (s *EnvSettings) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&s.RegistryConfig, "registry-config", s.RegistryConfig, "path to the registry config file") fs.StringVar(&s.RepositoryConfig, "repository-config", s.RepositoryConfig, "path to the file containing repository names and URLs") fs.StringVar(&s.RepositoryCache, "repository-cache", s.RepositoryCache, "path to the file containing cached repository indexes") + fs.StringVar(&s.ClientSecCertDirectory, "client-sec-cert-dir", s.ClientSecCertDirectory, "path to the secondary certificate directory used for 2-way ssl support(oci pull for artificat repo)") } func envOr(name, def string) string { @@ -146,17 +150,18 @@ func envCSV(name string) (ls []string) { func (s *EnvSettings) EnvVars() map[string]string { envvars := map[string]string{ - "HELM_BIN": os.Args[0], - "HELM_CACHE_HOME": helmpath.CachePath(""), - "HELM_CONFIG_HOME": helmpath.ConfigPath(""), - "HELM_DATA_HOME": helmpath.DataPath(""), - "HELM_DEBUG": fmt.Sprint(s.Debug), - "HELM_PLUGINS": s.PluginsDirectory, - "HELM_REGISTRY_CONFIG": s.RegistryConfig, - "HELM_REPOSITORY_CACHE": s.RepositoryCache, - "HELM_REPOSITORY_CONFIG": s.RepositoryConfig, - "HELM_NAMESPACE": s.Namespace(), - "HELM_MAX_HISTORY": strconv.Itoa(s.MaxHistory), + "HELM_BIN": os.Args[0], + "HELM_CACHE_HOME": helmpath.CachePath(""), + "HELM_CONFIG_HOME": helmpath.ConfigPath(""), + "HELM_DATA_HOME": helmpath.DataPath(""), + "HELM_DEBUG": fmt.Sprint(s.Debug), + "HELM_PLUGINS": s.PluginsDirectory, + "HELM_REGISTRY_CONFIG": s.RegistryConfig, + "HELM_REPOSITORY_CACHE": s.RepositoryCache, + "HELM_REPOSITORY_CONFIG": s.RepositoryConfig, + "HELM_NAMESPACE": s.Namespace(), + "HELM_MAX_HISTORY": strconv.Itoa(s.MaxHistory), + "HELM_SECONDARY_CERT_DIR": s.ClientSecCertDirectory, // broken, these are populated from helm flags and not kubeconfig. "HELM_KUBECONTEXT": s.KubeContext, diff --git a/pkg/registry/client.go b/pkg/registry/client.go index 89401a978..8be7b4c71 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -155,9 +155,9 @@ func NewCrosClient(chartref string, options ...ClientOption) (*Client, error) { if client.resolver == nil { host, err := urlutil.ExtractHostname(chartref) if err != nil { - + fmt.Printf("error :%v\n", err) } - clientOpts, err := tlsutil.ReadCertFromSecDir(CredentialsFileBasename, host) + clientOpts, err := tlsutil.ReadCertFromSecDir(host) if err != nil { return client, errors.Wrapf(err, "Client certificate/directory Not Exist !!") } From 7f7344b490a9e30d2c6e1495b8b542a233e377fb Mon Sep 17 00:00:00 2001 From: suryatech27-cloud Date: Fri, 25 Mar 2022 13:11:33 +0530 Subject: [PATCH 06/11] Code changes for Directory validation. Signed-off-by: Sunil Kumar --- internal/tlsutil/cfg.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/tlsutil/cfg.go b/internal/tlsutil/cfg.go index a64fc29d3..5c15487b4 100644 --- a/internal/tlsutil/cfg.go +++ b/internal/tlsutil/cfg.go @@ -78,8 +78,8 @@ func ReadCertFromSecDir(host string) (opts Options, err error) { fmt.Printf("Please Configure secondary certificate directory for ssl connection set/export HELM_SECONDARY_CERT_DIR='/etc/docker/certs.d/'\n") os.Exit(1) } - lastIndex := strings.LastIndexByte(clientCertDir, '/') - if lastIndex < 19 { + + if clientCertDir[len(clientCertDir)-1] != '/' { clientCertDir = fmt.Sprintf("%s/%s", clientCertDir, host) } else { clientCertDir = fmt.Sprintf("%s%s", clientCertDir, host) From 7afcef8678f0d3e4b734db1da91b5667a06b77e4 Mon Sep 17 00:00:00 2001 From: suryatech27-cloud Date: Fri, 25 Mar 2022 18:28:51 +0530 Subject: [PATCH 07/11] code addition for validation . Signed-off-by: Sunil Kumar --- internal/tlsutil/cfg.go | 32 +++++++++++++++----------------- pkg/action/pull.go | 2 +- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/internal/tlsutil/cfg.go b/internal/tlsutil/cfg.go index 5c15487b4..e6965b8a1 100644 --- a/internal/tlsutil/cfg.go +++ b/internal/tlsutil/cfg.go @@ -105,34 +105,32 @@ func ReadCertFromSecDir(host string) (opts Options, err error) { fmt.Printf(" Certificate not found in current directory - %v\n ", err) os.Exit(1) } - if opts.CaCertFile == "" && opts.CertFile == "" && opts.KeyFile == "" { + switch { + case opts.CaCertFile == "" && opts.CertFile == "" && opts.KeyFile == "": fmt.Printf("Error : Missing certificate (cacerts.crt,client.pem,client.key) required !!\n") os.Exit(1) - } - - if opts.CaCertFile == "" && opts.CertFile == "" { + case opts.CaCertFile == "" && opts.CertFile == "": fmt.Printf("Error : Missing certificate : Root-CA and client certificate (cacerts.crt,client.pem) required !!\n") os.Exit(1) - } - - if opts.CaCertFile == "" && opts.KeyFile == "" { - fmt.Printf("Error Certificate Required : Root-CA and and client key (cacerts.crt,client.key) not found.\n") + case opts.CaCertFile == "" && opts.KeyFile == "": + fmt.Printf("Error : Missing Certificate : Root-CA and and client key (cacerts.crt,client.key) required.\n") os.Exit(1) - } - if opts.CertFile == "" && opts.KeyFile == "" { - fmt.Printf("Error Certificate Required : Client certificate and client key (client.pem,client.key) not found.\n") + case opts.CertFile == "" && opts.KeyFile == "": + fmt.Printf("Error : Missing Certificate : Client certificate and client key (client.pem,client.key) required.\n") os.Exit(1) } - if opts.CaCertFile == "" { - fmt.Printf("Error Certificate Required : Client Root-CA (cacerts.crt) not found.\n") + switch { + case opts.CaCertFile == "": + fmt.Printf("Error : Missing Certificate : Client Root-CA (cacerts.crt) required.\n") os.Exit(1) - } else if opts.CertFile == "" { - fmt.Printf("Error Certificate Required : Client certificate(client.pem) not found.\n") + case opts.CertFile == "": + fmt.Printf("Error : Missing Certificate : Client certificate(client.pem) required.\n") os.Exit(1) - } else if opts.KeyFile == "" { - fmt.Printf("Error Certificate Required : Client keyfile (client.key) not found.\n") + case opts.KeyFile == "": + fmt.Printf("Error : Missing Certificate : Client keyfile (client.key) required.\n") os.Exit(1) + } } } diff --git a/pkg/action/pull.go b/pkg/action/pull.go index 6f728ea9f..87cbd4380 100644 --- a/pkg/action/pull.go +++ b/pkg/action/pull.go @@ -125,7 +125,7 @@ func (p *Pull) Run(chartRef string) (string, error) { saved, v, err := c.DownloadTo(chartRef, p.Version, dest) if err != nil { - if strings.Contains(fmt.Sprint(err), "remote error: tls: handshake failure") { + if registry.IsOCI(chartRef) && strings.Contains(fmt.Sprint(err), "remote error: tls: handshake failure") { registryClient, err := registry.NewCrosClient(chartRef, registry.ClientOptDebug(p.Settings.Debug), registry.ClientOptCredentialsFile(p.Settings.RegistryConfig), From fd085b33ef6a6b956a338a14b8d40168debbfbde Mon Sep 17 00:00:00 2001 From: suryatech27-cloud Date: Mon, 28 Mar 2022 12:16:27 +0530 Subject: [PATCH 08/11] Environment key added for client cert directory. Signed-off-by: Sunil Kumar --- cmd/helm/root.go | 2 +- cmd/helm/testdata/output/env-comp.txt | 2 +- internal/tlsutil/cfg.go | 6 +++--- pkg/cli/environment.go | 26 +++++++++++++------------- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/cmd/helm/root.go b/cmd/helm/root.go index 1bd1d956a..f0820a42d 100644 --- a/cmd/helm/root.go +++ b/cmd/helm/root.go @@ -67,7 +67,7 @@ Environment variables: | $HELM_KUBEASUSER | set the Username to impersonate for the operation. | | $HELM_KUBECONTEXT | set the name of the kubeconfig context. | | $HELM_KUBETOKEN | set the Bearer KubeToken used for authentication. | -| $HELM_SECONDARY_CERT_DIR | set the secondary certificate directory for 2-way ssl support for oci pull. | +| $HELM_CLIENT_TLS_CERT_DIR | set the certificate directory for 2-way tls support for oci pull. | Helm stores cache, configuration, and data based on the following configuration order: diff --git a/cmd/helm/testdata/output/env-comp.txt b/cmd/helm/testdata/output/env-comp.txt index 7a1412b86..f964ce16e 100644 --- a/cmd/helm/testdata/output/env-comp.txt +++ b/cmd/helm/testdata/output/env-comp.txt @@ -15,6 +15,6 @@ HELM_PLUGINS HELM_REGISTRY_CONFIG HELM_REPOSITORY_CACHE HELM_REPOSITORY_CONFIG -HELM_SECONDARY_CERT_DIR +HELM_CLIENT_TLS_CERT_DIR :4 Completion ended with directive: ShellCompDirectiveNoFileComp diff --git a/internal/tlsutil/cfg.go b/internal/tlsutil/cfg.go index e6965b8a1..11aa0cda1 100644 --- a/internal/tlsutil/cfg.go +++ b/internal/tlsutil/cfg.go @@ -68,14 +68,14 @@ func ReadCertFromSecDir(host string) (opts Options, err error) { fmt.Printf("%v OS not supported for this oci pull. Contact your administrator for more information !!!", runtime.GOOS) os.Exit(1) } else { - cmd, err := exec.Command("helm", "env", "HELM_SECONDARY_CERT_DIR").Output() + cmd, err := exec.Command("helm", "env", "HELM_CLIENT_TLS_CERT_DIR").Output() if err != nil { fmt.Printf("Error : %s", err) os.Exit(1) } clientCertDir := strings.TrimSuffix(string(cmd), "\n") if clientCertDir == "" { - fmt.Printf("Please Configure secondary certificate directory for ssl connection set/export HELM_SECONDARY_CERT_DIR='/etc/docker/certs.d/'\n") + fmt.Printf("Please configure client certificate directory for tls connection set/export HELM_CLIENT_TLS_CERT_DIR='/etc/docker/certs.d/'\n") os.Exit(1) } @@ -87,7 +87,7 @@ func ReadCertFromSecDir(host string) (opts Options, err error) { if _, err := os.Stat(clientCertDir); err != nil { if os.IsNotExist(err) { os.MkdirAll(clientCertDir, os.ModePerm) - return opts, errors.Wrapf(err, "Client Certificate Directory Not Exist !! \n %v Directory created.", clientCertDir) + return opts, errors.Wrapf(err, "%v\n%v Directory created.", clientCertDir) } } else { diff --git a/pkg/cli/environment.go b/pkg/cli/environment.go index bf4bb6761..a709ae0e0 100644 --- a/pkg/cli/environment.go +++ b/pkg/cli/environment.go @@ -82,7 +82,7 @@ func New() *EnvSettings { KubeAsGroups: envCSV("HELM_KUBEASGROUPS"), KubeAPIServer: os.Getenv("HELM_KUBEAPISERVER"), KubeCaFile: os.Getenv("HELM_KUBECAFILE"), - ClientSecCertDirectory: envOr("HELM_SECONDARY_CERT_DIR", ""), + ClientSecCertDirectory: envOr("HELM_CLIENT_TLS_CERT_DIR", ""), PluginsDirectory: envOr("HELM_PLUGINS", helmpath.DataPath("plugins")), RegistryConfig: envOr("HELM_REGISTRY_CONFIG", helmpath.ConfigPath("registry/config.json")), RepositoryConfig: envOr("HELM_REPOSITORY_CONFIG", helmpath.ConfigPath("repositories.yaml")), @@ -150,18 +150,18 @@ func envCSV(name string) (ls []string) { func (s *EnvSettings) EnvVars() map[string]string { envvars := map[string]string{ - "HELM_BIN": os.Args[0], - "HELM_CACHE_HOME": helmpath.CachePath(""), - "HELM_CONFIG_HOME": helmpath.ConfigPath(""), - "HELM_DATA_HOME": helmpath.DataPath(""), - "HELM_DEBUG": fmt.Sprint(s.Debug), - "HELM_PLUGINS": s.PluginsDirectory, - "HELM_REGISTRY_CONFIG": s.RegistryConfig, - "HELM_REPOSITORY_CACHE": s.RepositoryCache, - "HELM_REPOSITORY_CONFIG": s.RepositoryConfig, - "HELM_NAMESPACE": s.Namespace(), - "HELM_MAX_HISTORY": strconv.Itoa(s.MaxHistory), - "HELM_SECONDARY_CERT_DIR": s.ClientSecCertDirectory, + "HELM_BIN": os.Args[0], + "HELM_CACHE_HOME": helmpath.CachePath(""), + "HELM_CONFIG_HOME": helmpath.ConfigPath(""), + "HELM_DATA_HOME": helmpath.DataPath(""), + "HELM_DEBUG": fmt.Sprint(s.Debug), + "HELM_PLUGINS": s.PluginsDirectory, + "HELM_REGISTRY_CONFIG": s.RegistryConfig, + "HELM_REPOSITORY_CACHE": s.RepositoryCache, + "HELM_REPOSITORY_CONFIG": s.RepositoryConfig, + "HELM_NAMESPACE": s.Namespace(), + "HELM_MAX_HISTORY": strconv.Itoa(s.MaxHistory), + "HELM_CLIENT_TLS_CERT_DIR": s.ClientSecCertDirectory, // broken, these are populated from helm flags and not kubeconfig. "HELM_KUBECONTEXT": s.KubeContext, From afc2b1172d65bdeaf144f7489c549022b19d50a1 Mon Sep 17 00:00:00 2001 From: suryatech27-cloud Date: Mon, 28 Mar 2022 12:17:58 +0530 Subject: [PATCH 09/11] Environment key added for client cert directory. Signed-off-by: Sunil Kumar --- cmd/helm/root.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/root.go b/cmd/helm/root.go index f0820a42d..106741400 100644 --- a/cmd/helm/root.go +++ b/cmd/helm/root.go @@ -67,7 +67,7 @@ Environment variables: | $HELM_KUBEASUSER | set the Username to impersonate for the operation. | | $HELM_KUBECONTEXT | set the name of the kubeconfig context. | | $HELM_KUBETOKEN | set the Bearer KubeToken used for authentication. | -| $HELM_CLIENT_TLS_CERT_DIR | set the certificate directory for 2-way tls support for oci pull. | +| $HELM_CLIENT_TLS_CERT_DIR | set the certificate directory for 2-way tls support for oci pull. | Helm stores cache, configuration, and data based on the following configuration order: From 33613317a66e3fc9aa0993ac7b17338a6760fee8 Mon Sep 17 00:00:00 2001 From: suryatech27-cloud Date: Mon, 28 Mar 2022 13:09:52 +0530 Subject: [PATCH 10/11] Update error format. Signed-off-by: Sunil Kumar --- internal/tlsutil/cfg.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/tlsutil/cfg.go b/internal/tlsutil/cfg.go index 11aa0cda1..a4dc82228 100644 --- a/internal/tlsutil/cfg.go +++ b/internal/tlsutil/cfg.go @@ -87,7 +87,7 @@ func ReadCertFromSecDir(host string) (opts Options, err error) { if _, err := os.Stat(clientCertDir); err != nil { if os.IsNotExist(err) { os.MkdirAll(clientCertDir, os.ModePerm) - return opts, errors.Wrapf(err, "%v\n%v Directory created.", clientCertDir) + return opts, errors.Wrapf(err, clientCertDir, "%v\n%v Directory created.") } } else { From 19e0a5e7aa49e4f2495d904e1063063d788dbee2 Mon Sep 17 00:00:00 2001 From: suryatech27-cloud Date: Mon, 28 Mar 2022 13:38:50 +0530 Subject: [PATCH 11/11] Remove Cert Cert Directory Environment key and flag Signed-off-by: Sunil Kumar --- cmd/helm/testdata/output/env-comp.txt | 1 - pkg/cli/environment.go | 1 - 2 files changed, 2 deletions(-) diff --git a/cmd/helm/testdata/output/env-comp.txt b/cmd/helm/testdata/output/env-comp.txt index f964ce16e..b7befd69e 100644 --- a/cmd/helm/testdata/output/env-comp.txt +++ b/cmd/helm/testdata/output/env-comp.txt @@ -15,6 +15,5 @@ HELM_PLUGINS HELM_REGISTRY_CONFIG HELM_REPOSITORY_CACHE HELM_REPOSITORY_CONFIG -HELM_CLIENT_TLS_CERT_DIR :4 Completion ended with directive: ShellCompDirectiveNoFileComp diff --git a/pkg/cli/environment.go b/pkg/cli/environment.go index a709ae0e0..d9851be66 100644 --- a/pkg/cli/environment.go +++ b/pkg/cli/environment.go @@ -118,7 +118,6 @@ func (s *EnvSettings) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&s.RegistryConfig, "registry-config", s.RegistryConfig, "path to the registry config file") fs.StringVar(&s.RepositoryConfig, "repository-config", s.RepositoryConfig, "path to the file containing repository names and URLs") fs.StringVar(&s.RepositoryCache, "repository-cache", s.RepositoryCache, "path to the file containing cached repository indexes") - fs.StringVar(&s.ClientSecCertDirectory, "client-sec-cert-dir", s.ClientSecCertDirectory, "path to the secondary certificate directory used for 2-way ssl support(oci pull for artificat repo)") } func envOr(name, def string) string {