Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate SHA/Tag when checking docker images #30366

Merged
merged 1 commit into from
Aug 13, 2016

Conversation

dims
Copy link
Member

@dims dims commented Aug 10, 2016

Docker API does not validate the tag/sha, for example, all the following
calls work say for a alpine image with short SHA "4e38e38c8ce0"
echo -e "GET /images/alpine:4e38e38c8ce0/json HTTP/1.0\r\n" | nc -U /var/run/docker.sock
echo -e "GET /images/alpine:4e38e38c/json HTTP/1.0\r\n" | nc -U /var/run/docker.sock
echo -e "GET /images/alpine:4/json HTTP/1.0\r\n" | nc -U /var/run/docker.sock

So we should check the response from the Docker API and look for the tags or SHA explicitly.

Fixes #30355


This change is Reviewable

@dims dims force-pushed the fix-issue-30355 branch from c5b2314 to fba98e1 Compare August 10, 2016 14:28
@k8s-github-robot k8s-github-robot added size/S Denotes a PR that changes 10-29 lines, ignoring generated files. release-note-label-needed labels Aug 10, 2016
@yujuhong yujuhong added release-note-none Denotes a PR that doesn't merit a release note. and removed release-note-label-needed labels Aug 10, 2016
@@ -184,7 +185,27 @@ func (d *kubeDockerClient) InspectImage(image string) (*dockertypes.ImageInspect
}
return nil, err
}
return &resp, nil
parts := strings.SplitN(image, ":", 2)
Copy link
Contributor

Choose a reason for hiding this comment

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

Could probably reuse/share the logic in applyDefaultImageTag

_, isDigested := named.(dockerref.Digested)

@yujuhong
Copy link
Contributor

Could you add a unit test for this? Thanks!

/cc @Random-Liu

@dims
Copy link
Member Author

dims commented Aug 10, 2016

@yujuhong I don't see ANY tests for anything in this file !!

@yujuhong
Copy link
Contributor

yujuhong commented Aug 10, 2016

@yujuhong I don't see ANY tests for anything in this file !!

That's not a very good reason to not add a test, is it? :-)
I think this file was supposed to be a simple wrapper, but as we add more logic in it. It's worth adding tests for the additional logic. Especially now we have an ongoing integration with the new runtime interface (CRI), it'd be best to add tests for new changes to ensure that any regression would be caught in the new implementation.

The applyDefaultImageTag function actually has a test. In the same file, there are other image pulling tests as well. You can just add higher-level image pulling test there.

@dims
Copy link
Member Author

dims commented Aug 10, 2016

@yujuhong LOL, of course :)

