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

Build and sign container images on new tags #1017

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

almet
Copy link
Contributor

@almet almet commented Nov 28, 2024

This pull request introduces a new workflow to automate the release and signature (via sigstore) of container images. The workflow listens for new tags, builds a container image, signs it, and uploads it to the container registry.

Here is a list of the produced assets:

Verifying the validity of the attestation can be done with the following commands:

We should be able to also do it using sigstore-python and raw HTTP calls, but because the main goal here is to see how it works, I stopped there.

# First, login to the container registry.
# (We only need this because images are not publicly available yet)
# Enter "USERNAME" instead of your username
# and use your PAT as a password
regctl registry login ghcr.io

# Get the manifest from the latest tag
regctl manifest get --format raw-body ghcr.io/freedomofpress/dangerzone/dangerzone:latest > manifest.json

# The attestation for this manifest hash is available
# at the tag named "sha256-sha256(manifest.json)"
DIGEST="sha256-$(sha256sum manifest.json | awk '{ print $1 }')"
regctl artifact get ghcr.io/freedomofpress/dangerzone/dangerzone:${DIGEST} > bundle.json

# Finally verify that the attestation is the right one
cosign verify-blob-attestation --bundle bundle.json --new-bundle-format --certificate-oidc-issuer="https://token.actions.githubusercontent.com" --certificate-identity-regexp="^https://github.com/freedomofpress/dangerzone/.github/workflows/release-container-image.yml@refs/heads/test/image-publication-cosign" manifest.json

Related to #745

@almet almet force-pushed the test/image-publication-cosign branch from 87a65ce to 178364e Compare November 28, 2024 15:22
@almet
Copy link
Contributor Author

almet commented Nov 28, 2024

ℹ️ One of the things that isn't clear yet is why the attestations show up as sha256-$(sha256sum manifest.json) in the container registry.

It seems related to the Reference Types effort effort which might not be implemented by the GHCR.

@apyrgio apyrgio added this to the 0.9.0 milestone Dec 5, 2024
@almet
Copy link
Contributor Author

almet commented Dec 10, 2024

In order to get the attestation from the container registry, one need to do a few HTTP requests. We found these do be hard to put together, so here is a summary of the calls we had to do (testing on my personal user in order to have the container be public):

Step Endpoint Headers
1. Get authentication token https://ghcr.io/token None
2. Fetch manifest for tag https://ghcr.io/v2/almet/dangerzone/dangerzone/manifests/{tag} Accept: application/vnd.docker.distribution.manifest.v2+json
3. Get manifest list for attestation https://ghcr.io/v2/almet/dangerzone/dangerzone/manifests/sha256-{manifest_hash} Accept: application/vnd.oci.image.index.v1+json
4. Get Sigstore bundle manifest https://ghcr.io/v2/almet/dangerzone/dangerzone/manifests/{blob_manifest_digest} Accept: application/vnd.oci.image.manifest.v1+json
5. Retrieve attestation blob https://ghcr.io/v2/almet/dangerzone/dangerzone/blobs/{blob_hash} None

Variable definitions:

  • {tag}: Usually "latest" or a specific version
  • {manifest_hash}: SHA256 hash of the original manifest content
  • {blob_manifest_digest}: Digest from manifest list with artifactType = "application/vnd.dev.sigstore.bundle.v0.3+json"
  • {blob_hash}: Digest from layers where mediaType = "application/vnd.dev.sigstore.bundle.v0.3+json"

Authentication:

  • All requests (except token request) require header: Authorization: Bearer {token}
  • Token obtained from /token endpoint with:
    • service=ghcr.io
    • scope=repository:almet/dangerzone/dangerzone:pull

These calls have been put together in a small script I wrote to download the attestations from a container registry for a specific tag.

@almet
Copy link
Contributor Author

almet commented Dec 12, 2024

While trying to build our own attestations (without using the GHA), we've been puzzled by how the container registry was populated in different ways.

It turns out that attestations are different from plain signatures:

  1. The Cosign Signature spec explains how plain signatures are represented. This is what's being used via cosign sign. It's using annotations (not to be confused with attestations), attaching them to the container registry. The signed payload are represented by the "simple signing" format.
  2. The Cosign Bundle Specification explains how image attestations are to be represented as OCI artifacts, and attached to the container registry. This is what's being used via cosign attest

What's been complex to understand is that cosign, in their documentation, points us to use cosign sign in order to sign our container images. This will add plain signatures and is different from an attestation.

(the attest-build-provenance this PR has been using uses the Cosign Bundle Specification)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: PR Review
Development

Successfully merging this pull request may close these issues.

2 participants