Skip to content

Commit

Permalink
Insecure istag allows for insecure transport
Browse files Browse the repository at this point in the history
If the imagestream lacks insecure annotaion, make sure to honor insecure
tag import policy when pulling images.

Make sure to propage the insecure flag to all repositories belonging to
the insecure registry.

When finding pullthrough candidates, make sure to consider secure
repositories first. If not found, try the insecure repositories.

Signed-off-by: Michal Minář <[email protected]>
  • Loading branch information
Michal Minář committed Mar 8, 2017
1 parent f901770 commit 3e0d3ec
Show file tree
Hide file tree
Showing 14 changed files with 1,469 additions and 210 deletions.
54 changes: 52 additions & 2 deletions pkg/dockerregistry/server/blobdescriptorservice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ import (
imagetest "github.com/openshift/origin/pkg/image/admission/testutil"
)

const testPassthroughToUpstream = "openshift.test.passthrough-to-upstream"

func WithTestPassthroughToUpstream(ctx context.Context, passthrough bool) context.Context {
return context.WithValue(ctx, testPassthroughToUpstream, passthrough)
}

func GetTestPassThroughToUpstream(ctx context.Context) bool {
passthrough, found := ctx.Value(testPassthroughToUpstream).(bool)
return found && passthrough
}

// TestBlobDescriptorServiceIsApplied ensures that blobDescriptorService middleware gets applied.
// It relies on the fact that blobDescriptorService requires higher levels to set repository object on given
// context. If the object isn't given, its method will err out.
Expand All @@ -42,7 +53,7 @@ func TestBlobDescriptorServiceIsApplied(t *testing.T) {
// to make other unit tests working
defer m.changeUnsetRepository(false)

testImage, err := registrytest.NewImageForManifest("user/app", registrytest.SampleImageManifestSchema1, true)
testImage, err := registrytest.NewImageForManifest("user/app", registrytest.SampleImageManifestSchema1, "", true)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -93,7 +104,7 @@ func TestBlobDescriptorServiceIsApplied(t *testing.T) {
}
os.Setenv("DOCKER_REGISTRY_URL", serverURL.Host)

desc, _, err := registrytest.UploadTestBlob(serverURL, nil, "user/app")
desc, _, err := registrytest.UploadRandomTestBlob(serverURL, nil, "user/app")
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -510,3 +521,42 @@ func (f *fakeRegistryClient) Clients() (osclient.Interface, kclientset.Interface
func (f *fakeRegistryClient) SafeClientConfig() restclient.Config {
return (&registryClient{}).SafeClientConfig()
}

// passthroughBlobDescriptorService passes all Stat and Clear requests to
// custom blobDescriptorService by default. If
// "openshift.test.passthrough-to-upstream" is set on context with value
// "true", all the requests will be passed straight to the upstream blob
// descriptor service.
type passthroughBlobDescriptorService struct {
distribution.BlobDescriptorService
}

func (pbds *passthroughBlobDescriptorService) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
passthrough := GetTestPassThroughToUpstream(ctx)
if passthrough {
context.GetLogger(ctx).Debugf("(*passthroughBlobDescriptorService).Stat: passing down to upstream blob descriptor service")
return pbds.BlobDescriptorService.Stat(ctx, dgst)
}
context.GetLogger(ctx).Debugf("(*passthroughBlobDescriptorService).Stat: passing to openshift wrapper")
return (&blobDescriptorServiceFactory{}).BlobAccessController(pbds.BlobDescriptorService).Stat(ctx, dgst)
}

func (pbds *passthroughBlobDescriptorService) Clear(ctx context.Context, dgst digest.Digest) error {
passthrough := GetTestPassThroughToUpstream(ctx)
if passthrough {
context.GetLogger(ctx).Debugf("(*passthroughBlobDescriptorService).Clear: passing down to upstream blob descriptor service")
return pbds.BlobDescriptorService.Clear(ctx, dgst)
}
context.GetLogger(ctx).Debugf("(*passthroughBlobDescriptorService).Clear: passing to openshift wrapper")
return (&blobDescriptorServiceFactory{}).BlobAccessController(pbds.BlobDescriptorService).Clear(ctx, dgst)
}

type passthroughBlobDescriptorServiceFactory struct{}

func (pbf *passthroughBlobDescriptorServiceFactory) BlobAccessController(svc distribution.BlobDescriptorService) distribution.BlobDescriptorService {
return &passthroughBlobDescriptorService{svc}
}

func setPassthroughBlobDescriptorServiceFactory() {
middleware.RegisterOptions(storage.BlobDescriptorServiceFactory(&passthroughBlobDescriptorServiceFactory{}))
}
15 changes: 9 additions & 6 deletions pkg/dockerregistry/server/pullthroughblobstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ var _ distribution.BlobStore = &pullthroughBlobStore{}

// Stat makes a local check for the blob, then falls through to the other servers referenced by
// the image stream and looks for those that have the layer.
func (r *pullthroughBlobStore) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
func (pbs *pullthroughBlobStore) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
context.GetLogger(ctx).Debugf("(*pullthroughBlobStore).Stat: starting with dgst=%s", dgst.String())
// check the local store for the blob
desc, err := r.BlobStore.Stat(ctx, dgst)
desc, err := pbs.BlobStore.Stat(ctx, dgst)
switch {
case err == distribution.ErrBlobUnknown:
// continue on to the code below and look up the blob in a remote store since it is not in
Expand All @@ -38,7 +39,7 @@ func (r *pullthroughBlobStore) Stat(ctx context.Context, dgst digest.Digest) (di
return desc, err
}

return r.repo.remoteBlobGetter.Stat(ctx, dgst)
return pbs.repo.remoteBlobGetter.Stat(ctx, dgst)
}

// ServeBlob attempts to serve the requested digest onto w, using a remote proxy store if necessary.
Expand All @@ -47,6 +48,7 @@ func (r *pullthroughBlobStore) Stat(ctx context.Context, dgst digest.Digest) (di
// success response with no actual body content.
// [1] https://docs.docker.com/registry/spec/api/#existing-layers
func (pbs *pullthroughBlobStore) ServeBlob(ctx context.Context, w http.ResponseWriter, req *http.Request, dgst digest.Digest) error {
context.GetLogger(ctx).Debugf("(*pullthroughBlobStore).ServeBlob: starting with dgst=%s", dgst.String())
// This call should be done without BlobGetterService in the context.
err := pbs.BlobStore.ServeBlob(ctx, w, req, dgst)
switch {
Expand Down Expand Up @@ -89,13 +91,14 @@ func (pbs *pullthroughBlobStore) ServeBlob(ctx context.Context, w http.ResponseW
}

// Get attempts to fetch the requested blob by digest using a remote proxy store if necessary.
func (r *pullthroughBlobStore) Get(ctx context.Context, dgst digest.Digest) ([]byte, error) {
data, originalErr := r.BlobStore.Get(ctx, dgst)
func (pbs *pullthroughBlobStore) Get(ctx context.Context, dgst digest.Digest) ([]byte, error) {
context.GetLogger(ctx).Debugf("(*pullthroughBlobStore).Get: starting with dgst=%s", dgst.String())
data, originalErr := pbs.BlobStore.Get(ctx, dgst)
if originalErr == nil {
return data, nil
}

return r.repo.remoteBlobGetter.Get(ctx, dgst)
return pbs.repo.remoteBlobGetter.Get(ctx, dgst)
}

// setResponseHeaders sets the appropriate content serving headers
Expand Down
Loading

0 comments on commit 3e0d3ec

Please sign in to comment.