Docker notary client for multi-platform image publishing succeeds but tag is not trusted

101 Views Asked by At

I have been following the steps in the action script here closely (https://github.com/sudo-bot/action-docker-sign/blob/main/action.yml) to trust and sign a multi-platform image. The only modification required was for the extraction of the SHA256 where I extract the last SHA256 returned by the manifest-push-command (the cut command in the action script does not seem to return a valid SHA256); maybe the manifest-push result has changed. I have also tried different SHA256 values returned by the push with the same result.

This is the script, using Docker 23.0.0 and the notary package installed with sudo apt-get notary on Ubuntu.

The script completes without error but there is no image tag signature in the end. What am I missing? How do you trust and sign multi-platform image tags?

Note that buildx does not help signing multi-platform images; it just pushes unsigned images as far as I know.

export DOCKER_CONTENT_TRUST=1

# build for platforms, authentication build args omitted; needs docker 23.0.0
docker build --platform=linux/amd64 --tag mydockerid/test-amd64:$(tag)$(tagSuffix) --file $(Folder)/Dockerfile .
docker build --platform=linux/arm64 --tag mydockerid/test-arm64:$(tag)$(tagSuffix) --file $(Folder)/Dockerfile .

export DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE='$(SignerKeyPassword)'
docker trust key load $(signerKey.secureFilePath)

export NOTARY_TARGETS_PASSPHRASE='$(TargetKeyPassword)'
export NOTARY_SNAPSHOT_PASSPHRASE='$(SnapshotKeyPassword)'

# Sign and push platform specific images - is it necessary to sign these?
docker trust sign mydockerid/test-amd64:$(tag)$(tagSuffix)
docker trust sign mydockerid/test-arm64:$(tag)$(tagSuffix)

# Create manifest list from platform manifests
docker manifest create mydockerid/test:$(tag)$(tagSuffix) mydockerid/test-amd64:$(tag)$(tagSuffix) mydockerid/test-arm64:$(tag)$(tagSuffix)

# orignal action command does not extract valid SHA
# SHA_256=$(docker manifest push mydockerid/test:$(tag)$(tagSuffix) --purge | cut -d ':' -f 2)

# Push manifest
MANIFEST=$(docker manifest push mydockerid/test:$(tag)$(tagSuffix) --purge)
# Extract last sha256 return by push command which is the only sha256 not corresponding to layers
echo "MANIFEST: ${MANIFEST}"
SHA_256=$(echo ${MANIFEST//*:})          
echo "SHA_256: $SHA_256"

MANIFEST_FROM_REG="$(docker manifest inspect "mydockerid/test:$(tag)$(tagSuffix)" -v)";
echo "MANIFEST_FROM_REG: $MANIFEST_FROM_REG"

# Determine byte size as per action script
BYTES_SIZE="$(printf "${MANIFEST_FROM_REG}" | jq -r '.[].Descriptor.size' | uniq)";
echo "BYTES_SIZE: $BYTES_SIZE"

REF="mydockerid/test"
TAG="$(tag)$(tagSuffix)"

AUTH_BASIC=$(SignerAuthBasic)
ROLE_CLI=""
# Check that keys are present
notary key list -d $(DOCKER_CONFIG)/trust/
# Encode user:pat as base 64
export NOTARY_AUTH="$(printf "${AUTH_BASIC}" | base64 -w0)";
TRUST_FOLDER="$(DOCKER_CONFIG)/trust/"
echo "TRUST_FOLDER: $TRUST_FOLDER"
# publish and sign
notary -d ${TRUST_FOLDER} -s "https://notary.docker.io" addhash "${REF}" "${TAG}" "${BYTES_SIZE}" --sha256 "${SHA_256}" ${ROLE_CLI} --publish --verbose
notary -s "https://notary.docker.io" list "${REF}";
unset NOTARY_AUTH;

The script completes without error.

The notary ... --publish ... command returns:

Addition of target "1.1.1234-beta" by sha256 hash to repository "***/test" staged for next publish.
Auto-publishing changes to ***/test
Successfully published changes for repository ***/test

The last notary ... list command lists the image tag as expected:

NAME             DIGEST            SIZE (BYTES)    ROLE
----             ------            ------------    ----
1.0.1234-beta    91e75e43bd....    637             targets

But when inspecting trust then there is no signature:

docker trust inspect --pretty mydockerid/test

No signatures for mydockerid/test
...
1

There are 1 best solutions below

0
J.R. On

The fix is relatively simple. The image reference in the notary command needed docker.io in front in my case, like so:

notary -d ${TRUST_FOLDER} -s "https://notary.docker.io" addhash "docker.io/${REF}" "${TAG}" "${BYTES_SIZE}" --sha256 "${SHA_256}" ${ROLE_CLI} --publish --verbose

This will have notary ask for the repository key, which needs to be provided, i.e.:

export NOTARY_TARGETS_PASSPHRASE='$(RepoKeyPassword)'

The other notary keys are not required.

After these two changes, the signatures appear in docker inspect trust as expected.