@dims dims force-pushed the fix-issue-30355 branch from fba98e1 to 2e5518a Compare August 10, 2016 20:50
@k8s-github-robot k8s-github-robot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. and removed size/S Denotes a PR that changes 10-29 lines, ignoring generated files. labels Aug 10, 2016
@@ -184,6 +184,10 @@ func (d *kubeDockerClient) InspectImage(image string) (*dockertypes.ImageInspect
}
return nil, err
}
if !matchImageTagOrSHA(resp, image) {
err = imageNotFoundError{ID: image}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: just return nil, imageNotFoundError{ID: image}

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

@dims dims force-pushed the fix-issue-30355 branch from 2e5518a to 2c7a512 Compare August 10, 2016 21:40
// Check if the inspected image matches what we are looking for
func matchImageTagOrSHA(inspected dockertypes.ImageInspect, image string) bool {
parts := strings.SplitN(image, ":", 2)
if len(parts) == 1 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we reuse the same dockerref code for parsing the given string?

_, isDigested := named.(dockerref.Digested)

@yujuhong
Copy link
Contributor

!!! 'gofmt -s -w' needs to be run on the following files: 
./pkg/kubelet/dockertools/docker_test.go
FAILED   hack/make-rules/../../hack/verify-gofmt.sh 11s

Docker API does not validate the tag/sha, for example, all the following
calls work say for a alpine image with short SHA "4e38e38c8ce0"
echo -e "GET /images/alpine:4e38e38c8ce0/json HTTP/1.0\r\n" | nc -U /var/run/docker.sock
echo -e "GET /images/alpine:4e38e38c/json HTTP/1.0\r\n" | nc -U /var/run/docker.sock
echo -e "GET /images/alpine:4/json HTTP/1.0\r\n" | nc -U /var/run/docker.sock

So we should check the response from the Docker API and look for the
tags or SHA explicitly.

Fixes kubernetes#30355
@dims dims force-pushed the fix-issue-30355 branch from 2c7a512 to 875fd16 Compare August 11, 2016 12:53
@k8s-bot
Copy link

k8s-bot commented Aug 11, 2016

GCE e2e build/test passed for commit 875fd16.

@yujuhong yujuhong added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Aug 11, 2016
@k8s-github-robot
Copy link

@k8s-bot test this [submit-queue is verifying that this PR is safe to merge]

@k8s-bot
Copy link

k8s-bot commented Aug 13, 2016

GCE e2e build/test passed for commit 875fd16.

@k8s-github-robot
Copy link

Automatic merge from submit-queue

@k8s-github-robot k8s-github-robot merged commit 8a35d4c into kubernetes:master Aug 13, 2016
@smarterclayton
Copy link
Contributor

It looks correct on the Red Hat 1.10 I have but I don't think it was supported in Docker 1.9. Did we make a formal statement that we dropped 1.9?

@smarterclayton
Copy link
Contributor

I'm much less confident in RepoDigests being correct on every Docker variant version - probably couldn't say without trying a fair number of them.

@yujuhong
Copy link
Contributor

It looks correct on the Red Hat 1.10 I have but I don't think it was supported in Docker 1.9. Did we make a formal statement that we dropped 1.9?

I just checked 1.9 on my desktop and it reported correct RepoDigest nonetheless:

    "Id": "c38cc6bc48807ea450f17762c784114de8bf74ec1f33eab62b68d931f82ad167",
    "RepoTags": [],
    "RepoDigests": [
        "centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf"
    ],

@smarterclayton
Copy link
Contributor

Tomorrow I'll have someone look at the various 1.10 versions and make sure they're correct against schema 1.10. If i can prove that RepoDigest is correct I'll change the patch to prefer RepoDigests for a prefix match and then fall back to ID. The prefix match seemed slightly questionable, but I assume we validated there was no security risk in that?

@yujuhong
Copy link
Contributor

@smarterclayton thanks! Should we hold on to the PR #32627 for now until this is verified?

@yujuhong
Copy link
Contributor

but I assume we validated there was no security risk in that?

The motivation of adding this check is because docker's image inspection syntax is too loose and may mix up tags and digests. This is merely a sanity check to make sure docker has the right image. What security risk do you have in mind?

smarterclayton added a commit to smarterclayton/kubernetes that referenced this pull request Sep 14, 2016
Docker 1.10 does not guarantee that the pulled digest matches the digest
on disk when dealing with v1 schemas stored in a Docker registry. This
is the case for images like
centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf
which as a result of kubernetes#30366 cannot be pulled by Kube from a Docker 1.10
system.

Instead, use RepoDigests field as the primary match, validating the
digest, and then fall back to ID (also validating the match). Adds more
restrictive matching.
smarterclayton added a commit to smarterclayton/kubernetes that referenced this pull request Sep 14, 2016
Docker 1.10 does not guarantee that the pulled digest matches the digest
on disk when dealing with v1 schemas stored in a Docker registry. This
is the case for images like
centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf
which as a result of kubernetes#30366 cannot be pulled by Kube from a Docker 1.10
system.

Instead, use RepoDigests field as the primary match, validating the
digest, and then fall back to ID (also validating the match). Adds more
restrictive matching.
@smarterclayton
Copy link
Contributor

The prefix matching wasn't bounded, so you could get partial matches on tags by specifying part of a name that didn't end on a boundary:

pull "foo/bar:latest" would match "server/foo/bar:latest" as well as "superfoo/bar:latest"

@yujuhong
Copy link
Contributor

Yes, I had that in the comment and also in the comment from the PR #30789 (comment). There will be false positives. The alternative is to hard code the docker default registry (docker.io).

@smarterclayton
Copy link
Contributor

That's not enough because the default registry can be remapped. Basically, no tag prefix checking is really safe or accurate.

@smarterclayton
Copy link
Contributor

Only a SHA and a force verification can help

smarterclayton added a commit to smarterclayton/kubernetes that referenced this pull request Sep 14, 2016
Docker 1.10 does not guarantee that the pulled digest matches the digest
on disk when dealing with v1 schemas stored in a Docker registry. This
is the case for images like
centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf
which as a result of kubernetes#30366 cannot be pulled by Kube from a Docker 1.10
system.

Instead, use RepoDigests field as the primary match, validating the
digest, and then fall back to ID (also validating the match). Adds more
restrictive matching.
smarterclayton added a commit to smarterclayton/kubernetes that referenced this pull request Sep 14, 2016
Docker 1.10 does not guarantee that the pulled digest matches the digest
on disk when dealing with v1 schemas stored in a Docker registry. This
is the case for images like
centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf
which as a result of kubernetes#30366 cannot be pulled by Kube from a Docker 1.10
system.

Instead, use RepoDigests field as the primary match, validating the
digest, and then fall back to ID (also validating the match). Adds more
restrictive matching.
smarterclayton added a commit to smarterclayton/kubernetes that referenced this pull request Sep 14, 2016
Docker 1.10 does not guarantee that the pulled digest matches the digest
on disk when dealing with v1 schemas stored in a Docker registry. This
is the case for images like
centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf
which as a result of kubernetes#30366 cannot be pulled by Kube from a Docker 1.10
system.

Instead, use RepoDigests field as the primary match, validating the
digest, and then fall back to ID (also validating the match). Adds more
restrictive matching.
@yujuhong
Copy link
Contributor

That's not enough because the default registry can be remapped. Basically, no tag prefix checking is really safe or accurate.

Yes, it's a best effort check, which is better than nothing IMO.

@smarterclayton
Copy link
Contributor

But if it fails, you've broken a user who is doing something the container
engine allows.

On Wed, Sep 14, 2016 at 12:33 PM, Yu-Ju Hong notifications@github.com
wrote:

That's not enough because the default registry can be remapped. Basically,
no tag prefix checking is really safe or accurate.

Yes, it's a best effort check, which is better than nothing IMO.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#30366 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABG_p5siiG0LOGAMnDgICVsahOw5NZ5Kks5qqCHYgaJpZM4JhNAv
.

@smarterclayton
Copy link
Contributor

The tag check in this case fails closed (safer) but breaks allowed
scenarios. Remapping is really common in OpenShift production deployments

  • I'd say at least 50% of the enterprises I know of deploying docker at
    scale use registry remapping.

On Wed, Sep 14, 2016 at 12:57 PM, Clayton Coleman ccoleman@redhat.com
wrote:

But if it fails, you've broken a user who is doing something the container
engine allows.

On Wed, Sep 14, 2016 at 12:33 PM, Yu-Ju Hong notifications@github.com
wrote:

That's not enough because the default registry can be remapped.
Basically, no tag prefix checking is really safe or accurate.

Yes, it's a best effort check, which is better than nothing IMO.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#30366 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABG_p5siiG0LOGAMnDgICVsahOw5NZ5Kks5qqCHYgaJpZM4JhNAv
.

@yujuhong
Copy link
Contributor

yujuhong commented Sep 14, 2016

@smarterclayton I meant the current check (which checks only the suffix matches) allow false positive matches, so that it's not as strict, but would still catch some cases.

  • I'd say at least 50% of the enterprises I know of deploying docker at
    scale use registry remapping.

That's why I didn't hard code the registry name to enforce a more strict check.

@ncdc
Copy link
Member

ncdc commented Sep 14, 2016

Given that a prefix match against the inspected image's ID will match the config.digest of a schema version 2 image manifest, which is not a valid pull-by-id spec, the only way a prefix match can work is if you know:

  1. Node N has an image with ID A already on it (and remember, that's not the pull spec)
  2. Your pod specifies a container to run image ID A
  3. Your pod is scheduled to node N

@yujuhong
Copy link
Contributor

@ncdc I was talking about the "tag" check, not the digest check :-)

smarterclayton added a commit to smarterclayton/kubernetes that referenced this pull request Sep 14, 2016
Docker 1.10 does not guarantee that the pulled digest matches the digest
on disk when dealing with v1 schemas stored in a Docker registry. This
is the case for images like
centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf
which as a result of kubernetes#30366 cannot be pulled by Kube from a Docker 1.10
system.

Instead, use RepoDigests field as the primary match, validating the
digest, and then fall back to ID (also validating the match). Adds more
restrictive matching.
yujuhong pushed a commit to yujuhong/kubernetes that referenced this pull request Sep 14, 2016
Docker 1.10 does not guarantee that the pulled digest matches the digest
on disk when dealing with v1 schemas stored in a Docker registry. This
is the case for images like
centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf
which as a result of kubernetes#30366 cannot be pulled by Kube from a Docker 1.10
system.

Instead, use RepoDigests field as the primary match, validating the
digest, and then fall back to ID (also validating the match). Adds more
restrictive matching.
k8s-github-robot pushed a commit that referenced this pull request Sep 14, 2016
Automatic merge from submit-queue

Docker digest validation is too strict

Docker 1.10 does not guarantee that the pulled digest matches the digest
on disk when dealing with v1 schemas stored in a Docker registry. This
is the case for images like
centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf
which as a result of #30366 cannot be pulled by Kube from a Docker 1.10
system.

This partially reverts commit 875fd16.
eparis pushed a commit to eparis/kubernetes that referenced this pull request Sep 14, 2016
Automatic merge from submit-queue

Docker digest validation is too strict

Docker 1.10 does not guarantee that the pulled digest matches the digest
on disk when dealing with v1 schemas stored in a Docker registry. This
is the case for images like
centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf
which as a result of kubernetes#30366 cannot be pulled by Kube from a Docker 1.10
system.

This partially reverts commit 875fd16.
(cherry picked from commit b841a8b)
smarterclayton added a commit to smarterclayton/kubernetes that referenced this pull request Sep 15, 2016
Docker 1.10 does not guarantee that the pulled digest matches the digest
on disk when dealing with v1 schemas stored in a Docker registry. This
is the case for images like
centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf
which as a result of kubernetes#30366 cannot be pulled by Kube from a Docker 1.10
system.

Instead, use RepoDigests field as the primary match, validating the
digest, and then fall back to ID (also validating the match). Adds more
restrictive matching.
shyamjvs pushed a commit to shyamjvs/kubernetes that referenced this pull request Dec 1, 2016
Automatic merge from submit-queue

Docker digest validation is too strict

Docker 1.10 does not guarantee that the pulled digest matches the digest
on disk when dealing with v1 schemas stored in a Docker registry. This
is the case for images like
centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf
which as a result of kubernetes#30366 cannot be pulled by Kube from a Docker 1.10
system.

This partially reverts commit 875fd16.
(cherry picked from commit b841a8b)
@dims dims deleted the fix-issue-30355 branch November 16, 2017 22:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lgtm "Looks good to me", indicates that a PR is ready to be merged. release-note-none Denotes a PR that doesn't merit a release note. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants