Added support for insecure OCI registries

Signed-off-by: Andrew Block <andy.block@gmail.com>
pull/11711/head
Andrew Block 2 years ago
parent b0ecb21056
commit 08593c8dd6
No known key found for this signature in database
GPG Key ID: 02DFE631AEF35EBC

@ -35,9 +35,10 @@ it will also be uploaded.
` `
type registryPushOptions struct { type registryPushOptions struct {
certFile string certFile string
keyFile string keyFile string
caFile string caFile string
insecureSkipTLSverify bool
} }
func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
@ -70,6 +71,7 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
remote := args[1] remote := args[1]
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.WithPushOptWriter(out)) action.WithPushOptWriter(out))
client.Settings = settings client.Settings = settings
output, err := client.Run(chartRef, remote) output, err := client.Run(chartRef, remote)
@ -85,6 +87,7 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
f.StringVar(&o.certFile, "cert-file", "", "identify registry client using this SSL certificate file") f.StringVar(&o.certFile, "cert-file", "", "identify registry client using this SSL certificate file")
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")
return cmd return cmd
} }

@ -25,8 +25,10 @@ import (
) )
// NewClientTLS returns tls.Config appropriate for client auth. // NewClientTLS returns tls.Config appropriate for client auth.
func NewClientTLS(certFile, keyFile, caFile string) (*tls.Config, error) { func NewClientTLS(certFile, keyFile, caFile string, insecureSkipTLSverify bool) (*tls.Config, error) {
config := tls.Config{} config := tls.Config{
InsecureSkipVerify: insecureSkipTLSverify,
}
if certFile != "" && keyFile != "" { if certFile != "" && keyFile != "" {
cert, err := CertFromFilePair(certFile, keyFile) cert, err := CertFromFilePair(certFile, keyFile)

@ -65,8 +65,9 @@ func TestNewClientTLS(t *testing.T) {
certFile := testfile(t, testCertFile) certFile := testfile(t, testCertFile)
keyFile := testfile(t, testKeyFile) keyFile := testfile(t, testKeyFile)
caCertFile := testfile(t, testCaCertFile) caCertFile := testfile(t, testCaCertFile)
insecureSkipTLSverify := false
cfg, err := NewClientTLS(certFile, keyFile, caCertFile) cfg, err := NewClientTLS(certFile, keyFile, caCertFile, insecureSkipTLSverify)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -81,7 +82,7 @@ func TestNewClientTLS(t *testing.T) {
t.Fatalf("mismatch tls RootCAs, expecting non-nil") t.Fatalf("mismatch tls RootCAs, expecting non-nil")
} }
cfg, err = NewClientTLS("", "", caCertFile) cfg, err = NewClientTLS("", "", caCertFile, insecureSkipTLSverify)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -96,7 +97,7 @@ func TestNewClientTLS(t *testing.T) {
t.Fatalf("mismatch tls RootCAs, expecting non-nil") t.Fatalf("mismatch tls RootCAs, expecting non-nil")
} }
cfg, err = NewClientTLS(certFile, keyFile, "") cfg, err = NewClientTLS(certFile, keyFile, "", insecureSkipTLSverify)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }

@ -680,9 +680,9 @@ func (c *ChartPathOptions) LocateChart(name string, out io.Writer, settings *cli
// If there is no registry client and the name is in an OCI registry return // If there is no registry client and the name is in an OCI registry return
// an error and a lookup will not occur. // an error and a lookup will not occur.
if registry.IsOCI(name) { if registry.IsOCI(name) {
if (c.CertFile != "" && c.KeyFile != "") || c.CaFile != "" { if (c.CertFile != "" && c.KeyFile != "") || c.CaFile != "" || c.InsecureSkipTLSverify {
registryClient, err := registry.NewRegistryClientWithTLS(out, c.CertFile, c.KeyFile, c.CaFile, registryClient, err := registry.NewRegistryClientWithTLS(out, c.CertFile, c.KeyFile, c.CaFile,
settings.RegistryConfig, settings.Debug) c.InsecureSkipTLSverify, settings.RegistryConfig, settings.Debug)
if err != nil { if err != nil {
return "", err return "", err
} }

@ -104,9 +104,9 @@ func (p *Pull) Run(chartRef string) (string, error) {
if registry.IsOCI(chartRef) { if registry.IsOCI(chartRef) {
// Provide a tls enabled client for the pull command if the user has // Provide a tls enabled client for the pull command if the user has
// specified the cert file or key file or ca file. // specified the cert file or key file or ca file.
if (p.ChartPathOptions.CertFile != "" && p.ChartPathOptions.KeyFile != "") || p.ChartPathOptions.CaFile != "" { if (p.ChartPathOptions.CertFile != "" && p.ChartPathOptions.KeyFile != "") || p.ChartPathOptions.CaFile != "" || p.ChartPathOptions.InsecureSkipTLSverify {
registryClient, err := registry.NewRegistryClientWithTLS(p.out, p.ChartPathOptions.CertFile, p.ChartPathOptions.KeyFile, p.ChartPathOptions.CaFile, registryClient, err := registry.NewRegistryClientWithTLS(p.out, p.ChartPathOptions.CertFile, p.ChartPathOptions.KeyFile, p.ChartPathOptions.CaFile,
p.Settings.RegistryConfig, p.Settings.Debug) p.ChartPathOptions.InsecureSkipTLSverify, p.Settings.RegistryConfig, p.Settings.Debug)
if err != nil { if err != nil {
return out.String(), err return out.String(), err
} }
@ -114,6 +114,7 @@ func (p *Pull) Run(chartRef string) (string, error) {
} }
c.Options = append(c.Options, c.Options = append(c.Options,
getter.WithRegistryClient(p.cfg.RegistryClient)) getter.WithRegistryClient(p.cfg.RegistryClient))
c.RegistryClient = p.cfg.RegistryClient
} }
if p.Verify { if p.Verify {

@ -30,12 +30,13 @@ import (
// //
// It provides the implementation of 'helm push'. // It provides the implementation of 'helm push'.
type Push struct { type Push struct {
Settings *cli.EnvSettings Settings *cli.EnvSettings
cfg *Configuration cfg *Configuration
certFile string certFile string
keyFile string keyFile string
caFile string caFile string
out io.Writer insecureSkipTLSverify bool
out io.Writer
} }
// PushOpt is a type of function that sets options for a push action. // PushOpt is a type of function that sets options for a push action.
@ -57,6 +58,13 @@ func WithTLSClientConfig(certFile, keyFile, caFile string) PushOpt {
} }
} }
// WithInsecureSkipTLSVerify determines if a TLS Certificate will be checked
func WithInsecureSkipTLSVerify(insecureSkipTLSVerify bool) PushOpt {
return func(p *Push) {
p.insecureSkipTLSverify = insecureSkipTLSVerify
}
}
// 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) {
@ -88,9 +96,9 @@ func (p *Push) Run(chartRef string, remote string) (string, error) {
if registry.IsOCI(remote) { if registry.IsOCI(remote) {
// Provide a tls enabled client for the pull command if the user has // Provide a tls enabled client for the pull command if the user has
// specified the cert file or key file or ca file. // specified the cert file or key file or ca file.
if (p.certFile != "" && p.keyFile != "") || p.caFile != "" { if (p.certFile != "" && p.keyFile != "") || p.caFile != "" || p.insecureSkipTLSverify {
registryClient, err := registry.NewRegistryClientWithTLS(p.out, p.certFile, p.keyFile, p.caFile, registryClient, err := registry.NewRegistryClientWithTLS(p.out, p.certFile, p.keyFile, p.caFile,
p.Settings.RegistryConfig, p.Settings.Debug) p.insecureSkipTLSverify, p.Settings.RegistryConfig, p.Settings.Debug)
if err != nil { if err != nil {
return out.String(), err return out.String(), err
} }

@ -123,8 +123,8 @@ func (g *HTTPGetter) httpClient() (*http.Client, error) {
} }
}) })
if (g.opts.certFile != "" && g.opts.keyFile != "") || g.opts.caFile != "" { if (g.opts.certFile != "" && g.opts.keyFile != "") || g.opts.caFile != "" || g.opts.insecureSkipVerifyTLS {
tlsConf, err := tlsutil.NewClientTLS(g.opts.certFile, g.opts.keyFile, g.opts.caFile) tlsConf, err := tlsutil.NewClientTLS(g.opts.certFile, g.opts.keyFile, g.opts.caFile, g.opts.insecureSkipVerifyTLS)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "can't create TLS config for client") return nil, errors.Wrap(err, "can't create TLS config for client")
} }

@ -285,9 +285,10 @@ func TestDownload(t *testing.T) {
func TestDownloadTLS(t *testing.T) { func TestDownloadTLS(t *testing.T) {
cd := "../../testdata" cd := "../../testdata"
ca, pub, priv := filepath.Join(cd, "rootca.crt"), filepath.Join(cd, "crt.pem"), filepath.Join(cd, "key.pem") ca, pub, priv := filepath.Join(cd, "rootca.crt"), filepath.Join(cd, "crt.pem"), filepath.Join(cd, "key.pem")
insecureSkipTLSverify := false
tlsSrv := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) tlsSrv := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
tlsConf, err := tlsutil.NewClientTLS(pub, priv, ca) tlsConf, err := tlsutil.NewClientTLS(pub, priv, ca, insecureSkipTLSverify)
if err != nil { if err != nil {
t.Fatal(errors.Wrap(err, "can't create TLS config for client")) t.Fatal(errors.Wrap(err, "can't create TLS config for client"))
} }

@ -122,8 +122,8 @@ func (g *OCIGetter) newRegistryClient() (*registry.Client, error) {
} }
}) })
if (g.opts.certFile != "" && g.opts.keyFile != "") || g.opts.caFile != "" { if (g.opts.certFile != "" && g.opts.keyFile != "") || g.opts.caFile != "" || g.opts.insecureSkipVerifyTLS {
tlsConf, err := tlsutil.NewClientTLS(g.opts.certFile, g.opts.keyFile, g.opts.caFile) tlsConf, err := tlsutil.NewClientTLS(g.opts.certFile, g.opts.keyFile, g.opts.caFile, g.opts.insecureSkipVerifyTLS)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't create TLS config for client: %w", err) return nil, fmt.Errorf("can't create TLS config for client: %w", err)
} }

@ -106,8 +106,8 @@ func NewOCIPusher(ops ...Option) (Pusher, error) {
} }
func (pusher *OCIPusher) newRegistryClient() (*registry.Client, error) { func (pusher *OCIPusher) newRegistryClient() (*registry.Client, error) {
if (pusher.opts.certFile != "" && pusher.opts.keyFile != "") || pusher.opts.caFile != "" { if (pusher.opts.certFile != "" && pusher.opts.keyFile != "") || pusher.opts.caFile != "" || pusher.opts.insecureSkipTLSverify {
tlsConf, err := tlsutil.NewClientTLS(pusher.opts.certFile, pusher.opts.keyFile, pusher.opts.caFile) tlsConf, err := tlsutil.NewClientTLS(pusher.opts.certFile, pusher.opts.keyFile, pusher.opts.caFile, pusher.opts.insecureSkipTLSverify)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "can't create TLS config for client") return nil, errors.Wrap(err, "can't create TLS config for client")
} }

@ -35,10 +35,12 @@ func TestNewOCIPusher(t *testing.T) {
cd := "../../testdata" cd := "../../testdata"
join := filepath.Join join := filepath.Join
ca, pub, priv := join(cd, "rootca.crt"), join(cd, "crt.pem"), join(cd, "key.pem") ca, pub, priv := join(cd, "rootca.crt"), join(cd, "crt.pem"), join(cd, "key.pem")
insecureSkipTLSverify := false
// Test with options // Test with options
p, err = NewOCIPusher( p, err = NewOCIPusher(
WithTLSClientConfig(pub, priv, ca), WithTLSClientConfig(pub, priv, ca),
WithInsecureSkipTLSVerify(insecureSkipTLSverify),
) )
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

@ -27,10 +27,11 @@ import (
// //
// Pushers may or may not ignore these parameters as they are passed in. // Pushers may or may not ignore these parameters as they are passed in.
type options struct { type options struct {
registryClient *registry.Client registryClient *registry.Client
certFile string certFile string
keyFile string keyFile string
caFile string caFile string
insecureSkipTLSverify 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
@ -53,6 +54,13 @@ func WithTLSClientConfig(certFile, keyFile, caFile string) Option {
} }
} }
// WithInsecureSkipTLSVerify determines if a TLS Certificate will be checked
func WithInsecureSkipTLSVerify(insecureSkipTLSVerify bool) Option {
return func(opts *options) {
opts.insecureSkipTLSverify = insecureSkipTLSVerify
}
}
// 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

@ -31,7 +31,7 @@ type RegistryClientTestSuite struct {
func (suite *RegistryClientTestSuite) SetupSuite() { func (suite *RegistryClientTestSuite) SetupSuite() {
// init test client // init test client
dockerRegistry := setup(&suite.TestSuite, false) dockerRegistry := setup(&suite.TestSuite, false, false)
// Start Docker registry // Start Docker registry
go dockerRegistry.ListenAndServe() go dockerRegistry.ListenAndServe()

@ -29,7 +29,7 @@ type TLSRegistryClientTestSuite struct {
func (suite *TLSRegistryClientTestSuite) SetupSuite() { func (suite *TLSRegistryClientTestSuite) SetupSuite() {
// init test client // init test client
dockerRegistry := setup(&suite.TestSuite, true) dockerRegistry := setup(&suite.TestSuite, true, false)
// Start Docker registry // Start Docker registry
go dockerRegistry.ListenAndServe() go dockerRegistry.ListenAndServe()

@ -133,8 +133,8 @@ func parseReference(raw string) (registry.Reference, error) {
} }
// NewRegistryClientWithTLS is a helper function to create a new registry client with TLS enabled. // NewRegistryClientWithTLS is a helper function to create a new registry client with TLS enabled.
func NewRegistryClientWithTLS(out io.Writer, certFile, keyFile, caFile string, registryConfig string, debug bool) (*Client, error) { func NewRegistryClientWithTLS(out io.Writer, certFile, keyFile, caFile string, insecureSkipTLSverify bool, registryConfig string, debug bool) (*Client, error) {
tlsConf, err := tlsutil.NewClientTLS(certFile, keyFile, caFile) tlsConf, err := tlsutil.NewClientTLS(certFile, keyFile, caFile, insecureSkipTLSverify)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't create TLS config for client: %s", err) return nil, fmt.Errorf("can't create TLS config for client: %s", err)
} }

@ -66,7 +66,7 @@ type TestSuite struct {
RegistryClient *Client RegistryClient *Client
} }
func setup(suite *TestSuite, secure bool) *registry.Registry { func setup(suite *TestSuite, tlsEnabled bool, insecure bool) *registry.Registry {
suite.WorkspaceDir = testWorkspaceDir suite.WorkspaceDir = testWorkspaceDir
os.RemoveAll(suite.WorkspaceDir) os.RemoveAll(suite.WorkspaceDir)
os.Mkdir(suite.WorkspaceDir, 0700) os.Mkdir(suite.WorkspaceDir, 0700)
@ -79,9 +79,9 @@ func setup(suite *TestSuite, secure bool) *registry.Registry {
credentialsFile := filepath.Join(suite.WorkspaceDir, CredentialsFileBasename) credentialsFile := filepath.Join(suite.WorkspaceDir, CredentialsFileBasename)
// init test client // init test client
if secure { if tlsEnabled {
var tlsConf *tls.Config var tlsConf *tls.Config
tlsConf, err = tlsutil.NewClientTLS(tlsCert, tlsKey, tlsCA) tlsConf, err = tlsutil.NewClientTLS(tlsCert, tlsKey, tlsCA, insecure)
httpClient := &http.Client{ httpClient := &http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
TLSClientConfig: tlsConf, TLSClientConfig: tlsConf,
@ -117,7 +117,7 @@ func setup(suite *TestSuite, secure bool) *registry.Registry {
config := &configuration.Configuration{} config := &configuration.Configuration{}
port, err := freeport.GetFreePort() port, err := freeport.GetFreePort()
suite.Nil(err, "no error finding free port for test registry") suite.Nil(err, "no error finding free port for test registry")
if secure { if tlsEnabled {
// docker has "MatchLocalhost is a host match function which returns true for // docker has "MatchLocalhost is a host match function which returns true for
// localhost, and is used to enforce http for localhost requests." // localhost, and is used to enforce http for localhost requests."
// That function does not handle matching of ip addresses in octal, // That function does not handle matching of ip addresses in octal,
@ -138,7 +138,7 @@ func setup(suite *TestSuite, secure bool) *registry.Registry {
} }
// config tls // config tls
if secure { if tlsEnabled {
// TLS config // TLS config
// this set tlsConf.ClientAuth = tls.RequireAndVerifyClientCert in the // this set tlsConf.ClientAuth = tls.RequireAndVerifyClientCert in the
// server tls config // server tls config

@ -360,6 +360,7 @@ func (s *Server) Start() {
func (s *Server) StartTLS() { func (s *Server) StartTLS() {
cd := "../../testdata" cd := "../../testdata"
ca, pub, priv := filepath.Join(cd, "rootca.crt"), filepath.Join(cd, "crt.pem"), filepath.Join(cd, "key.pem") ca, pub, priv := filepath.Join(cd, "rootca.crt"), filepath.Join(cd, "crt.pem"), filepath.Join(cd, "key.pem")
insecure := false
s.srv = httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { s.srv = httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if s.middleware != nil { if s.middleware != nil {
@ -367,7 +368,7 @@ func (s *Server) StartTLS() {
} }
http.FileServer(http.Dir(s.Root())).ServeHTTP(w, r) http.FileServer(http.Dir(s.Root())).ServeHTTP(w, r)
})) }))
tlsConf, err := tlsutil.NewClientTLS(pub, priv, ca) tlsConf, err := tlsutil.NewClientTLS(pub, priv, ca, insecure)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -400,6 +401,7 @@ func (s *Server) Stop() {
// URL returns the URL of the server. // URL returns the URL of the server.
// //
// Example: // Example:
//
// http://localhost:1776 // http://localhost:1776
func (s *Server) URL() string { func (s *Server) URL() string {
return s.srv.URL return s.srv.URL

Loading…
Cancel
Save