oci: Add flag `--plain-http` to enable working with HTTP registries

Add a new flag `--plain-http` to the following commands:
* `helm install`
* `helm pull`
* `helm push`
* `helm template`
* `helm upgrade`
* `helm show`

This flag instructs the registry client to use plain HTTP connections,
thus enabling upload/download of charts from OCI registries served at
an HTTP endpoint.

Signed-off-by: Sanskar Jaiswal <jaiswalsanskar078@gmail.com>
pull/12128/head
Sanskar Jaiswal 1 year ago
parent 1c4885fce7
commit 2538b927a7
No known key found for this signature in database
GPG Key ID: 5982D0279C227FFD

@ -61,6 +61,7 @@ func addChartPathOptionsFlags(f *pflag.FlagSet, c *action.ChartPathOptions) {
f.StringVar(&c.CertFile, "cert-file", "", "identify HTTPS client using this SSL certificate file") f.StringVar(&c.CertFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
f.StringVar(&c.KeyFile, "key-file", "", "identify HTTPS client using this SSL key file") 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.BoolVar(&c.InsecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart download")
f.BoolVar(&c.PlainHTTP, "plain-http", false, "use insecure HTTP connections 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")
} }

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

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

@ -39,6 +39,7 @@ type registryPushOptions struct {
keyFile string keyFile string
caFile string caFile string
insecureSkipTLSverify bool insecureSkipTLSverify bool
plainHTTP bool
} }
func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
@ -67,7 +68,7 @@ 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) 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)
} }
@ -77,6 +78,7 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
client := action.NewPushWithOpts(action.WithPushConfig(cfg), client := action.NewPushWithOpts(action.WithPushConfig(cfg),
action.WithTLSClientConfig(o.certFile, o.keyFile, o.caFile), action.WithTLSClientConfig(o.certFile, o.keyFile, o.caFile),
action.WithInsecureSkipTLSVerify(o.insecureSkipTLSverify), action.WithInsecureSkipTLSVerify(o.insecureSkipTLSverify),
action.WithPlainHTTP(o.plainHTTP),
action.WithPushOptWriter(out)) action.WithPushOptWriter(out))
client.Settings = settings client.Settings = settings
output, err := client.Run(chartRef, remote) output, err := client.Run(chartRef, remote)
@ -93,6 +95,7 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
f.StringVar(&o.keyFile, "key-file", "", "identify registry client using this SSL key file") f.StringVar(&o.keyFile, "key-file", "", "identify registry client using this SSL key file")
f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") 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 chart upload") f.BoolVar(&o.insecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart upload")
f.BoolVar(&o.plainHTTP, "plain-http", false, "use insecure HTTP connections for the chart upload")
return cmd return cmd
} }

@ -152,7 +152,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() registryClient, err := newDefaultRegistryClient(false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -257,7 +257,7 @@ func checkForExpiredRepos(repofile string) {
} }
func newRegistryClient(certFile, keyFile, caFile string, insecureSkipTLSverify bool) (*registry.Client, error) { func newRegistryClient(certFile, keyFile, caFile string, insecureSkipTLSverify, plainHTTP bool) (*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)
if err != nil { if err != nil {
@ -265,21 +265,26 @@ func newRegistryClient(certFile, keyFile, caFile string, insecureSkipTLSverify b
} }
return registryClient, nil return registryClient, nil
} }
registryClient, err := newDefaultRegistryClient() registryClient, err := newDefaultRegistryClient(plainHTTP)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return registryClient, nil return registryClient, nil
} }
func newDefaultRegistryClient() (*registry.Client, error) { func newDefaultRegistryClient(plainHTTP bool) (*registry.Client, error) {
// Create a new registry client opts := []registry.ClientOption{
registryClient, err := registry.NewClient(
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),
) }
if plainHTTP {
opts = append(opts, registry.ClientOptPlainHTTP())
}
// Create a new registry client
registryClient, err := registry.NewClient(opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -226,7 +226,8 @@ 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, client.InsecureSkipTLSverify) registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile,
client.InsecureSkipTLSverify, client.PlainHTTP)
if err != nil { if err != nil {
return fmt.Errorf("missing registry client: %w", err) return fmt.Errorf("missing registry client: %w", err)
} }

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

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

