Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ RUN apt-get update && apt-get install -y \
python-mock \
python-pip \
zip \
gpgme-devel \
libassuan-devel \
&& pip install awscli==1.10.15
# Get lvm2 source for compiling statically
ENV LVM2_VERSION 2.02.103
Expand Down Expand Up @@ -285,6 +287,17 @@ RUN set -x \
&& cp bin/ctr /usr/local/bin/docker-containerd-ctr \
&& rm -rf "$GOPATH"

# Install skopeo
ENV SKOPEO_COMMIT v0.1.16
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/projectatomic/skopeo.git "$GOPATH/src/github.com/projectatomic/skopeo" \
&& cd "$GOPATH/src/github.com/projectatomic/skopeo" \
&& git checkout -q "$SKOPEO_COMMIT" \
&& make binary-local \
&& make install GO_MD2MAN="/usr/local/bin/go-md2man" \
&& rm -rf "$GOPATH"

# Wrap all commands in the "docker-in-docker" script to allow nested containers
ENTRYPOINT ["hack/dind"]

Expand Down
2 changes: 2 additions & 0 deletions daemon/config_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type Config struct {
Runtimes map[string]types.Runtime `json:"runtimes,omitempty"`
DefaultRuntime string `json:"default-runtime,omitempty"`
OOMScoreAdjust int `json:"oom-score-adjust,omitempty"`
SigCheck bool `json:"signature-verification"`
}

// bridgeConfig stores all the bridge driver specific
Expand Down Expand Up @@ -94,6 +95,7 @@ func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) strin
cmd.Var(runconfigopts.NewNamedRuntimeOpt("runtimes", &config.Runtimes, stockRuntimeName), []string{"-add-runtime"}, usageFn("Register an additional OCI compatible runtime"))
cmd.StringVar(&config.DefaultRuntime, []string{"-default-runtime"}, stockRuntimeName, usageFn("Default OCI runtime for containers"))
cmd.IntVar(&config.OOMScoreAdjust, []string{"-oom-score-adjust"}, -500, usageFn("Set the oom_score_adj for the daemon"))
cmd.BoolVar(&config.SigCheck, []string{"-signature-verification"}, true, usageFn("Check image's signatures on pull"))

config.attachExperimentalFlags(cmd, usageFn)
}
Expand Down
1 change: 1 addition & 0 deletions daemon/image_pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.
ImageStore: daemon.imageStore,
ReferenceStore: daemon.referenceStore,
DownloadManager: daemon.downloadManager,
SignatureCheck: daemon.configStore.SigCheck,
}

err := distribution.Pull(ctx, ref, imagePullConfig)
Expand Down
14 changes: 12 additions & 2 deletions distribution/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"strings"

"github.com/Sirupsen/logrus"
"github.com/containers/image/signature"
"github.com/docker/distribution/digest"
"github.com/docker/docker/api"
"github.com/docker/docker/distribution/metadata"
Expand Down Expand Up @@ -41,6 +42,8 @@ type ImagePullConfig struct {
ReferenceStore reference.Store
// DownloadManager manages concurrent pulls.
DownloadManager *xfer.LayerDownloadManager
// SignatureCheck controls whether to check image's signatures or not
SignatureCheck bool
}

