diff --git a/README.md b/README.md
index aeffa1e386809b7705c7f8b60d00572e04a96131..1edfbdda6d0249f00bd5a7327a2a1ecd77055ca1 100644
--- a/README.md
+++ b/README.md
@@ -243,7 +243,9 @@ The signing process can be configured with the following variables:
| Input / Variable | Description | Default value |
| --------------------------------------------------------- | -------------------------------------------- | --------------------- |
| `cosign-strategy` / `DOCKER_COSIGN_STRATEGY` | Determines when images should be signed with [cosign](https://github.com/sigstore/cosign (`never`: disabled, `onrelease`: only on `$INTEG_REF`, `$PROD_REF` and `$RELEASE_REF` pipelines; `always`: any pipeline).
:warning: `cosign-enabled` / `DOCKER_COSIGN_ENABLED` takes precedence | `never` |
-| `cosign-opts` / `DOCKER_COSIGN_OPTS` | Options for cosign | `--tlog-upload=false` |
+| `cosign-opts` / `DOCKER_COSIGN_OPTS` | Options for [`cosign sign`](https://docs.sigstore.dev/cosign/signing/signing_with_containers/) command | `--tlog-upload=false --recursive` |
+| `cosign-attest-opts` / `DOCKER_COSIGN_ATTEST_OPTS` | Options for [`cosign attest`](https://docs.sigstore.dev/cosign/verifying/attestation/) command
+ | `--tlog-upload=false` |
| `cosign-dist-url` / `DOCKER_COSIGN_DIST_URL` | Url to the `linux-amd64` binary of Cosign to use (ex: `https://github.com/sigstore/cosign/releases/download/v2.5.0/cosign-linux-amd64`)
_When unset, the latest version will be used_ | _none_ |
| :lock: `cosign-private-key` / `DOCKER_COSIGN_PRIVATE_KEY` | Private key used for signing the Docker image and the attestation | _none_ |
| :lock: `cosign-password` / `COSIGN_PASSWORD` | Password of the private key | _none_ |
diff --git a/kicker.json b/kicker.json
index 0fac255dd4a2f7e1cee83697433581a048f94ba4..b8071b4d765394feba9462aaff9f2d83d39bff4d 100644
--- a/kicker.json
+++ b/kicker.json
@@ -231,7 +231,13 @@
},
{
"name": "DOCKER_COSIGN_OPTS",
- "description": "Options for cosign",
+ "description": "Options for [`cosign sign`](https://docs.sigstore.dev/cosign/signing/signing_with_containers/) command",
+ "default": "--tlog-upload=false --recursive",
+ "advanced": true
+ },
+ {
+ "name": "DOCKER_COSIGN_ATTEST_OPTS",
+ "description": "Options for [`cosign attest`](https://docs.sigstore.dev/cosign/verifying/attestation/) command",
"default": "--tlog-upload=false",
"advanced": true
},
diff --git a/templates/gitlab-ci-docker.yml b/templates/gitlab-ci-docker.yml
index 6213abbed43de5b3520ede93f3296ecd35fc3ac9..d2ca9a6359ac4d33a145957c777bcd8b33fbea91 100644
--- a/templates/gitlab-ci-docker.yml
+++ b/templates/gitlab-ci-docker.yml
@@ -180,7 +180,10 @@ spec:
- always
default: never
cosign-opts:
- description: Options for cosign
+ description: Options for [`cosign sign`](https://docs.sigstore.dev/cosign/signing/signing_with_containers/) command
+ default: --tlog-upload=false --recursive
+ cosign-attest-opts:
+ description: Options for [`cosign attest`](https://docs.sigstore.dev/cosign/verifying/attestation/) command
default: --tlog-upload=false
cosign-dist-url:
description: |-
@@ -292,6 +295,7 @@ variables:
COSIGN_YES: "true" # skip confirmation prompts for non-destructive operations
DOCKER_COSIGN_STRATEGY: $[[ inputs.cosign-strategy ]]
DOCKER_COSIGN_OPTS: $[[ inputs.cosign-opts ]]
+ DOCKER_COSIGN_ATTEST_OPTS: $[[ inputs.cosign-attest-opts ]]
DOCKER_COSIGN_DIST_URL: $[[ inputs.cosign-dist-url ]]
# default: one-click publish
@@ -1333,7 +1337,7 @@ docker-sbom:
log_info "Attaching attested SBOM to ${DOCKER_SNAPSHOT_IMAGE}..."
install_cosign
configure_cosign_private_key
- $docker_cosign attest --key ${docker_cosign_private_key} ${DOCKER_COSIGN_OPTS} --predicate reports/docker-sbom-${basename}.cyclonedx.json ${DOCKER_SNAPSHOT_IMAGE}
+ $docker_cosign attest --key ${docker_cosign_private_key} ${DOCKER_COSIGN_ATTEST_OPTS} --predicate reports/docker-sbom-${basename}.cyclonedx.json ${DOCKER_SNAPSHOT_IMAGE}
fi
artifacts:
name: "SBOM for docker from $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG"
@@ -1396,7 +1400,7 @@ docker-publish:
- BUILDTOOL_HOME=${BUILDTOOL_HOME:-$HOME}
# 1: push main image
- log_info "Copying ${DOCKER_SNAPSHOT_IMAGE} to ${DOCKER_RELEASE_IMAGE}..."
- - skopeo copy ${TRACE+--debug} --all --src-authfile "$BUILDTOOL_HOME/skopeo/.docker/src-config.json" --dest-authfile "$BUILDTOOL_HOME/skopeo/.docker/dest-config.json" ${DOCKER_PUBLISH_ARGS} "docker://$DOCKER_SNAPSHOT_IMAGE" "docker://$DOCKER_RELEASE_IMAGE"
+ - skopeo copy ${TRACE+--debug} --all --src-authfile "$BUILDTOOL_HOME/skopeo/.docker/src-config.json" --dest-authfile "$BUILDTOOL_HOME/skopeo/.docker/dest-config.json" ${DOCKER_PUBLISH_ARGS} "docker://$DOCKER_SNAPSHOT_IMAGE" "docker://$DOCKER_RELEASE_IMAGE" | tee skopeo-copy.log
- |
if [[ ${DOCKER_COSIGN_STRATEGY} == "onrelease" ]] || [[ ${DOCKER_COSIGN_STRATEGY} == "always" ]]
then
@@ -1404,12 +1408,16 @@ docker-publish:
release_repository=${DOCKER_RELEASE_IMAGE%:*}
# extract snapshot image digest
# ⚠ don't use upstream $docker_digest due to possible parallel matrix job producing several
- docker_digest=$(skopeo inspect ${TRACE+--debug} --authfile "$BUILDTOOL_HOME/skopeo/.docker/src-config.json" --format='{{ .Digest }}' "docker://$DOCKER_SNAPSHOT_IMAGE")
- tag=$(echo "${docker_digest}" | tr ':' '-')
- log_info "Copying image signature to ${release_repository}:${tag}.sig..."
- skopeo copy ${TRACE+--debug} --src-authfile "$BUILDTOOL_HOME/skopeo/.docker/src-config.json" --dest-authfile "$BUILDTOOL_HOME/skopeo/.docker/dest-config.json" ${DOCKER_PUBLISH_ARGS} "docker://${snapshot_repository}:${tag}.sig" "docker://${release_repository}:${tag}.sig"
- log_info "Copying image attestation to ${release_repository}:${tag}.att..."
- skopeo copy ${TRACE+--debug} --src-authfile "$BUILDTOOL_HOME/skopeo/.docker/src-config.json" --dest-authfile "$BUILDTOOL_HOME/skopeo/.docker/dest-config.json" ${DOCKER_PUBLISH_ARGS} "docker://${snapshot_repository}:${tag}.att" "docker://${release_repository}:${tag}.att"
+ docker_digest=$(skopeo inspect ${TRACE+--debug} --authfile "$BUILDTOOL_HOME/skopeo/.docker/src-config.json" --format='{{ .Digest }}' --no-tags "docker://$DOCKER_SNAPSHOT_IMAGE")
+ all_digests="$docker_digest"$'\n'"$(sed -nE 's|Copying image (sha256:[[:alnum:]]+).*|\1|p' skopeo-copy.log)"
+ echo "$all_digests" | tr ':' '-' | sed '/^[ \t]*$/d' | while read sha; do
+ log_info "Copying image signature to ${release_repository}:${sha}.sig..."
+ skopeo copy ${TRACE+--debug} --src-authfile "$BUILDTOOL_HOME/skopeo/.docker/src-config.json" --dest-authfile "$BUILDTOOL_HOME/skopeo/.docker/dest-config.json" ${DOCKER_PUBLISH_ARGS} "docker://${snapshot_repository}:${sha}.sig" "docker://${release_repository}:${sha}.sig" \
+ || log_warn "No signature found for ${sha}"
+ log_info "Copying image attestation to ${release_repository}:${sha}.att..."
+ skopeo copy ${TRACE+--debug} --src-authfile "$BUILDTOOL_HOME/skopeo/.docker/src-config.json" --dest-authfile "$BUILDTOOL_HOME/skopeo/.docker/dest-config.json" ${DOCKER_PUBLISH_ARGS} "docker://${snapshot_repository}:${sha}.att" "docker://${release_repository}:${sha}.att" \
+ || log_warn "No attestation found for ${sha}"
+ done
fi
- |
log_info "Well done your image is pushed and can be pulled with: docker pull $DOCKER_RELEASE_IMAGE"