Skip to content

Commit

Permalink
lib/backend/registrybackend/security: Disable automated HTTP fallback (
Browse files Browse the repository at this point in the history
  • Loading branch information
orirawlings authored May 1, 2020
1 parent dac6d1e commit e8b9a9f
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 31 deletions.
28 changes: 15 additions & 13 deletions lib/backend/registrybackend/blobclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,42 +75,42 @@ func NewBlobClient(config Config) (*BlobClient, error) {

// Stat sends a HEAD request to registry for a blob and returns the blob size.
func (c *BlobClient) Stat(namespace, name string) (*core.BlobInfo, error) {
opt, err := c.authenticator.Authenticate(namespace)
opts, err := c.authenticator.Authenticate(namespace)
if err != nil {
return nil, fmt.Errorf("get security opt: %s", err)
}

info, err := c.statHelper(namespace, name, _layerquery, opt)
info, err := c.statHelper(namespace, name, _layerquery, opts)
if err != nil && err == backenderrors.ErrBlobNotFound {
// Docker registry does not support querying manifests with blob path.
log.Infof("Blob %s unknown to registry. Tring to stat manifest instead", name)
info, err = c.statHelper(namespace, name, _manifestquery, opt)
info, err = c.statHelper(namespace, name, _manifestquery, opts)
}
return info, err
}

// Download gets a blob from registry.
func (c *BlobClient) Download(namespace, name string, dst io.Writer) error {
opt, err := c.authenticator.Authenticate(namespace)
opts, err := c.authenticator.Authenticate(namespace)
if err != nil {
return fmt.Errorf("get security opt: %s", err)
}

err = c.downloadHelper(namespace, name, _layerquery, dst, opt)
err = c.downloadHelper(namespace, name, _layerquery, dst, opts)
if err != nil && err == backenderrors.ErrBlobNotFound {
// Docker registry does not support querying manifests with blob path.
log.Infof("Blob %s unknown to registry. Tring to download manifest instead", name)
err = c.downloadHelper(namespace, name, _manifestquery, dst, opt)
err = c.downloadHelper(namespace, name, _manifestquery, dst, opts)
}
return err
}

func (c *BlobClient) statHelper(namespace, name, query string, opt httputil.SendOption) (*core.BlobInfo, error) {
func (c *BlobClient) statHelper(namespace, name, query string, opts []httputil.SendOption) (*core.BlobInfo, error) {
URL := fmt.Sprintf(query, c.config.Address, namespace, name)
resp, err := httputil.Head(
URL,
opt,
httputil.SendAcceptedCodes(http.StatusOK))
append(opts, httputil.SendAcceptedCodes(http.StatusOK))...,
)
if err != nil {
if httputil.IsNotFound(err) {
return nil, backenderrors.ErrBlobNotFound
Expand All @@ -125,13 +125,15 @@ func (c *BlobClient) statHelper(namespace, name, query string, opt httputil.Send
return core.NewBlobInfo(size), nil
}

func (c *BlobClient) downloadHelper(namespace, name, query string, dst io.Writer, opt httputil.SendOption) error {
func (c *BlobClient) downloadHelper(namespace, name, query string, dst io.Writer, opts []httputil.SendOption) error {
URL := fmt.Sprintf(query, c.config.Address, namespace, name)
resp, err := httputil.Get(
URL,
opt,
httputil.SendAcceptedCodes(http.StatusOK),
httputil.SendTimeout(c.config.Timeout),
append(
opts,
httputil.SendAcceptedCodes(http.StatusOK),
httputil.SendTimeout(c.config.Timeout),
)...,
)
if err != nil {
if httputil.IsNotFound(err) {
Expand Down
6 changes: 3 additions & 3 deletions lib/backend/registrybackend/blobclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func TestBlobDownloadBlobSuccess(t *testing.T) {
addr, stop := testutil.StartServer(r)
defer stop()

config := Config{Address: addr}
config := newTestConfig(addr)
client, err := NewBlobClient(config)
require.NoError(err)

Expand Down Expand Up @@ -85,7 +85,7 @@ func TestBlobDownloadManifestSuccess(t *testing.T) {
addr, stop := testutil.StartServer(r)
defer stop()

config := Config{Address: addr}
config := newTestConfig(addr)
client, err := NewBlobClient(config)
require.NoError(err)

Expand Down Expand Up @@ -115,7 +115,7 @@ func TestBlobDownloadFileNotFound(t *testing.T) {
addr, stop := testutil.StartServer(r)
defer stop()

config := Config{Address: addr}
config := newTestConfig(addr)
client, err := NewBlobClient(config)
require.NoError(err)

Expand Down
26 changes: 26 additions & 0 deletions lib/backend/registrybackend/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) 2016-2019 Uber Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package registrybackend

import "github.com/uber/kraken/lib/backend/registrybackend/security"

func newTestConfig(addr string) Config {
return Config{
Address: addr,
Security: security.Config{
EnableHTTPFallback: true,
},
}
}
20 changes: 15 additions & 5 deletions lib/backend/registrybackend/security/security.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,15 @@ type Config struct {
TLS httputil.TLSConfig `yaml:"tls"`
BasicAuth *types.AuthConfig `yaml:"basic"`
RemoteCredentialsStore string `yaml:"credsStore"`
EnableHTTPFallback bool `yaml:"enableHTTPFallback"`
}

// Authenticator creates send options to authenticate requests to registry
// backends.
type Authenticator interface {
// Authenticate returns a send option to authenticate to the registry,
// scoped to the given image repository.
Authenticate(repo string) (httputil.SendOption, error)
Authenticate(repo string) ([]httputil.SendOption, error)
}

type authenticator struct {
Expand Down Expand Up @@ -89,18 +90,27 @@ func NewAuthenticator(address string, config Config) (Authenticator, error) {
}, nil
}

func (a *authenticator) Authenticate(repo string) (httputil.SendOption, error) {
func (a *authenticator) Authenticate(repo string) ([]httputil.SendOption, error) {
config := a.config

var opts []httputil.SendOption
if config.TLS.Client.Disabled {
return httputil.SendNoop(), nil
opts = append(opts, httputil.SendNoop())
return opts, nil
}

if !config.EnableHTTPFallback {
opts = append(opts, httputil.DisableHTTPFallback())
}
if !a.shouldAuth() {
return httputil.SendTLSTransport(a.roundTripper), nil
opts = append(opts, httputil.SendTLSTransport(a.roundTripper))
return opts, nil
}
if err := a.updateChallenge(); err != nil {
return nil, fmt.Errorf("could not update auth challenge: %s", err)
}
return httputil.SendTLSTransport(a.transport(repo)), nil
opts = append(opts, httputil.SendTLSTransport(a.transport(repo)))
return opts, nil
}

func (a *authenticator) shouldAuth() bool {
Expand Down
22 changes: 14 additions & 8 deletions lib/backend/registrybackend/tagclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,20 @@ func (c *TagClient) Stat(namespace, name string) (*core.BlobInfo, error) {
}
repo, tag := tokens[0], tokens[1]

opt, err := c.authenticator.Authenticate(repo)
opts, err := c.authenticator.Authenticate(repo)
if err != nil {
return nil, fmt.Errorf("get security opt: %s", err)
}

URL := fmt.Sprintf(_tagquery, c.config.Address, repo, tag)
resp, err := httputil.Head(
URL,
opt,
httputil.SendHeaders(map[string]string{"Accept": _v2ManifestType}),
httputil.SendAcceptedCodes(http.StatusOK, http.StatusNotFound))
append(
opts,
httputil.SendHeaders(map[string]string{"Accept": _v2ManifestType}),
httputil.SendAcceptedCodes(http.StatusOK, http.StatusNotFound),
)...,
)
if err != nil {
return nil, fmt.Errorf("check blob exists: %s", err)
}
Expand All @@ -115,17 +118,20 @@ func (c *TagClient) Download(namespace, name string, dst io.Writer) error {
}
repo, tag := tokens[0], tokens[1]

opt, err := c.authenticator.Authenticate(repo)
opts, err := c.authenticator.Authenticate(repo)
if err != nil {
return fmt.Errorf("get security opt: %s", err)
}

URL := fmt.Sprintf(_tagquery, c.config.Address, repo, tag)
resp, err := httputil.Get(
URL,
opt,
httputil.SendHeaders(map[string]string{"Accept": _v2ManifestType}),
httputil.SendAcceptedCodes(http.StatusOK, http.StatusNotFound))
append(
opts,
httputil.SendHeaders(map[string]string{"Accept": _v2ManifestType}),
httputil.SendAcceptedCodes(http.StatusOK, http.StatusNotFound),
)...,
)
if err != nil {
return fmt.Errorf("check blob exists: %s", err)
}
Expand Down
4 changes: 2 additions & 2 deletions lib/backend/registrybackend/tagclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func TestTagDownloadSuccess(t *testing.T) {
addr, stop := testutil.StartServer(r)
defer stop()

config := Config{Address: addr}
config := newTestConfig(addr)
client, err := NewTagClient(config)
require.NoError(err)

Expand Down Expand Up @@ -87,7 +87,7 @@ func TestTagDownloadFileNotFound(t *testing.T) {
addr, stop := testutil.StartServer(r)
defer stop()

config := Config{Address: addr}
config := newTestConfig(addr)
client, err := NewTagClient(config)
require.NoError(err)

Expand Down

0 comments on commit e8b9a9f

Please sign in to comment.