Cosign signatures lifecycle in Artifactory

devopsLeave a Comment on Cosign signatures lifecycle in Artifactory

Cosign signatures lifecycle in Artifactory

In this article, we will explore the process of signing Docker containers using Cosign and signatures lifecycle in Artifactory docker registry. Additionally, we’ll delve into a proposed solution for copying the signature to a target repository during artifact promotion or copying phases, addressing potential challenges in the process.

Details regarding signing and verifying docker containers won’t be covered in this blog post. This has been very well explained in other people blog posts[1], as well as in the official documentation[2][3]. It’s safe to say that it works since at least 2021.

Working with Artifactory

Before going on with signing we need to authenticate ourselves to the docker registry. I’m using Artifactory docker registry[4] as an example in this scenario.

cosign login -u {{ username }} -p '{{ password }}' x.artifactory.com

Cosign could return an error if you provide an URL with the schema:

Error: registries must be valid RFC 3986 URI authorities: https://x.artifactory.com
main.go:74: error during command execution: registries must be valid RFC 3986 URI authorities: https://x.artifactory.com

As a solution simply omit the schema (https:// in the above example).

When cosign has successfully logged in, build and push the image as usual. Afterwards, you should sign your docker image using cosign sign. If you did everything right to this point, executing cosign verify as a sanity check on the same machine will provide the following output:

$ cosign verify --key cosign.pub x.artifactory.com/fajfer/image:example
The following checks were performed on these signatures:
  - The cosign claims were validated
  - The signatures were verified against the specified public key
{"Critical":{"Identity":{"docker-reference":""},"Image":{"Docker-manifest-digest":"sha256:87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8"},"Type":"cosign container image signature"},"Optional":null}

You can repeat the command on a different machine to verify that the signature has been successfully uploaded. The output should remain the same and the signature should be visible in the webUI:

Cosign signature in Artifactory

So what’s the problem?

As per documentation:

Cosign documentation @ af555d5

Signatures are stored as separate objects in the OCI registry, with only a weak reference back to the object they “sign”. This means this relationship is opaque to the registry, and signatures will not be deleted or garbage-collected when the image is deleted. Similarly, they can easily be copied from one environment to another, but this is not automatic.


If your artifact lifecycle ends here and images from here are being deployed to production or are available to public then that’s it, you’re done. Otherwise, if you want to promote your images or copy them somewhere else then you’ll notice that while your artifacts are getting promoted to the target repository, their signatures are left intact in the source repository. Which means that if you build and sign artifacts in the repository x, then after promoting it to repository y cosign will give you this sad response:

$ cosign verify --key cosign.pub y.artifactory.com/fajfer/image:example
Error: no matching signatures:

main.go:52: error during command execution: no matching signatures:

What’s wrong, right? It just worked perfectly in the old repository.

The proposed solution

We need to copy the signature to the target repository. After the Promote Docker Image REST API request we need to do a Copy Item request to copy the signature. There’s an important detail here – cosign names the signature after SHA256 of manifest.json of our image. Luckily, we can easily access that information by executing File Info request. We can also calculate this ourselves but I assume you don’t have the image locally anymore during the promotion/copy phase.

Digest field under ‘Docker Info’ in the UI also displays the hash

To understand the solution better and get an idea of how your requests should look like, here’s an example in Ansible code that could be used to implement a solution in your CI system:

- name: Promote Docker Image
  # https://jfrog.com/help/r/jfrog-rest-apis/promote-docker-image
  uri:
    url: "{{ artifactory_url }}/api/docker/{{ source_repo }}/v2/promote"
    method: POST
    url_username: "{{ username }}"
    url_password: "{{ password }}"
    force_basic_auth: true
    body_format: json
    body:
      targetRepo: "{{ target_repo }}"
      dockerRepository: "{{ docker_repository }}"
      copy: true

- name: Get manifest.json (File Info)
  # https://jfrog.com/help/r/jfrog-rest-apis/file-info
  uri:
    url: "{{ artifactory_url }}/api/storage/{{ source_repo }}/\
      {{ file_path }}/{{ tag }}/manifest.json"
    method: GET
    url_username: "{{ username }}"
    url_password: "{{ password }}"
    force_basic_auth: true
  register: manifest

- name: Copy cosign signature (Copy Item)
  # https://jfrog.com/help/r/jfrog-rest-apis/copy-item
  uri:
    url: "{{ artifactory_url }}/api/copy/{{ source_repo }}/\
      {{ source_file_path }}/sha256-{{ manifest.json.checksums.sha256 }}.sig\
      ?to=/{{ target_repo }}/{{ target_file_path }}"
    method: POST
    url_username: "{{ username }}"
    url_password: "{{ password }}"
    force_basic_auth: true

This approach makes the best use of Artifactory’s API and doesn’t require the image and signature to be downloaded locally at all.

Closing thoughts

Cosign support of Artifactory is very well done and the Artifactory knows that it serves you signed images as it sends you a signature along with the container after executing docker pull. The API doesn’t reflect that though, but that’s hopefully going to change in the future. Container signing becomes more popular and more accessible thanks to tools like cosign, notary and kyverno to name a few so doing workarounds like this shouldn’t be required in the future.


[1] Jabar Asadi, “Digital Signature With Cosign” May 4, 2023. https://eng.d2iq.com/blog/digital-signature-with-cosign/ Accessed 22.07.2023

[2] Sigstore, “Signing Containers” https://docs.sigstore.dev/cosign/signing_with_containers/ GitHub: 18b11e2

[3] Sigstore, “Verifying” https://docs.sigstore.dev/cosign/verify GitHub: 4186c93

[4] JFrog Artifactory Documentation, “Docker Registry” https://jfrog.com/help/r/jfrog-artifactory-documentation/docker-registry Accessed: 23.07.2023

I live in Warsaw, Poland and I'm currently employed as a DevOps Engineer at Bank Pekao S.A. In the meantime I'm helping NGOs with cloud adoption and their IT departments. Social volunteer focused on local community. Passionate home chef.

Leave a Reply

Your email address will not be published. Required fields are marked *

Back To Top