# Offline Content Signing Proposal 1. The content is fully offline before the signature can be produced. 2. The signature may be done using notation plugins or other configuration as need for local keys or using a remote signing service. Here we use an example dockerfile below to build an offline archive that can be signed before pushing to the registry. ```dockerfile FROM alpine:latest RUN apk update && \ apk add --update curl && \ rm -rf /var/cache/apk/* ENTRYPOINT ["/usr/bin/curl"] ``` ## Proposal The proposal is to recommend using `buildx` to create the offline archive and use the contents from that to generate the signature. :::warning Proposal uses buildx which can be replaced with any builder that is able to produce a local OCI archive. ::: ### Setup buildx and build the image offline This should generate a metadata file which as the image manifest descriptor ```bash $ docker buildx create --use --driver=docker-container $ docker buildx build --metadata-file metadata.json \ --output=type=docker,dest=offline_alpine.tar \ -f Dockerfile . ``` ### Sign using notation from stdin or file path. - Option 1: Have notation use the archive. ```bash # generate the signature from the OCI layout. $ notation sign offline_alpine.tar Content manifest digest: sha256:aabbccddee Signature manifest digest: sha256:aabbccddee # View signatures locally $notation ls ``` - Option 2: Support descriptor signing in notation if the full archive is not available and produce a file for consumption. ```bash # extract the descriptor and sign cat metadata.json | jq '."containerimage.descriptor"' | \ notation sign --output image.signature --descriptor -- ``` ### Push the signature and image Use the image digest to push the signature. ```bash ## Use the digest from the previous step. # and see if we can get the signature from the notation cache notation attach \ myregistry.io/wabbit-networks/net-monitor \ -d $SIGNATURE_MANIFEST_DIGEST # Push the image to the registry # This can be any client that can push an OCI layout. oras push -t myregistry.io/wabbit-networks/net-monitor:v1 --archive offline_netmonitor.tar ``` :::info See below for more details about the files produced by buildx ::: --- #### Details Docker buildx produces the following metadata. ```json ➜ cat metadata.json | jq { "containerimage.buildinfo": { "frontend": "dockerfile.v0", "attrs": { "filename": "Dockerfile" }, "sources": [ { "type": "docker-image", "ref": "docker.io/library/alpine:latest", "pin": "sha256:bc41182d7ef5ffc53a40b044e725193bc10142a1243f395ee852a8d9730fc2ad" } ] }, "containerimage.config.digest": "sha256:29088db788c0c622191aa050f719d11936ece2fc3bf8bae6e3a048f4efb51c26", "containerimage.descriptor": { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "digest": "sha256:bc324a405167653cbd13ee15f46d50e862131af12e5ed97bf5495fc46dec56e4", "size": 739, "annotations": { "org.opencontainers.image.created": "2022-10-14T20:37:40Z" } }, "containerimage.digest": "sha256:bc324a405167653cbd13ee15f46d50e862131af12e5ed97bf5495fc46dec56e4" } ``` The manifest can be viewed in the tar file that has the oci layout ```bash ➜ tar -t -f offline_alpine.tar blobs/ blobs/sha256/ blobs/sha256/213ec9aee27d8be045c6a92b7eac22c9a64b44558193775a1a7f626352392b49 blobs/sha256/29088db788c0c622191aa050f719d11936ece2fc3bf8bae6e3a048f4efb51c26 blobs/sha256/400d6aa32c694f8ce9342269ed26d085505b1a02bf9e976378e7bec2ccdb5898 blobs/sha256/bc324a405167653cbd13ee15f46d50e862131af12e5ed97bf5495fc46dec56e4 index.json manifest.json oci-layout ``` You can see the manifest here - ```json ➜ tar -axf offline_alpine.tar index.json -O | jq { "schemaVersion": 2, "manifests": [ { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "digest": "sha256:bc324a405167653cbd13ee15f46d50e862131af12e5ed97bf5495fc46dec56e4", "size": 739, "annotations": { "org.opencontainers.image.created": "2022-10-14T20:37:40Z" } } ] } ``` - Notation only needs the descriptor for signing and maybe we can pass in more info into notation. ## Cleanup ```bash docker buildx rm docker-container ```