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

crictl v1.28.0 reporting incorrect image digest #1366

Open
bmelbourne opened this issue Feb 26, 2024 · 15 comments
Open

crictl v1.28.0 reporting incorrect image digest #1366

bmelbourne opened this issue Feb 26, 2024 · 15 comments
Labels
kind/bug Categorizes issue or PR as related to a bug. sig/node Categorizes an issue or PR as relevant to SIG Node.

Comments

@bmelbourne
Copy link

What happened:

When attempting to use a vulnerability scanner, such as kubevuln as part of the Kubescape security platform, the kube-apiserver v1.28.4 pod is not reporting the correct image digest and hence, the image cannot be pulled from registry.k8s.io, scanned and verified.

crictl v1.28.0

$ sudo crictl --version
crictl version v1.28.0

$ sudo crictl images --no-trunc | grep kube-apiserver
registry.k8s.io/kube-apiserver                                   v1.28.4              sha256:04b4c447bb9d4840af3bf7e836397379d65df87c86e55dcd27f31a8d11df2419   31.6MB

$ sudo crictl pull registry.k8s.io/kube-apiserver@sha256:04b4c447bb9d4840af3bf7e836397379d65df87c86e55dcd27f31a8d11df2419
E0226 11:21:38.111187   67843 remote_image.go:180] "PullImage from image service failed" err="rpc error: code = NotFound desc = failed to pull and unpack image \"registry.k8s.io/kube-apiserver@sha256:04b4c447bb9d4840af3bf7e836397379d65df87c86e55dcd27f31a8d11df2419\": failed to unpack image on snapshotter overlayfs: unexpected media type binary/octet-stream for sha256:04b4c447bb9d4840af3bf7e836397379d65df87c86e55dcd27f31a8d11df2419: not found" image="registry.k8s.io/kube-apiserver@sha256:04b4c447bb9d4840af3bf7e836397379d65df87c86e55dcd27f31a8d11df2419"
FATA[0000] pulling image: rpc error: code = NotFound desc = failed to pull and unpack image "registry.k8s.io/kube-apiserver@sha256:04b4c447bb9d4840af3bf7e836397379d65df87c86e55dcd27f31a8d11df2419": failed to unpack image on snapshotter overlayfs: unexpected media type binary/octet-stream for sha256:04b4c447bb9d4840af3bf7e836397379d65df87c86e55dcd27f31a8d11df2419: not found

nerdctl v1.7.1

$ sudo nerdctl --version
nerdctl version 1.7.1

$ sudo nerdctl images --namespace k8s.io --no-trunc | grep kube-apiserver
registry.k8s.io/kube-apiserver                                    v1.28.4               sha256:5b28a364467cf7e134343bb3ee2c6d40682b473a743a72142c7bbe25767d36eb    13 days ago    linux/arm64       118.0 MiB    30.1 MiB

$ sudo nerdctl pull registry.k8s.io/kube-apiserver@sha256:5b28a364467cf7e134343bb3ee2c6d40682b473a743a72142c7bbe25767d36eb
registry.k8s.io/kube-apiserver@sha256:5b28a364467cf7e134343bb3ee2c6d40682b473a743a72142c7bbe25767d36eb: resolved       |++++++++++++++++++++++++++++++++++++++|
index-sha256:5b28a364467cf7e134343bb3ee2c6d40682b473a743a72142c7bbe25767d36eb:                          done           |++++++++++++++++++++++++++++++++++++++|
manifest-sha256:a4c3e6bec39f5dcb221a2f08266513ab19b7d977ccc76a0bcaf04d4935ac0fb2:                       done           |++++++++++++++++++++++++++++++++++++++|
config-sha256:04b4c447bb9d4840af3bf7e836397379d65df87c86e55dcd27f31a8d11df2419:                         done           |++++++++++++++++++++++++++++++++++++++|
elapsed: 0.2 s                                                                                          total:   0.0 B (0.0 B/s)

kube-apiserver v1.28.4

$ kubectl describe pod --namespace kube-system kube-apiserver-ip-10-50-0-228.eu-west-2.compute.internal
Name:                 kube-apiserver-ip-10-50-0-228.eu-west-2.compute.internal
Namespace:            kube-system
...
Containers:
  kube-apiserver:
    Container ID:  containerd://6ad055fd25b0301bdf5497620e796b6083d9542e488ae72baf465f3c5693df1a
    Image:         registry.k8s.io/kube-apiserver:v1.28.4
    Image ID:      sha256:04b4c447bb9d4840af3bf7e836397379d65df87c86e55dcd27f31a8d11df2419
...index-sha256

What you expected to happen:

Closer examination shows that crictl is incorrectly setting the image ID in the container runtime using config-sha256 and not index-sha256 which matches the image digest stored in the remote kubernetes registry.k8s.io image registry, and hence, security scanners such as kubevuln would be able to use the correct digest and pull the image successfully.

How to reproduce it (as minimally and precisely as possible):

  1. Install kubeadm and pull the kubernetes v1.28.4 system images
$ sudo kubeadm config images pull --kubernetes-version=v1.28.4
[config/images] Pulled registry.k8s.io/kube-apiserver:v1.28.4
[config/images] Pulled registry.k8s.io/kube-controller-manager:v1.28.4
[config/images] Pulled registry.k8s.io/kube-scheduler:v1.28.4
[config/images] Pulled registry.k8s.io/kube-proxy:v1.28.4
[config/images] Pulled registry.k8s.io/pause:3.9
[config/images] Pulled registry.k8s.io/etcd:3.5.9-0
[config/images] Pulled registry.k8s.io/coredns/coredns:v1.10.1
  1. Repeat the steps outlined in the What happened section to review the kube-apiserver image digest

Anything else we need to know?:

Environment:

  • Container runtime or hardware configuration:
$ containerd --version
containerd github.com/containerd/containerd v1.7.11 64b8a811b07ba6288238eefc14d898ee0b5b99ba
  • OS (e.g: cat /etc/os-release):
$ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.3 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.3 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
  • Kernel (e.g. uname -a):
$ uname -a
Linux ip-10-50-0-228.eu-west-2.compute.internal 6.5.0-1014-aws #14~22.04.1-Ubuntu SMP Thu Feb 15 19:20:45 UTC 2024 aarch64 aarch64 aarch64 GNU/Linux`
@bmelbourne bmelbourne added kind/bug Categorizes issue or PR as related to a bug. sig/node Categorizes an issue or PR as relevant to SIG Node. labels Feb 26, 2024
@bmelbourne
Copy link
Author

Here is the output from ctr which also reports the correct image digest...

$ sudo ctr --namespace k8s.io images list | grep kube-apiserver
registry.k8s.io/kube-apiserver:v1.28.4                                           application/vnd.docker.distribution.manifest.list.v2+json sha256:5b28a364467cf7e134343bb3ee2c6d40682b473a743a72142c7bbe25767d36eb 30.1 MiB  linux/amd64,linux/arm64,linux/ppc64le,linux/s390x                                        io.cri-containerd.image=managed

@kannon92
Copy link
Contributor

@saschagrunert @haircommander is this related to the image id work?

@saschagrunert
Copy link
Member

saschagrunert commented Feb 28, 2024

@kannon92 @bmelbourne this is likely an issue with containerd, since you can reproduce it only with nerdctl and crictl.

You probably want to move this issue to the containerd repo.

/cc @mikebrow

@bmelbourne
Copy link
Author

bmelbourne commented Feb 28, 2024

@saschagrunert
In the description you'll see that the issue is specific to crictl only, both nerdctl and ctr report the correct pullable image digest for registry.k8s.io/kube-apiserver:v1.28.4.

/cc @mikebrow

@saschagrunert
Copy link
Member

@bmelbourne but the underlying runtime is containerd with a CRI middle layer, right? Means that containerd or the CRI shim needs to take care of the result, not crictl.

@bmelbourne
Copy link
Author

@saschagrunert not sure I agree, everything provided in the description has been generated from the same containerd runtime running on the same AWS cluster node running Ubuntu 22.04, and both nerdctl and ctr are reporting the correct pullable image digest.

If you look closely at the following output of the nerdctl pull, it appears crictl is using the config-sha256 hash and not the index-sha256 hash which would provide the correct image digest for any CRI tool to pull from registry.k8s.io.

registry.k8s.io/kube-apiserver@sha256:5b28a364467cf7e134343bb3ee2c6d40682b473a743a72142c7bbe25767d36eb: resolved       |++++++++++++++++++++++++++++++++++++++|
index-sha256:5b28a364467cf7e134343bb3ee2c6d40682b473a743a72142c7bbe25767d36eb:                          done           |++++++++++++++++++++++++++++++++++++++|
manifest-sha256:a4c3e6bec39f5dcb221a2f08266513ab19b7d977ccc76a0bcaf04d4935ac0fb2:                       done           |++++++++++++++++++++++++++++++++++++++|
config-sha256:04b4c447bb9d4840af3bf7e836397379d65df87c86e55dcd27f31a8d11df2419:                         done           |++++++++++++++++++++++++++++++++++++++|

@kannon92 @mikebrow what are your thoughts?

@saschagrunert
Copy link
Member

We get the images from the ListImages RPC and then normalize the digests by just using the first one:

repoDigestPair := strings.Split(repoDigests[0], "@")
if len(repoDigestPair) != 2 {
return "errorName", "errorRepoDigest"
}
return repoDigestPair[0], repoDigestPair[1]

Maybe we should take multiple digests into account, but what's the value of repoDigests[0] is in the hands of containerd.

@bmelbourne
Copy link
Author

bmelbourne commented Feb 28, 2024

Thanks for the specific code snippet, I'll compare this with how nerdctl and ctr are retrieving the image digest, and then raise the issue with the containerd project for their feedback.

Maybe something in recent containerd releases, and/or the OCI image spec means repoDigests[0] is being assigned the config-sha256 hash.

@mikebrow
Copy link
Contributor

Hello. In your example for crictl images you are looking at the image ID not the image ref.... At the moment (the last 6y), yes the image id we are showing on image pull / list etc. for use by the cri apis, for example to say remove the cri image.., is the config digest.. But that is just an id to reference our internal cri meta for the actual cri image. confusing if you think it's the digest of the image/index..

What you want, I believe, is repo digest:

(base) root@ubnt:~# crictl images --digests
IMAGE                             TAG                 DIGEST              IMAGE ID            SIZE
docker.io/library/busybox         1.35.0              02289a9972c50       0c00acac9c279       2.22MB
docker.io/library/nginx           latest              ea97e6aace270       247f7abff9f70       70.5MB
registry.k8s.io/coredns/coredns   v1.11.1             1eeb4c7316bac       cbb01a7bd410d       18.2MB
registry.k8s.io/pause             3.6                 3d380ca886454       6270bb605e12e       302kB
registry.k8s.io/pause             3.9                 7031c1b283388       e6f1816883972       322kB
(base) root@ubnt:~# crictl images --digests -v
ID: sha256:0c00acac9c2794adfa8bb7b13ef38504300b505a043bf68dff7a00068dcc732b
RepoTags: docker.io/library/busybox:1.35.0
RepoDigests: docker.io/library/busybox@sha256:02289a9972c5024cd2f083221f6903786e7f4cb4a9a9696f665d20dd6892e5d6
Size: 2223917

FYI cool tool that Derek put together:

ctr -n k8s.io images i docker.io/library/busybox:1.35.0 --content

@afbjorklund
Copy link
Contributor

afbjorklund commented Feb 29, 2024

I get the same results with dockerd, so I don't think that it is related to containerd.

It has another intesting quirk, in that filtering the images removes the digests...

$ docker images --digests busybox:latest
REPOSITORY   TAG       DIGEST    IMAGE ID       CREATED       SIZE
busybox      latest    <none>    3f57d9401f8d   6 weeks ago   4.26MB
$ docker images --digests | grep busybox | grep latest
busybox                                               latest           sha256:6d9ac9237a84afe1516540f40a0fafdc86859b2141954b4d643af7066d598b74   3f57d9401f8d   6 weeks ago     4.26MB

This behaviour also spreads to cri-dockerd, so filtered images end up with <none>

$ sudo crictl images --digests busybox:latest
busybox             latest              <none>              3f57d9401f8d4       4.26MB
$ sudo crictl images --digests | grep busybox | grep latest
busybox                                               latest              6d9ac9237a84a       3f57d9401f8d4       4.26MB

But otherwise, it seems to be about the Id versus the RepoDigest, as mentioned.

        "Id": "sha256:3f57d9401f8d42f986df300f0c69192fc41da28ccc8d797829467780db3dd741",
        "RepoTags": [
            "busybox:latest"
        ],
        "RepoDigests": [
            "busybox@sha256:6d9ac9237a84afe1516540f40a0fafdc86859b2141954b4d643af7066d598b74"
        ],

@afbjorklund
Copy link
Contributor

Images that are built locally only have an Id, they won't get a digest until they are pushed to a repo.

        "RepoTags": [
            "myimage:latest"
        ],
        "RepoDigests": [],

@bmelbourne
Copy link
Author

bmelbourne commented Mar 1, 2024

I've created a clean standalone AWS node with no pre-existing running Kubernetes cluster, and I believe the issue relates to how the ctr images pull command is not setting the image digest correctly.

Based on the following output, I'd appreciate an expert review to confirm my assumption before I close this ticket, and raise the issue with the containerd project?

$ sudo kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"28", GitVersion:"v1.28.7", GitCommit:"c8dcb00be9961ec36d141d2e4103f85f92bcf291", GitTreeState:"clean", BuildDate:"2024-02-14T10:39:01Z", GoVersion:"go1.21.7", Compiler:"gc", Platform:"linux/arm64"}

$ sudo containerd --version
containerd github.com/containerd/containerd v1.7.13 7c3aca7a610df76212171d200ca3811ff6096eb8

$ sudo ctr --version
ctr github.com/containerd/containerd v1.7.13

$ sudo crictl --version
crictl version v1.28.0

$ sudo kubeadm config images pull --kubernetes-version=v1.28.4
[config/images] Pulled registry.k8s.io/kube-apiserver:v1.28.4
[config/images] Pulled registry.k8s.io/kube-controller-manager:v1.28.4
[config/images] Pulled registry.k8s.io/kube-scheduler:v1.28.4
[config/images] Pulled registry.k8s.io/kube-proxy:v1.28.4
[config/images] Pulled registry.k8s.io/pause:3.9
[config/images] Pulled registry.k8s.io/etcd:3.5.10-0
[config/images] Pulled registry.k8s.io/coredns/coredns:v1.10.1

$ sudo crictl images --digests | grep kube-apiserver
registry.k8s.io/kube-apiserver            v1.28.4             5b28a364467cf       04b4c447bb9d4       31.6MB

$ sudo ctr -n k8s.io images list | grep kube-apiserver
registry.k8s.io/kube-apiserver:v1.28.4                                                                          application/vnd.docker.distribution.manifest.list.v2+json sha256:5b28a364467cf7e134343bb3ee2c6d40682b473a743a72142c7bbe25767d36eb 30.1 MiB  linux/amd64,linux/arm64,linux/ppc64le,linux/s390x                             io.cri-containerd.image=managed
registry.k8s.io/kube-apiserver@sha256:5b28a364467cf7e134343bb3ee2c6d40682b473a743a72142c7bbe25767d36eb          application/vnd.docker.distribution.manifest.list.v2+json sha256:5b28a364467cf7e134343bb3ee2c6d40682b473a743a72142c7bbe25767d36eb 30.1 MiB  linux/amd64,linux/arm64,linux/ppc64le,linux/s390x                             io.cri-containerd.image=managed

$ sudo crictl rmi --prune
Deleted: registry.k8s.io/kube-apiserver:v1.28.4
Deleted: registry.k8s.io/kube-controller-manager:v1.28.4
Deleted: registry.k8s.io/kube-scheduler:v1.28.4
Deleted: registry.k8s.io/kube-proxy:v1.28.4
Deleted: registry.k8s.io/pause:3.9
Deleted: registry.k8s.io/etcd:3.5.10-0
Deleted: registry.k8s.io/coredns/coredns:v1.10.1

$ sudo ctr -n k8s.io images pull --hosts-dir /etc/containerd/certs.d registry.k8s.io/kube-apiserver:v1.28.4
registry.k8s.io/kube-apiserver:v1.28.4:                                           resolved       |++++++++++++++++++++++++++++++++++++++|
index-sha256:5b28a364467cf7e134343bb3ee2c6d40682b473a743a72142c7bbe25767d36eb:    done           |++++++++++++++++++++++++++++++++++++++|
...
elapsed: 1.1 s                                                                    total:  30.1 M (27.4 MiB/s)
unpacking linux/arm64/v8 sha256:5b28a364467cf7e134343bb3ee2c6d40682b473a743a72142c7bbe25767d36eb...
done: 867.437748ms

$ sudo crictl images --digests
IMAGE                            TAG                 DIGEST              IMAGE ID            SIZE
registry.k8s.io/kube-apiserver   v1.28.4             <none>              04b4c447bb9d4       31.6MB

$ sudo ctr -n k8s.io images list
REF                                                                     TYPE                                                      DIGEST                                                                  SIZE     PLATFORMS
                     LABELS
registry.k8s.io/kube-apiserver:v1.28.4                                  application/vnd.docker.distribution.manifest.list.v2+json sha256:5b28a364467cf7e134343bb3ee2c6d40682b473a743a72142c7bbe25767d36eb 30.1 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed
sha256:04b4c447bb9d4840af3bf7e836397379d65df87c86e55dcd27f31a8d11df2419 application/vnd.docker.distribution.manifest.list.v2+json sha256:5b28a364467cf7e134343bb3ee2c6d40682b473a743a72142c7bbe25767d36eb 30.1 MiB linux/amd64,linux/arm64,linux/ppc64le,linux/s390x io.cri-containerd.image=managed

You'll notice from the above output, ctr lists the correct image info, tag and digest e.g. registry.k8s.io/kube-apiserver@sha256:5b28a364467cf7e134343bb3ee2c6d40682b473a743a72142c7bbe25767d36eb when using kubeadm config images pull to pull the registry.k8s.io images, but when using ctr images pull, the image digest is not fully formed and incorrectly shows sha256:04b4c447bb9d4840af3bf7e836397379d65df87c86e55dcd27f31a8d11df2419 for the image digest.

@afbjorklund
Copy link
Contributor

You say image digest, but reference the image id?

@bmelbourne
Copy link
Author

Yes, I didn't quite explain it properly, the ctr images pull command is not populating the Image ID correctly. The image path is missing and the image digest is incorrect.

@afbjorklund
Copy link
Contributor

Okay, that behaviour I can reproduce. Using ctr (or nerdctl) does not create the digests entry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Categorizes issue or PR as related to a bug. sig/node Categorizes an issue or PR as relevant to SIG Node.
Projects
None yet
Development

No branches or pull requests

5 participants