// Puller is an interface that abstracts pulling for different API versions.
Expand All @@ -57,13 +60,22 @@ type Puller interface {
// through to the underlying puller implementation for use during the actual
// pull operation.
func newPuller(endpoint registry.APIEndpoint, repoInfo *registry.RepositoryInfo, imagePullConfig *ImagePullConfig) (Puller, error) {
var pc *signature.PolicyContext
if imagePullConfig.SignatureCheck {
var err error
pc, err = configurePolicyContext()
if err != nil {
return nil, err
}
}
switch endpoint.Version {
case registry.APIVersion2:
return &v2Puller{
V2MetadataService: metadata.NewV2MetadataService(imagePullConfig.MetadataStore),
endpoint: endpoint,
config: imagePullConfig,
repoInfo: repoInfo,
policyContext: pc,
}, nil
case registry.APIVersion1:
return &v1Puller{
Expand Down Expand Up @@ -97,15 +109,13 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
fqr, err := reference.QualifyUnqualifiedReference(ref, r)
if err != nil {
errStr := fmt.Sprintf("Failed to fully qualify %q name with %q registry: %v", ref.Name(), r, err)
progress.Message(imagePullConfig.ProgressOutput, "", errStr)
if i == len(registry.DefaultRegistries)-1 {
return fmt.Errorf(errStr)
}
continue
}
if err := pullFromRegistry(ctx, fqr, imagePullConfig); err != nil {
// make sure we get a final "Error response from daemon: "
progress.Message(imagePullConfig.ProgressOutput, "", err.Error())
if i == len(registry.DefaultRegistries)-1 {
return err
}
Expand Down
63 changes: 57 additions & 6 deletions distribution/pull_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"runtime"

"github.com/Sirupsen/logrus"
"github.com/containers/image/signature"
"github.com/docker/distribution"
"github.com/docker/distribution/digest"
"github.com/docker/distribution/manifest/manifestlist"
Expand Down Expand Up @@ -54,6 +55,9 @@ type v2Puller struct {
// confirmedV2 is set to true if we confirm we're talking to a v2
// registry. This is used to limit fallbacks to the v1 protocol.
confirmedV2 bool

policyContext *signature.PolicyContext
originalRef reference.Named
}

func (p *v2Puller) Pull(ctx context.Context, ref reference.Named) (err error) {
Expand Down Expand Up @@ -88,16 +92,26 @@ func (p *v2Puller) Pull(ctx context.Context, ref reference.Named) (err error) {
func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named) (err error) {
var layersDownloaded bool
if !reference.IsNameOnly(ref) {
var err error
if p.config.SignatureCheck {
ref, err = p.checkTrusted(ctx, ref)
if err != nil {
// do not fallback to v1 is there was any error checking image's signatures
return err
}
}
layersDownloaded, err = p.pullV2Tag(ctx, ref)
if err != nil {
return err
}
} else {
tags, err := p.repo.Tags(ctx).All(ctx)
if err != nil {
// If this repository doesn't exist on V2, we should
// permit a fallback to V1.
return allowV1Fallback(err)
if p.config.SignatureCheck {
return err
} else {
return allowV1Fallback(err)
}
}

// The v2 registry knows about this repository, so we will not
Expand All @@ -110,7 +124,17 @@ func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named) (e
if err != nil {
return err
}
pulledNew, err := p.pullV2Tag(ctx, tagRef)
var ref reference.Named
ref = tagRef
if p.config.SignatureCheck {
trustedRef, err := p.checkTrusted(ctx, tagRef)
if err != nil {
p.originalRef = nil
return err
}
ref = trustedRef
}
pulledNew, err := p.pullV2Tag(ctx, ref)
if err != nil {
// Since this is the pull-all-tags case, don't
// allow an error pulling a particular tag to
Expand All @@ -126,7 +150,9 @@ func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named) (e
}
}

writeStatus(ref.String(), p.config.ProgressOutput, layersDownloaded)
if p.originalRef != nil {
writeStatus(p.originalRef.String(), p.config.ProgressOutput, layersDownloaded)
}

return nil
}
Expand Down Expand Up @@ -344,7 +370,11 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat
// all registry versions.
manifest, err = manSvc.Get(ctx, "", distribution.WithTag(tagged.Tag()))
if err != nil {
return false, allowV1Fallback(err)
if p.config.SignatureCheck {
return false, err
} else {
return false, allowV1Fallback(err)
}
}
tagOrDigest = tagged.Tag()
} else if digested, isDigested := ref.(reference.Canonical); isDigested {
Expand Down Expand Up @@ -398,6 +428,11 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat
oldTagImageID, err := p.config.ReferenceStore.Get(ref)
if err == nil {
if oldTagImageID == imageID {
if p.config.SignatureCheck {
if err := p.addTrustedTag(imageID); err != nil {
return false, err
}
}
return false, addDigestReference(p.config.ReferenceStore, ref, manifestDigest, imageID)
}
} else if err != reference.ErrDoesNotExist {
Expand All @@ -408,6 +443,11 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat
if err = p.config.ReferenceStore.AddDigest(canonical, imageID, true); err != nil {
return false, err
}
if p.config.SignatureCheck {
if err := p.addTrustedTag(imageID); err != nil {
return false, err
}
}
} else {
if err = addDigestReference(p.config.ReferenceStore, ref, manifestDigest, imageID); err != nil {
return false, err
Expand All @@ -419,6 +459,17 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat
return true, nil
}

func (p *v2Puller) addTrustedTag(id image.ID) error {
if p.policyContext != nil {
if _, ok := p.originalRef.(reference.Canonical); !ok {
if err := p.config.ReferenceStore.AddTag(p.originalRef, id, true); err != nil {
return err
}
}
}
return nil
}

func (p *v2Puller) pullSchema1(ctx context.Context, ref reference.Named, unverifiedManifest *schema1.SignedManifest) (imageID image.ID, manifestDigest digest.Digest, err error) {
var verifiedManifest *schema1.Manifest
verifiedManifest, err = verifySchema1Manifest(unverifiedManifest, ref)
Expand Down
78 changes: 78 additions & 0 deletions distribution/pull_v2_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,22 @@
package distribution

import (
"fmt"

"github.com/containers/image/docker"
containersImageRef "github.com/containers/image/docker/reference"
"github.com/containers/image/manifest"
"github.com/containers/image/signature"
"github.com/containers/image/types"
"github.com/docker/distribution"
"github.com/docker/distribution/context"
"github.com/docker/distribution/digest"
"github.com/docker/distribution/manifest/schema1"
"github.com/docker/docker/dockerversion"
"github.com/docker/docker/image"
"github.com/docker/docker/reference"
"github.com/docker/docker/registry"
gctx "golang.org/x/net/context"
)

func detectBaseLayer(is image.Store, m *schema1.Manifest, rootFS *image.RootFS) error {
Expand All @@ -17,3 +29,69 @@ func (ld *v2LayerDescriptor) open(ctx context.Context) (distribution.ReadSeekClo
blobs := ld.repo.Blobs(ctx)
return blobs.Open(ctx, ld.digest)
}

func configurePolicyContext() (*signature.PolicyContext, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would putting these into a separate file make maintaining this patch easier?

defaultPolicy, err := signature.DefaultPolicy(nil)
if err != nil {
return nil, err
}
pc, err := signature.NewPolicyContext(defaultPolicy)
if err != nil {
return nil, err
}
return pc, nil
}

func (p *v2Puller) checkTrusted(c gctx.Context, ref reference.Named) (reference.Named, error) {
p.originalRef = ref
// we can't use upstream docker/docker/reference since in projectatomic/docker
// we modified docker/docker/reference and it's not doing any normalization.
// we instead forked docker/docker/reference in containers/image and we need
// this parsing here to make sure signature naming checks are consistent.
dockerRef, err := containersImageRef.ParseNamed(ref.String())
if err != nil {
return nil, err
}
imgRef, err := docker.NewReference(dockerRef)
if err != nil {
return nil, err
}
isSecure := (p.endpoint.TLSConfig == nil || !p.endpoint.TLSConfig.InsecureSkipVerify)
authConfig := registry.ResolveAuthConfig(p.config.AuthConfigs, p.repoInfo.Index)
dockerAuthConfig := types.DockerAuthConfig{
Username: authConfig.Username,
Password: authConfig.Password,
}
ctx := &types.SystemContext{
DockerInsecureSkipTLSVerify: !isSecure,
DockerAuthConfig: &dockerAuthConfig,
DockerRegistryUserAgent: dockerversion.DockerUserAgent(c),
}
img, err := imgRef.NewImage(ctx)
if err != nil {
return nil, err
}
allowed, err := p.policyContext.IsRunningImageAllowed(img)
if !allowed {
if err != nil {
return nil, fmt.Errorf("%s isn't allowed: %v", ref.String(), err)
}
return nil, fmt.Errorf("%s isn't allowed", ref.String())
}
if err != nil {
return nil, err
}
mfst, _, err := img.Manifest()
if err != nil {
return nil, err
}
dgst, err := manifest.Digest(mfst)
if err != nil {
return nil, err
}
ref, err = reference.WithDigest(ref, digest.Digest(dgst))
if err != nil {
return nil, err
}
return ref, nil
}
11 changes: 11 additions & 0 deletions distribution/pull_v2_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ import (
"net/http"
"os"

"github.com/containers/image/signature"
"github.com/docker/distribution"
"github.com/docker/distribution/context"
"github.com/docker/distribution/manifest/schema1"
"github.com/docker/distribution/manifest/schema2"
"github.com/docker/distribution/registry/client/transport"
"github.com/docker/docker/image"
"github.com/docker/docker/reference"
gctx "golang.org/x/net/context"
)

func detectBaseLayer(is image.Store, m *schema1.Manifest, rootFS *image.RootFS) error {
Expand Down Expand Up @@ -67,3 +70,11 @@ func (ld *v2LayerDescriptor) open(ctx context.Context) (distribution.ReadSeekClo
}
return rsc, err
}

func configurePolicyContext() (*signature.PolicyContext, error) {
return nil, nil
}

func (p *v2Puller) checkTrusted(c gctx.Context, ref reference.Named) (reference.Named, error) {
return ref, nil
}
11 changes: 11 additions & 0 deletions hack/make.sh
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,17 @@ install_binary() {
fi
}

install_policy() {
file="$1"
target="/etc/containers/policy.json"
if [ "$(go env GOOS)" == "linux" ]; then
if [ ! -e "/etc/containers/policy.json" ]; then
echo "Installing $(basename $file) to ${target}"
mkdir -p /etc/containers
cp -L "$file" "$target"
fi
fi
}

main() {
# We want this to fail if the bundles already exist and cannot be removed.
Expand Down
2 changes: 2 additions & 0 deletions hack/make/.integration-daemon-start
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ if [ "$(go env GOOS)" = 'windows' ]; then
return
fi

install_policy "$base/../../policy.json"

if [ -z "$DOCKER_TEST_HOST" ]; then
if docker version &> /dev/null; then
echo >&2 'skipping daemon start, since daemon appears to be already started'
Expand Down
1 change: 1 addition & 0 deletions hack/make/install-binary-daemon
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ rm -rf "$DEST"
source "${MAKEDIR}/.binary-setup"
install_binary "${DEST}/${DOCKER_DAEMON_BINARY_NAME}"
install_binary "${DEST}/${DOCKER_PROXY_BINARY_NAME}"
install_policy "${SCRIPTDIR}/../policy.json"
)
Loading