@ -114,6 +114,7 @@ type ChartPathOptions struct {
CertFile string // --cert-file CertFile string // --cert-file
KeyFile string // --key-file KeyFile string // --key-file
InsecureSkipTLSverify bool // --insecure-skip-verify InsecureSkipTLSverify bool // --insecure-skip-verify
PlainHTTP bool // --plain-http
Keyring string // --keyring Keyring string // --keyring
Password string // --password Password string // --password
PassCredentialsAll bool // --pass-credentials PassCredentialsAll bool // --pass-credentials
@ -733,6 +734,7 @@ func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) (
getter.WithPassCredentialsAll(c.PassCredentialsAll), getter.WithPassCredentialsAll(c.PassCredentialsAll),
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),
}, },
RepositoryConfig: settings.RepositoryConfig, RepositoryConfig: settings.RepositoryConfig,
RepositoryCache: settings.RepositoryCache, RepositoryCache: settings.RepositoryCache,

@ -90,6 +90,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.WithPlainHTTP(p.PlainHTTP),
}, },
RegistryClient: p.cfg.RegistryClient, RegistryClient: p.cfg.RegistryClient,
RepositoryConfig: p.Settings.RepositoryConfig, RepositoryConfig: p.Settings.RepositoryConfig,

@ -36,6 +36,7 @@ type Push struct {
keyFile string keyFile string
caFile string caFile string
insecureSkipTLSverify bool insecureSkipTLSverify bool
plainHTTP bool
out io.Writer out io.Writer
} }
@ -65,6 +66,13 @@ func WithInsecureSkipTLSVerify(insecureSkipTLSVerify bool) PushOpt {
} }
} }
// WithPlainHTTP configures the use of plain HTTP connections.
func WithPlainHTTP(plainHTTP bool) PushOpt {
return func(p *Push) {
p.plainHTTP = plainHTTP
}
}
// WithOptWriter sets the registryOut field on the push configuration object. // WithOptWriter sets the registryOut field on the push configuration object.
func WithPushOptWriter(out io.Writer) PushOpt { func WithPushOptWriter(out io.Writer) PushOpt {
return func(p *Push) { return func(p *Push) {
@ -91,6 +99,7 @@ func (p *Push) Run(chartRef string, remote string) (string, error) {
Options: []pusher.Option{ Options: []pusher.Option{
pusher.WithTLSClientConfig(p.certFile, p.keyFile, p.caFile), pusher.WithTLSClientConfig(p.certFile, p.keyFile, p.caFile),
pusher.WithInsecureSkipTLSVerify(p.insecureSkipTLSverify), pusher.WithInsecureSkipTLSVerify(p.insecureSkipTLSverify),
pusher.WithPlainHTTP(p.plainHTTP),
}, },
} }

@ -37,6 +37,7 @@ type options struct {
caFile string caFile string
unTar bool unTar bool
insecureSkipVerifyTLS bool insecureSkipVerifyTLS bool
plainHTTP bool
username string username string
password string password string
passCredentialsAll bool passCredentialsAll bool
@ -96,6 +97,12 @@ func WithTLSClientConfig(certFile, keyFile, caFile string) Option {
} }
} }
func WithPlainHTTP(plainHTTP bool) Option {
return func(opts *options) {
opts.plainHTTP = plainHTTP
}
}
// WithTimeout sets the timeout for requests // WithTimeout sets the timeout for requests
func WithTimeout(timeout time.Duration) Option { func WithTimeout(timeout time.Duration) Option {
return func(opts *options) { return func(opts *options) {

@ -137,12 +137,15 @@ func (g *OCIGetter) newRegistryClient() (*registry.Client, error) {
g.transport.TLSClientConfig = tlsConf g.transport.TLSClientConfig = tlsConf
} }
client, err := registry.NewClient( opts := []registry.ClientOption{registry.ClientOptHTTPClient(&http.Client{
registry.ClientOptHTTPClient(&http.Client{ Transport: g.transport,
Transport: g.transport, Timeout: g.opts.timeout,
Timeout: g.opts.timeout, })}
}), if g.opts.plainHTTP {
) opts = append(opts, registry.ClientOptPlainHTTP())
}
client, err := registry.NewClient(opts...)
if err != nil { if err != nil {
return nil, err return nil, err

@ -139,9 +139,12 @@ func (pusher *OCIPusher) newRegistryClient() (*registry.Client, error) {
return registryClient, nil return registryClient, nil
} }
registryClient, err := registry.NewClient( opts := []registry.ClientOption{registry.ClientOptEnableCache(true)}
registry.ClientOptEnableCache(true), if pusher.opts.plainHTTP {
) opts = append(opts, registry.ClientOptPlainHTTP())
}
registryClient, err := registry.NewClient(opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -32,6 +32,7 @@ type options struct {
keyFile string keyFile string
caFile string caFile string
insecureSkipTLSverify bool insecureSkipTLSverify bool
plainHTTP bool
} }
// Option allows specifying various settings configurable by the user for overriding the defaults // Option allows specifying various settings configurable by the user for overriding the defaults
@ -61,6 +62,12 @@ func WithInsecureSkipTLSVerify(insecureSkipTLSVerify bool) Option {
} }
} }
func WithPlainHTTP(plainHTTP bool) Option {
return func(opts *options) {
opts.plainHTTP = plainHTTP
}
}
// Pusher is an interface to support upload to the specified URL. // Pusher is an interface to support upload to the specified URL.
type Pusher interface { type Pusher interface {
// Push file content by url string // Push file content by url string

@ -61,6 +61,7 @@ type (
registryAuthorizer *registryauth.Client registryAuthorizer *registryauth.Client
resolver remotes.Resolver resolver remotes.Resolver
httpClient *http.Client httpClient *http.Client
plainHTTP bool
} }
// 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
@ -93,6 +94,9 @@ func NewClient(options ...ClientOption) (*Client, error) {
if client.httpClient != nil { if client.httpClient != nil {
opts = append(opts, auth.WithResolverClient(client.httpClient)) opts = append(opts, auth.WithResolverClient(client.httpClient))
} }
if client.plainHTTP {
opts = append(opts, auth.WithResolverPlainHTTP())
}
resolver, err := client.authorizer.ResolverWithOpts(opts...) resolver, err := client.authorizer.ResolverWithOpts(opts...)
if err != nil { if err != nil {
return nil, err return nil, err
@ -177,6 +181,12 @@ func ClientOptHTTPClient(httpClient *http.Client) ClientOption {
} }
} }
func ClientOptPlainHTTP() ClientOption {
return func(c *Client) {
c.plainHTTP = true
}
}
type ( type (
// LoginOption allows specifying various settings on login // LoginOption allows specifying various settings on login
LoginOption func(*loginOperation) LoginOption func(*loginOperation)
@ -626,23 +636,14 @@ func (c *Client) Tags(ref string) ([]string, error) {
repository := registryremote.Repository{ repository := registryremote.Repository{
Reference: parsedReference, Reference: parsedReference,
Client: c.registryAuthorizer, Client: c.registryAuthorizer,
PlainHTTP: c.plainHTTP,
} }
var registryTags []string var registryTags []string
for { registryTags, err = registry.Tags(ctx(c.out, c.debug), &repository)
registryTags, err = registry.Tags(ctx(c.out, c.debug), &repository) if err != nil {
if err != nil { return nil, err
// Fallback to http based request
if !repository.PlainHTTP && strings.Contains(err.Error(), "server gave HTTP response") {
repository.PlainHTTP = true
continue
}
return nil, err
}
break
} }
var tagVersions []*semver.Version var tagVersions []*semver.Version

Loading…
Cancel
Save