Skip to content

Commit

Permalink
Added support for insecure OCI registries
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Block <andy.block@gmail.com>
  • Loading branch information
sabre1041 committed Mar 3, 2023
1 parent b0ecb21 commit 08593c8
Show file tree
Hide file tree
Showing 17 changed files with 69 additions and 41 deletions.
9 changes: 6 additions & 3 deletions cmd/helm/push.go
Expand Up @@ -35,9 +35,10 @@ it will also be uploaded.
`

type registryPushOptions struct {
certFile string
keyFile string
caFile string
certFile string
keyFile string
caFile string
insecureSkipTLSverify bool
}

func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
Expand Down Expand Up @@ -70,6 +71,7 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
remote := args[1]
client := action.NewPushWithOpts(action.WithPushConfig(cfg),
action.WithTLSClientConfig(o.certFile, o.keyFile, o.caFile),
action.WithInsecureSkipTLSVerify(o.insecureSkipTLSverify),
action.WithPushOptWriter(out))
client.Settings = settings
output, err := client.Run(chartRef, remote)
Expand All @@ -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.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.BoolVar(&o.insecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart upload")

return cmd
}
6 changes: 4 additions & 2 deletions internal/tlsutil/tls.go
Expand Up @@ -25,8 +25,10 @@ import (
)

// NewClientTLS returns tls.Config appropriate for client auth.
func NewClientTLS(certFile, keyFile, caFile string) (*tls.Config, error) {
config := tls.Config{}
func NewClientTLS(certFile, keyFile, caFile string, insecureSkipTLSverify bool) (*tls.Config, error) {
config := tls.Config{
InsecureSkipVerify: insecureSkipTLSverify,
}

if certFile != "" && keyFile != "" {
cert, err := CertFromFilePair(certFile, keyFile)
Expand Down
7 changes: 4 additions & 3 deletions internal/tlsutil/tlsutil_test.go
Expand Up @@ -65,8 +65,9 @@ func TestNewClientTLS(t *testing.T) {
certFile := testfile(t, testCertFile)
keyFile := testfile(t, testKeyFile)
caCertFile := testfile(t, testCaCertFile)
insecureSkipTLSverify := false

cfg, err := NewClientTLS(certFile, keyFile, caCertFile)
cfg, err := NewClientTLS(certFile, keyFile, caCertFile, insecureSkipTLSverify)
if err != nil {
t.Error(err)
}
Expand All @@ -81,7 +82,7 @@ func TestNewClientTLS(t *testing.T) {
t.Fatalf("mismatch tls RootCAs, expecting non-nil")
}

cfg, err = NewClientTLS("", "", caCertFile)
cfg, err = NewClientTLS("", "", caCertFile, insecureSkipTLSverify)
if err != nil {
t.Error(err)
}
Expand All @@ -96,7 +97,7 @@ func TestNewClientTLS(t *testing.T) {
t.Fatalf("mismatch tls RootCAs, expecting non-nil")
}

cfg, err = NewClientTLS(certFile, keyFile, "")
cfg, err = NewClientTLS(certFile, keyFile, "", insecureSkipTLSverify)
if err != nil {
t.Error(err)
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/action/install.go
Expand Up @@ -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
// an error and a lookup will not occur.
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,
settings.RegistryConfig, settings.Debug)
c.InsecureSkipTLSverify, settings.RegistryConfig, settings.Debug)
if err != nil {
return "", err
}
Expand Down
5 changes: 3 additions & 2 deletions pkg/action/pull.go
Expand Up @@ -104,16 +104,17 @@ func (p *Pull) Run(chartRef string) (string, error) {
if registry.IsOCI(chartRef) {
// Provide a tls enabled client for the pull command if the user has
// 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,
p.Settings.RegistryConfig, p.Settings.Debug)
p.ChartPathOptions.InsecureSkipTLSverify, p.Settings.RegistryConfig, p.Settings.Debug)
if err != nil {
return out.String(), err
}
p.cfg.RegistryClient = registryClient
}
c.Options = append(c.Options,
getter.WithRegistryClient(p.cfg.RegistryClient))
c.RegistryClient = p.cfg.RegistryClient
}

if p.Verify {
Expand Down
24 changes: 16 additions & 8 deletions pkg/action/push.go
Expand Up @@ -30,12 +30,13 @@ import (
//
// It provides the implementation of 'helm push'.
type Push struct {
Settings *cli.EnvSettings
cfg *Configuration
certFile string
keyFile string
caFile string
out io.Writer
Settings *cli.EnvSettings
cfg *Configuration
certFile string
keyFile string
caFile string
insecureSkipTLSverify bool
out io.Writer
}

// PushOpt is a type of function that sets options for a push action.
Expand All @@ -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.
func WithPushOptWriter(out io.Writer) PushOpt {
return func(p *Push) {
Expand Down Expand Up @@ -88,9 +96,9 @@ func (p *Push) Run(chartRef string, remote string) (string, error) {
if registry.IsOCI(remote) {
// Provide a tls enabled client for the pull command if the user has
// 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,
p.Settings.RegistryConfig, p.Settings.Debug)
p.insecureSkipTLSverify, p.Settings.RegistryConfig, p.Settings.Debug)
if err != nil {
return out.String(), err
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/getter/httpgetter.go
Expand Up @@ -123,8 +123,8 @@ func (g *HTTPGetter) httpClient() (*http.Client, error) {
}
})

if (g.opts.certFile != "" && g.opts.keyFile != "") || g.opts.caFile != "" {
tlsConf, err := tlsutil.NewClientTLS(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, g.opts.insecureSkipVerifyTLS)
if err != nil {
return nil, errors.Wrap(err, "can't create TLS config for client")
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/getter/httpgetter_test.go
Expand Up @@ -285,9 +285,10 @@ func TestDownload(t *testing.T) {
func TestDownloadTLS(t *testing.T) {
cd := "../../testdata"
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) {}))
tlsConf, err := tlsutil.NewClientTLS(pub, priv, ca)
tlsConf, err := tlsutil.NewClientTLS(pub, priv, ca, insecureSkipTLSverify)
if err != nil {
t.Fatal(errors.Wrap(err, "can't create TLS config for client"))
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/getter/ocigetter.go
Expand Up @@ -122,8 +122,8 @@ func (g *OCIGetter) newRegistryClient() (*registry.Client, error) {
}
})

if (g.opts.certFile != "" && g.opts.keyFile != "") || g.opts.caFile != "" {
tlsConf, err := tlsutil.NewClientTLS(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, g.opts.insecureSkipVerifyTLS)
if err != nil {
return nil, fmt.Errorf("can't create TLS config for client: %w", err)
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/pusher/ocipusher.go
Expand Up @@ -106,8 +106,8 @@ func NewOCIPusher(ops ...Option) (Pusher, error) {
}

func (pusher *OCIPusher) newRegistryClient() (*registry.Client, error) {
if (pusher.opts.certFile != "" && pusher.opts.keyFile != "") || pusher.opts.caFile != "" {
tlsConf, err := tlsutil.NewClientTLS(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, pusher.opts.insecureSkipTLSverify)
if err != nil {
return nil, errors.Wrap(err, "can't create TLS config for client")
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/pusher/ocipusher_test.go
Expand Up @@ -35,10 +35,12 @@ func TestNewOCIPusher(t *testing.T) {
cd := "../../testdata"
join := filepath.Join
ca, pub, priv := join(cd, "rootca.crt"), join(cd, "crt.pem"), join(cd, "key.pem")
insecureSkipTLSverify := false

// Test with options
p, err = NewOCIPusher(
WithTLSClientConfig(pub, priv, ca),
WithInsecureSkipTLSVerify(insecureSkipTLSverify),
)
if err != nil {
t.Fatal(err)
Expand Down
16 changes: 12 additions & 4 deletions pkg/pusher/pusher.go
Expand Up @@ -27,10 +27,11 @@ import (
//
// Pushers may or may not ignore these parameters as they are passed in.
type options struct {
registryClient *registry.Client
certFile string
keyFile string
caFile string
registryClient *registry.Client
certFile string
keyFile string
caFile string
insecureSkipTLSverify bool
}

// Option allows specifying various settings configurable by the user for overriding the defaults
Expand All @@ -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.
type Pusher interface {
// Push file content by url string
Expand Down
2 changes: 1 addition & 1 deletion pkg/registry/client_test.go
Expand Up @@ -31,7 +31,7 @@ type RegistryClientTestSuite struct {

func (suite *RegistryClientTestSuite) SetupSuite() {
// init test client
dockerRegistry := setup(&suite.TestSuite, false)
dockerRegistry := setup(&suite.TestSuite, false, false)

// Start Docker registry
go dockerRegistry.ListenAndServe()
Expand Down
2 changes: 1 addition & 1 deletion pkg/registry/client_tls_test.go
Expand Up @@ -29,7 +29,7 @@ type TLSRegistryClientTestSuite struct {

func (suite *TLSRegistryClientTestSuite) SetupSuite() {
// init test client
dockerRegistry := setup(&suite.TestSuite, true)
dockerRegistry := setup(&suite.TestSuite, true, false)

// Start Docker registry
go dockerRegistry.ListenAndServe()
Expand Down
4 changes: 2 additions & 2 deletions pkg/registry/util.go
Expand Up @@ -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.
func NewRegistryClientWithTLS(out io.Writer, certFile, keyFile, caFile string, registryConfig string, debug bool) (*Client, error) {
tlsConf, err := tlsutil.NewClientTLS(certFile, keyFile, caFile)
func NewRegistryClientWithTLS(out io.Writer, certFile, keyFile, caFile string, insecureSkipTLSverify bool, registryConfig string, debug bool) (*Client, error) {
tlsConf, err := tlsutil.NewClientTLS(certFile, keyFile, caFile, insecureSkipTLSverify)
if err != nil {
return nil, fmt.Errorf("can't create TLS config for client: %s", err)
}
Expand Down
10 changes: 5 additions & 5 deletions pkg/registry/utils_test.go
Expand Up @@ -66,7 +66,7 @@ type TestSuite struct {
RegistryClient *Client
}

func setup(suite *TestSuite, secure bool) *registry.Registry {
func setup(suite *TestSuite, tlsEnabled bool, insecure bool) *registry.Registry {
suite.WorkspaceDir = testWorkspaceDir
os.RemoveAll(suite.WorkspaceDir)
os.Mkdir(suite.WorkspaceDir, 0700)
Expand All @@ -79,9 +79,9 @@ func setup(suite *TestSuite, secure bool) *registry.Registry {
credentialsFile := filepath.Join(suite.WorkspaceDir, CredentialsFileBasename)

// init test client
if secure {
if tlsEnabled {
var tlsConf *tls.Config
tlsConf, err = tlsutil.NewClientTLS(tlsCert, tlsKey, tlsCA)
tlsConf, err = tlsutil.NewClientTLS(tlsCert, tlsKey, tlsCA, insecure)
httpClient := &http.Client{
Transport: &http.Transport{
TLSClientConfig: tlsConf,
Expand Down Expand Up @@ -117,7 +117,7 @@ func setup(suite *TestSuite, secure bool) *registry.Registry {
config := &configuration.Configuration{}
port, err := freeport.GetFreePort()
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
// localhost, and is used to enforce http for localhost requests."
// That function does not handle matching of ip addresses in octal,
Expand All @@ -138,7 +138,7 @@ func setup(suite *TestSuite, secure bool) *registry.Registry {
}

// config tls
if secure {
if tlsEnabled {
// TLS config
// this set tlsConf.ClientAuth = tls.RequireAndVerifyClientCert in the
// server tls config
Expand Down
4 changes: 3 additions & 1 deletion pkg/repo/repotest/server.go
Expand Up @@ -360,14 +360,15 @@ func (s *Server) Start() {
func (s *Server) StartTLS() {
cd := "../../testdata"
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) {
if s.middleware != nil {
s.middleware.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 {
panic(err)
}
Expand Down Expand Up @@ -400,6 +401,7 @@ func (s *Server) Stop() {
// URL returns the URL of the server.
//
// Example:
//
// http://localhost:1776
func (s *Server) URL() string {
return s.srv.URL
Expand Down

0 comments on commit 08593c8

Please sign in to comment.