Bug fix for client certificate not reaching for mutual tls handshake in helm oci pull

Signed-off-by: Balaji026 balajinatrajan68@gmail.com
pull/11185/head
Balaji026 3 years ago
parent 44b4b5e8b3
commit 907953d3ff

@ -61,6 +61,7 @@ func addChartPathOptionsFlags(f *pflag.FlagSet, c *action.ChartPathOptions) {
f.BoolVar(&c.InsecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart download") 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.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") f.BoolVar(&c.PassCredentialsAll, "pass-credentials", false, "pass credentials to all domains")
f.BoolVar(&c.TlsEnabled, "mtls-enabled", false, "if two-way tls authentication enabled then trying to send client certificate")
} }
// bindOutputFlag will add the output flag to the given command and bind the // bindOutputFlag will add the output flag to the given command and bind the

@ -117,6 +117,7 @@ type ChartPathOptions struct {
Username string // --username Username string // --username
Verify bool // --verify Verify bool // --verify
Version string // --version Version string // --version
TlsEnabled bool // --mtls-enabled
// registryClient provides a registry client but is not added with // registryClient provides a registry client but is not added with
// options from a flag // options from a flag

@ -25,6 +25,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"helm.sh/helm/v3/internal/tlsutil"
"helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/cli" "helm.sh/helm/v3/pkg/cli"
"helm.sh/helm/v3/pkg/downloader" "helm.sh/helm/v3/pkg/downloader"
@ -86,6 +87,7 @@ func (p *Pull) Run(chartRef string) (string, error) {
getter.WithPassCredentialsAll(p.PassCredentialsAll), getter.WithPassCredentialsAll(p.PassCredentialsAll),
getter.WithTLSClientConfig(p.CertFile, p.KeyFile, p.CaFile), getter.WithTLSClientConfig(p.CertFile, p.KeyFile, p.CaFile),
getter.WithInsecureSkipVerifyTLS(p.InsecureSkipTLSverify), getter.WithInsecureSkipVerifyTLS(p.InsecureSkipTLSverify),
getter.WithTwoWayTLSEnable(p.TlsEnabled),
}, },
RegistryClient: p.cfg.RegistryClient, RegistryClient: p.cfg.RegistryClient,
RepositoryConfig: p.Settings.RepositoryConfig, RepositoryConfig: p.Settings.RepositoryConfig,
@ -93,8 +95,24 @@ func (p *Pull) Run(chartRef string) (string, error) {
} }
if registry.IsOCI(chartRef) { if registry.IsOCI(chartRef) {
if !p.TlsEnabled {
c.Options = append(c.Options, c.Options = append(c.Options,
getter.WithRegistryClient(p.cfg.RegistryClient)) getter.WithRegistryClient(p.cfg.RegistryClient),
)
} else {
registryClient, err := registry.NewClient(
registry.ClientOptDebug(p.Settings.Debug),
registry.ClientOptCredentialsFile(p.Settings.RegistryConfig),
registry.ClientOptWriter(&out),
registry.ClientOptTwoWayTLSEnable(p.TlsEnabled),
registry.ClientOptChartRef(chartRef),
registry.ClientOptWithTLSOpts(tlsutil.Options{CaCertFile: p.CaFile, KeyFile: p.KeyFile, CertFile: p.CertFile, InsecureSkipVerify: p.InsecureSkipTLSverify}),
)
if err != nil {
return out.String(), err
}
c.Options = append(c.Options, getter.WithRegistryClient(registryClient))
}
} }
if p.Verify { if p.Verify {

@ -42,6 +42,7 @@ type options struct {
passCredentialsAll bool passCredentialsAll bool
userAgent string userAgent string
version string version string
tlsEnabled bool
registryClient *registry.Client registryClient *registry.Client
timeout time.Duration timeout time.Duration
transport *http.Transport transport *http.Transport
@ -87,6 +88,12 @@ func WithInsecureSkipVerifyTLS(insecureSkipVerifyTLS bool) Option {
} }
} }
func WithTwoWayTLSEnable(tlsEnabled bool) Option {
return func(opts *options) {
opts.tlsEnabled = tlsEnabled
}
}
// WithTLSClientConfig sets the client auth with the provided credentials. // WithTLSClientConfig sets the client auth with the provided credentials.
func WithTLSClientConfig(certFile, keyFile, caFile string) Option { func WithTLSClientConfig(certFile, keyFile, caFile string) Option {
return func(opts *options) { return func(opts *options) {

@ -22,9 +22,11 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net"
"net/http" "net/http"
"sort" "sort"
"strings" "strings"
"time"
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes"
@ -38,6 +40,7 @@ import (
registryremote "oras.land/oras-go/pkg/registry/remote" registryremote "oras.land/oras-go/pkg/registry/remote"
registryauth "oras.land/oras-go/pkg/registry/remote/auth" registryauth "oras.land/oras-go/pkg/registry/remote/auth"
"helm.sh/helm/v3/internal/tlsutil"
"helm.sh/helm/v3/internal/version" "helm.sh/helm/v3/internal/version"
"helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v3/pkg/helmpath"
@ -61,6 +64,9 @@ type (
authorizer auth.Client authorizer auth.Client
registryAuthorizer *registryauth.Client registryAuthorizer *registryauth.Client
resolver remotes.Resolver resolver remotes.Resolver
tlsEnabled bool
chartRef string
utilOpts tlsutil.Options
} }
// ClientOption allows specifying various settings configurable by the user for overriding the defaults // ClientOption allows specifying various settings configurable by the user for overriding the defaults
@ -87,6 +93,31 @@ func NewClient(options ...ClientOption) (*Client, error) {
client.authorizer = authClient client.authorizer = authClient
} }
if client.resolver == nil { if client.resolver == nil {
if client.tlsEnabled {
cfgtls, err := tlsutil.ClientConfig(client.utilOpts)
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(30 * time.Second),
DisableKeepAlives: true,
}
sClient := 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(&sClient)}
resolver, err := client.authorizer.ResolverWithOpts(opts...)
if err != nil {
return nil, err
}
client.resolver = resolver
} else {
headers := http.Header{} headers := http.Header{}
headers.Set("User-Agent", version.GetUserAgent()) headers.Set("User-Agent", version.GetUserAgent())
opts := []auth.ResolverOption{auth.WithResolverHeaders(headers)} opts := []auth.ResolverOption{auth.WithResolverHeaders(headers)}
@ -96,7 +127,7 @@ func NewClient(options ...ClientOption) (*Client, error) {
} }
client.resolver = resolver client.resolver = resolver
} }
}
// allocate a cache if option is set // allocate a cache if option is set
var cache registryauth.Cache var cache registryauth.Cache
if client.enableCache { if client.enableCache {
@ -159,6 +190,12 @@ func ClientOptWriter(out io.Writer) ClientOption {
} }
} }
func ClientOptChartRef(chartRef string) ClientOption {
return func(client *Client) {
client.chartRef = chartRef
}
}
// ClientOptCredentialsFile returns a function that sets the credentialsFile setting on a client options set // ClientOptCredentialsFile returns a function that sets the credentialsFile setting on a client options set
func ClientOptCredentialsFile(credentialsFile string) ClientOption { func ClientOptCredentialsFile(credentialsFile string) ClientOption {
return func(client *Client) { return func(client *Client) {
@ -166,6 +203,20 @@ func ClientOptCredentialsFile(credentialsFile string) ClientOption {
} }
} }
//ClientOptTwoWayTLSEnable returns a function that sets the client certificate when two-way tls authentication enable
func ClientOptTwoWayTLSEnable(tlsEnabled bool) ClientOption {
return func(client *Client) {
client.tlsEnabled = tlsEnabled
}
}
//ClientOptTwoWayTLSEnable returns a function that sets the client certificate when two-way tls authentication enable
func ClientOptWithTLSOpts(tlsOpts tlsutil.Options) ClientOption {
return func(client *Client) {
client.utilOpts = tlsOpts
}
}
type ( type (
// LoginOption allows specifying various settings on login // LoginOption allows specifying various settings on login
LoginOption func(*loginOperation) LoginOption func(*loginOperation)

Loading…
Cancel
Save