Skip to content

Dockerfile.rego - signature validation does not work with standard keyless Cosign signatures. #4010

Description

@K-Fl

Contributing guidelines

I've found a bug and checked that ...

  • ... the documentation does not mention anything about my problem
  • ... there are no open or closed issues that are related to my problem

Description

I am testing the Dockerfile.rego to validate base-image signatures, and while I did get it working, it required several non-obvious workarounds.
I followed the Docker documentation on image attestation and provenance(https://docs.docker.com/build/policies/examples/) , but was unable to get signature validation working with standard keyless Cosign signatures out of the box. Here is what I had to do to make it work:

  • Sign the attestation manifest, not the root digest. Docker Build Policy follows the provenance chain (OCI index → platform manifest → provenance attestation → signature), so a signature on the root digest alone is not sufficient.
  • Use Cosign's legacy simplesigning-v1 format with --new-bundle-format=false and --experimental-oci11=true. The default bundle format used by Cosign v3 is not recognized by BuildKit.
  • Downgrade to Cosign v2.6.5, because newer versions (e.g. v3.1.3) fail hard on Rekor 409 Conflict responses, whereas v2.6.5 correctly falls back to fetching and verifying the existing log entry.

After applying all of the above, everything works as expected.

It would be great if the signature validation policy could be updated to support the latest Cosign bundle format and root digest signature validation, so that standard keyless signing works without requiring these workarounds.

Expected behaviour

I expect Dockerfile.rego to successfully validate images signed with keyless cosign signatures, signed like this:

                IMAGE_DIGEST_REF="${{ inputs.image }}@${IMAGE_DIGEST}"
                COSIGN_ARGS=(
                  --yes
                  -a sType=image
                  -a stage=${STAGE}
                  -a gitRepo=${{ github.repository }}
                  -a gitRef=${{ github.ref }}
                  -a gitCommitSha=${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
                  -a ciRunId=${{ github.run_id }}
                  -a ciRunAttempt=${{ github.run_attempt }}
                  -a workflowRef=${{ github.workflow_ref }}
                  -a imageTag=${{ inputs.version_tag }}
                  -a imageDigest=${IMAGE_DIGEST}
                )

                cosign sign "${COSIGN_ARGS[@]}" "${IMAGE_DIGEST_REF}"

Actual behaviour

To get it work I had to signe like this:

                INDEX_JSON="$(docker buildx imagetools inspect --raw "${VERSION_IMAGE}")"
                mapfile -t ATTESTATION_DIGESTS < <(jq -r \
                  '.manifests[] | select(.annotations["vnd.docker.reference.type"] == "attestation-manifest") | .digest' \
                  <<< "$INDEX_JSON" | sort -u)

                if [[ "${#ATTESTATION_DIGESTS[@]}" -eq 0 ]]; then
                  echo "FAIL: no attestation manifests found for ${VERSION_IMAGE}"
                  exit 1
                fi

                for attestation_digest in "${ATTESTATION_DIGESTS[@]}"; do
                  cosign sign \
                    --new-bundle-format=false \
                    --use-signing-config=false \
                    --registry-referrers-mode=oci-1-1 \
                    "${{ inputs.image }}@${attestation_digest}"
                  echo "Signed attestation digest: ${attestation_digest}"
                done

Buildx version

github.com/docker/buildx v0.36.1

Docker info


Builders list

docker buildx ls 
NAME/NODE             DRIVER/ENDPOINT                                     STATUS    BUILDKIT   PLATFORMS
policytest*           docker-container                                                         
 \_ policytest0        \_ unix:///Users/kjetil.floisand/.rd/docker.sock   running   v0.32.2    linux/amd64 (+2), linux/arm64
default               docker                                                                   
 \_ default            \_ default                                         running   v0.30.0    linux/amd64 (+2), linux/arm64
rancher-desktop       docker                                                                   
 \_ rancher-desktop    \_ rancher-desktop                                 running   v0.30.0    linux/amd64 (+2), linux/arm64

Configuration

FROM ghcr.io/MY-ORG/test-sign.image:fb3014b11127-SNAPSHOT
package docker

default allow := false

allow if input.local

allow if {
  some sig in input.image.signatures
  trusted_github_builder(sig.signer)
}

trusted_github_builder(signer) if {
   input.image.hasProvenance
   signer.certificateIssuer == "CN=sigstore-intermediate,O=sigstore.dev"
   signer.issuer == "https://token.actions.githubusercontent.com"
   startswith(signer.buildSignerURI, "https://github.com/MY_ORG/image-actions/.github/workflows")
   signer.runnerEnvironment == "github-hosted"
}
decision := {
   "allow": allow
}

Build logs


Additional info

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions