-
Notifications
You must be signed in to change notification settings - Fork 379
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
isManifestUnknownError fails against Harbor registries, breaking sigstore signature upload #2203
Comments
Thanks for your report. As you see, the code is trying to copy signatures. This is supposed to work. AFAICS the issue here is interoperability with the specific destination registry implementation; a signed push with a sigstore signature to that registry would fail just the same. First, please make sure you are using the recently-released Skopeo 1.14.0; the behavior in this area has changed, quite possibly fixing this. If that’s not the case, we’ll need to fix that in c/image; for starters, please provide a full log from |
Hello, To give you some more information about the environment. Both source and destination are harbor registries - please see goharbor.io if you need more information about the product. The "test:0.1" image is a very simple image only containing an alpine image with a simple echo hello line as cmd. That image has been signed with cosign and a local self created key. The image has been uploaded to registry 1 into the project "images". Please see the following sysouts. First one copying the image into a local dir into the running container that provides skopeo version 1.14.0: ---snip--- [root@6bbacdc9b6e4 ~]# skopeo copy docker://192.168.a.b/images/test:0.1 dir:test_0-1 [root@6bbacdc9b6e4 ~]# skopeo --debug copy dir:test_0-1 docker://192.168.y.z/images/test:0.1 ---snap--- If I understand the last line correctly, instead of "signature-1" a file named sha256-3a1332abd837b013a0378d662f403387f64a5bdc21c174031705d9de07d1a0db.sig will be expected - is this correct? Second one showing sysout copying the image directly between harbor 1 and harbor 2: ---snip--- [root@6bbacdc9b6e4 ~]# skopeo --debug copy docker://192.168.a.b/images/test:0.1 docker://192.168.y.z/images/test:0.1 ---snap--- Second attempt showing the same result. Added the following lines to /etc/containers/registries.d/default.yaml: Hope that helps. Please let me know if any further information is needed. |
Thanks!
OK, the registry (ref. https://github.com/goharbor/harbor/blob/7cef4217b03db1cb61d9fabded22540fafbff4b2/src/controller/artifact/controller.go#L298) apparently uses a non-standard
No, that name refers to a tag on the destination registry (and a component of the URLs quoted above). That works as expected. Either way, we’ll want to capture the full HTTP response of the above-quoted HTTP request (with the relevant authentication headers). Is that easy to do for you in the current environment? If not, we’ll need a source code patch to capture that in Skopeo. |
… looking more closely (and compare goharbor/harbor#19179 , not the same request but a sample of the error message):
our |
Hello again, If I understand you correctly, the situation is that a not expected response will be returned to prevent the signature to be delivered to harbor. Is this something that can be shipped around inside skopeo or must this be changed on harbor side? As the image copy works between two harbor registries directly, also if the source image has a signature, the functionality is available in general. |
Hi @mtrmac, I use the Harbor server ( Hope this information helps and feel free to ask me if you need me to capture additional debug information, thanks. By refer to goharbor/harbor#19179, if I understand correctly, it seems like this will be fixed in harbor |
@STARRY-S Thanks; that’s the request body, but not full request headers. Could you perhaps apply https://github.com/containers/image/pull/201/files (with (I don’t expect the response to contain credentials or secrets, but please double-check.) |
@mtrmac Hi, here's the log with captured response output:
HTTP response body: "{\"errors\":[{\"code\":\"NOT_FOUND\",\"message\":\"artifact test/alpine:sha256-443205b0cfcc78444321d56a2fe273f06e27b2c72b5058f8d7e975997d45b015.sig not found\"}]}\n" |
... per data in containers#2203 . Signed-off-by: Miloslav Trmač <mitr@redhat.com>
... per data in containers#2203 . Signed-off-by: Miloslav Trmač <mitr@redhat.com>
... per data in containers#2203 . Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Using PR #2413, replacing the Test ResultCommand: skopeo copy \
docker://docker.io/library/alpine:3 \
docker://harbor.example.local/library/alpine:3 \
--src-tls-verify=false --dest-tls-verify=false \
--sign-by-sigstore-private-key=sigstore.private \
--sign-passphrase-file=password.txt \
--multi-arch=all \
--preserve-digests Log outputs:
ResultThe error message |
... per data in containers#2203 . Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Thanks for the testing! #2413 was merged. |
Hello @mtrmac, Hello @STARRY-S , unfortunatelly, I cannot agree that the problem is solved. Let me describe the setup: Test case:
Question: is the skopeo image v.1.15.0 to old and does not contain the changes described above, or is the working outcome the result of the different steps, replicating an image from docker hub to an own harbor instance and just sign that one after replication. This is another approach as mine. skopeo copy --debug docker://192.168.210.91/images/alpine:3.18.4 docker://192.168.210.93/images/alpine:3.18.4 DEBU[0000] Using registries.d directory /etc/containers/registries.d DEBU[0000] Loading registries configuration "/root/.config/containers/registries.conf" DEBU[0000] Found credentials for 192.168.210.93/images/alpine in credential helper containers-auth.json in file /tmp/auth.json DEBU[0000] Lookaside configuration: using "docker" namespace 192.168.210.93 DEBU[0000] No signature storage configuration found for 192.168.210.93/images/alpine:3.18.4, using built-in default file:///var/lib/containers/sigstore DEBU[0000] Looking for TLS certificates and private keys in /etc/docker/certs.d/192.168.210.93 DEBU[0000] Sigstore attachments: using "docker" namespace 192.168.210.93 DEBU[0000] Using registries.d directory /etc/containers/registries.d DEBU[0000] Trying to access "192.168.210.91/images/alpine:3.18.4" DEBU[0000] Found credentials for 192.168.210.91/images/alpine in credential helper containers-auth.json in file /tmp/auth.json DEBU[0000] Lookaside configuration: using "docker" namespace 192.168.210.91 DEBU[0000] No signature storage configuration found for 192.168.210.91/images/alpine:3.18.4, using built-in default file:///var/lib/containers/sigstore DEBU[0000] Looking for TLS certificates and private keys in /etc/docker/certs.d/192.168.210.91 DEBU[0000] Sigstore attachments: using "docker" namespace 192.168.210.91 DEBU[0000] GET https://192.168.210.91/v2/ DEBU[0000] Ping https://192.168.210.91/v2/ err Get "https://192.168.210.91/v2/": dial tcp 192.168.210.91:443: connect: no route to host (&url.Error{Op:"Get", URL:"https://192.168.210.91/v2/", Err:(*net.OpError)(0xc000516190)}) DEBU[0000] GET http://192.168.210.91/v2/ DEBU[0000] Ping http://192.168.210.91/v2/ status 401 DEBU[0000] GET http://nuc02/service/token?account=sascha&scope=repository%3Aimages%2Falpine%3Apull&service=harbor-registry DEBU[0000] GET http://192.168.210.91/v2/images/alpine/manifests/3.18.4 DEBU[0000] Content-Type from manifest GET is "application/vnd.docker.distribution.manifest.v2+json" DEBU[0000] Using SQLite blob info cache at /var/lib/containers/cache/blob-info-cache-v1.sqlite DEBU[0000] IsRunningImageAllowed for image docker:192.168.210.91/images/alpine:3.18.4 DEBU[0000] Using default policy section DEBU[0000] Requirement 0: allowed DEBU[0000] Overall: allowed Getting image source signatures DEBU[0000] Reading /var/lib/containers/sigstore/images/alpine@sha256=48d9183eb12a05c99bcc0bf44a003607b8e941e1d4f41f9ad12bdcc4b5672f86/signature-1 DEBU[0000] Looking for sigstore attachments in 192.168.210.91/images/alpine:sha256-48d9183eb12a05c99bcc0bf44a003607b8e941e1d4f41f9ad12bdcc4b5672f86.sig DEBU[0000] GET http://192.168.210.91/v2/images/alpine/manifests/sha256-48d9183eb12a05c99bcc0bf44a003607b8e941e1d4f41f9ad12bdcc4b5672f86.sig DEBU[0000] Content-Type from manifest GET is "application/vnd.oci.image.manifest.v1+json" DEBU[0000] Found a sigstore attachment manifest with 1 layers DEBU[0000] Fetching sigstore attachment 1/1: sha256:73915660087de524a0f777380d9d6f6b7b7df31c9c63f77d5375bdb5d3c1ad54 DEBU[0000] Downloading /v2/images/alpine/blobs/sha256:73915660087de524a0f777380d9d6f6b7b7df31c9c63f77d5375bdb5d3c1ad54 DEBU[0000] GET http://192.168.210.91/v2/images/alpine/blobs/sha256:73915660087de524a0f777380d9d6f6b7b7df31c9c63f77d5375bdb5d3c1ad54 Checking if image destination supports signatures DEBU[0000] GET https://192.168.210.93/v2/ DEBU[0000] Ping https://192.168.210.93/v2/ err Get "https://192.168.210.93/v2/": dial tcp 192.168.210.93:443: connect: no route to host (&url.Error{Op:"Get", URL:"https://192.168.210.93/v2/", Err:(*net.OpError)(0xc0005163c0)}) DEBU[0000] GET http://192.168.210.93/v2/ DEBU[0000] Ping http://192.168.210.93/v2/ status 401 DEBU[0000] We can't modify the manifest, hoping for the best... DEBU[0000] Checking if we can reuse blob sha256:96526aa774ef0126ad0fe9e9a95764c5fc37f409ab9e97021e7b4775d82bf6fa: general substitution = false, compression for MIME type "application/vnd.docker.image.rootfs.diff.tar.gzip" = true DEBU[0000] Checking /v2/images/alpine/blobs/sha256:96526aa774ef0126ad0fe9e9a95764c5fc37f409ab9e97021e7b4775d82bf6fa DEBU[0000] GET http://nuc07/service/token?account=sascha&scope=repository%3Aimages%2Falpine%3Apull%2Cpush&service=harbor-registry DEBU[0000] HEAD http://192.168.210.93/v2/images/alpine/blobs/sha256:96526aa774ef0126ad0fe9e9a95764c5fc37f409ab9e97021e7b4775d82bf6fa DEBU[0000] ... already exists DEBU[0000] Skipping blob sha256:96526aa774ef0126ad0fe9e9a95764c5fc37f409ab9e97021e7b4775d82bf6fa (already present): Copying blob 96526aa774ef skipped: already exists DEBU[0000] Downloading /v2/images/alpine/blobs/sha256:8ca4688f4f356596b5ae539337c9941abc78eda10021d35cbc52659c74d9b443 DEBU[0000] GET http://192.168.210.91/v2/images/alpine/blobs/sha256:8ca4688f4f356596b5ae539337c9941abc78eda10021d35cbc52659c74d9b443 DEBU[0000] No compression detected DEBU[0000] Compression change for blob sha256:8ca4688f4f356596b5ae539337c9941abc78eda10021d35cbc52659c74d9b443 ("application/vnd.docker.container.image.v1+json") not supported DEBU[0000] Using original blob without modification DEBU[0000] Checking /v2/images/alpine/blobs/sha256:8ca4688f4f356596b5ae539337c9941abc78eda10021d35cbc52659c74d9b443 DEBU[0000] HEAD http://192.168.210.93/v2/images/alpine/blobs/sha256:8ca4688f4f356596b5ae539337c9941abc78eda10021d35cbc52659c74d9b443 DEBU[0000] ... already exists Copying config 8ca4688f4f done | Writing manifest to image destination DEBU[0000] PUT http://192.168.210.93/v2/images/alpine/manifests/3.18.4 Storing signatures DEBU[0000] Looking for sigstore attachments in 192.168.210.93/images/alpine:sha256-48d9183eb12a05c99bcc0bf44a003607b8e941e1d4f41f9ad12bdcc4b5672f86.sig DEBU[0000] GET http://192.168.210.93/v2/images/alpine/manifests/sha256-48d9183eb12a05c99bcc0bf44a003607b8e941e1d4f41f9ad12bdcc4b5672f86.sig DEBU[0000] Content-Type from manifest GET is "application/json; charset=utf-8" DEBU[0000] Fetching sigstore attachment manifest failed: reading manifest sha256-48d9183eb12a05c99bcc0bf44a003607b8e941e1d4f41f9ad12bdcc4b5672f86.sig in 192.168.210.93/images/alpine: unknown: artifact images/alpine:sha256-48d9183eb12a05c99bcc0bf44a003607b8e941e1d4f41f9ad12bdcc4b5672f86.sig not found FATA[0000] writing signatures: reading manifest sha256-48d9183eb12a05c99bcc0bf44a003607b8e941e1d4f41f9ad12bdcc4b5672f86.sig in 192.168.210.93/images/alpine: unknown: artifact images/alpine:sha256-48d9183eb12a05c99bcc0bf44a003607b8e941e1d4f41f9ad12bdcc4b5672f86.sig not found [root@c86d2ed07d47 /]# skopeo --version skopeo version 1.15.0 If I copy within the container from one directory to another, the signature is available: skopeo copy --debug dir:alpine_3-18-4 dir:alpine_3.18.4 DEBU[0000] overwriting existing container image directory "/root/alpine_3.18.4" DEBU[0000] Using SQLite blob info cache at /var/lib/containers/cache/blob-info-cache-v1.sqlite DEBU[0000] IsRunningImageAllowed for image dir:/root/alpine_3-18-4 DEBU[0000] Using default policy section DEBU[0000] Requirement 0: allowed DEBU[0000] Overall: allowed Getting image source signatures Checking if image destination supports signatures DEBU[0000] We can't modify the manifest, hoping for the best... DEBU[0000] Checking if we can reuse blob sha256:96526aa774ef0126ad0fe9e9a95764c5fc37f409ab9e97021e7b4775d82bf6fa: general substitution = false, compression for MIME type "application/vnd.docker.image.rootfs.diff.tar.gzip" = true DEBU[0000] Detected compression format gzip DEBU[0000] Using original blob without modification Copying blob 96526aa774ef done | DEBU[0000] No compression detected DEBU[0000] Compression change for blob sha256:8ca4688f4f356596b5ae539337c9941abc78eda10021d35cbc52659c74d9b443 ("application/vnd.docker.container.image.v1+json") not supported DEBU[0000] Using original blob without modification Copying config 8ca4688f4f done | Writing manifest to image destination Storing signatures ll total 16 drwxr-xr-x. 2 root root 4096 May 30 23:57 alpine_3-18-4 drwxr-xr-x. 2 root root 4096 May 31 12:22 alpine_3.18.4 [root@c86d2ed07d47 ~]# ls alpin* | grep sig signature-1 signature-1 [root@c86d2ed07d47 ~]# diff alpine_3.18.4/signature-1 alpine_3-18-4/signature-1 [root@c86d2ed07d47 ~]# May I ask for another test or check? Best regards |
Yes; this was included in c/image v5.31.0, and that isn’t in a Skopeo release yet. Per https://github.com/containers/image_build/blob/main/README.md , those unreleased versions should have (unstable! testing-only!) builds at https://quay.io/repository/skopeo/upstream, but https://quay.io/repository/skopeo/upstream?tab=history shows the tag being deleted. @cevich is that just me forgetting about an announced change, or is that unexpected? |
Oh! That's wrong, there should always be a "latest" tag there. Checking podman and buildah, it's the same deal. Something is wrong. I'll look into it. |
Thanks @mtrmac and @cevich, skopeo --version skopeo version 1.16.0-dev Test result: skopeo copy docker://192.168.210.91/images/alpine:3.18.4 docker://192.168.210.93/images/alpine:3.18.4. The image will be replicated with the already existing signature to vm02 harbor instance. Inside the project, the image now shows an existing signature. Many thanks for your help. |
Skopeo is planned to be used to copy already signed images between two or more private registries.
In my situation, the images are already signed in a private source registry. This signature is also shown as existing within the source registry.
If this signed image is copied directly between the two registries - there is a graphical front end in the registry product for this - the image includes the signature appearing on the target registry.
However, this solution cannot be used due to other disadvantages. Thats the reason trying skopeo for a potential solution.
A $skopeo copy docker://192.168.x.y/images/test:0.1 dir:test_0.1 copies the image including the signature into the test_0.1 directory - into signature-1.
However, a copy directly between two registries does not work:
$skopeo copy docker://192.168.x.y/images/test:0.1 docker://192.168.y.z/images/test:0.1
Getting image source signatures
Checking if image destination supports signatures
Copying blob 96526aa774ef skipped: already exists
Copying blob 5b088f1e648c skipped: already exists
Copying config 33b8df73a9 done
Writing manifest to image destination
Storing signatures
FATA[0000] writing signatures: reading manifest sha256-blablabla.sig in 192.168.y.z/images/test: unknown: artifact images/test:sha256-blablabla.sig not found
Also, there is no positiv result trying to copy the content from inside the local directory. The same message is the result.
My question is: might it be that Skopeo cannot be used to copy images between two or more registries that are already signed in the source registry? There are no plans to re-sign the image with the private key in between again. This signature should be adopted 1:1 into the target registry - just as the registry product itself can do, although there are other reasons against using this solution.
May I ask for assistance or is this some kind of issue or enhancement?
The text was updated successfully, but these errors were encountered: