sigstore / cosign

Code signing and transparency for containers and binaries
Apache License 2.0
4.38k stars 533 forks source link

`cosign dockerfile verify` problem with multistage dockerfile #3425

Open itsibitzi opened 9 months ago

itsibitzi commented 9 months ago

Question

Hello everyone, I've spent a while Googling and hunting after docs and other issues to no avail, so I thought I'd ask here. Apologies in advance if I've missed something.

I've got the following multistage docker file for building a Rust project, using cargo-chef to cache dependencies. The details of this hopefully shouldn't matter but here's the whole file anyway.

# We need perl to build OpenSSL
FROM cgr.dev/chainguard/wolfi-base AS perl

# We need perl to build OpenSSL but the Rust wofli image doesn't ship with perl
# and it seems easier to simply move perl from wolfi-base than to build a whole new wolfi image?
RUN apk update && apk add perl

#
# Install chef on the chainguard image
#
FROM cgr.dev/chainguard/rust AS chainguard-rust-chef
WORKDIR /app

# Set up PATH to work cargo-chef
ENV PATH="/home/nonroot/.cargo/bin:$PATH"
ENV CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse

RUN cargo install cargo-chef --locked --version 0.1.62
RUN rm -rf $CARGO_HOME/registry/

COPY --from=perl /usr/share/perl5/ /usr/share/perl5/
COPY --from=perl /usr/lib/perl5/   /usr/lib/perl5/
COPY --from=perl /usr/bin/perl     /usr/bin/perl 

#
# PLAN (learn dependencies)
#
FROM chainguard-rust-chef AS planner

COPY . .

RUN cargo chef prepare --recipe-path recipe.json

#
# BUILD
#
FROM chainguard-rust-chef AS build

# pre-build dependencies (and cache!)
COPY --from=planner /app/recipe.json recipe.json

RUN cargo chef cook --release --recipe-path recipe.json --bin api

COPY . .

RUN cargo build --release --bin api

#
# RUN
#
FROM cgr.dev/chainguard/glibc-dynamic
COPY --from=build --chown=nonroot:nonroot /app/target/release/api /usr/local/bin/api

EXPOSE 3000

CMD ["/usr/local/bin/api"]

In my GitHub actions I would like to verify the signatures of all of the stages before I build Dockerfile, which cosign dockerfile verify looks to be the tool for.

When I run the following command I get messages about error during command execution: GET https://index.docker.io/v2/library/chainguard-rust-chef/manifests/latest - suggesting that cosign is trying to look up my multistage FROM in the docker registry, which seems wrong since it shouldn't exist. You can see the warning at the bottom of this snippet.

sam_cutler@31456 code % cosign dockerfile verify ./docker/prod/api/Dockerfile --certificate-identity 'https://github.com/chainguard-images/images/.github/workflows/release.yaml@refs/heads/main' --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' | jq .
Extracted image(s): cgr.dev/chainguard/wolfi-base, cgr.dev/chainguard/rust, chainguard-rust-chef, chainguard-rust-chef, cgr.dev/chainguard/glibc-dynamic

Verification for cgr.dev/chainguard/wolfi-base:latest --
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - Existence of the claims in the transparency log was verified offline
  - The code-signing certificate was verified using trusted certificate authority certificates

--- SNIP a load of JSON ---

Verification for cgr.dev/chainguard/rust:latest --
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - Existence of the claims in the transparency log was verified offline
  - The code-signing certificate was verified using trusted certificate authority certificates

--- SNIP a load of JSON ---

Error: GET https://index.docker.io/v2/library/chainguard-rust-chef/manifests/latest: UNAUTHORIZED: authentication required; [map[Action:pull Class: Name:library/chainguard-rust-chef Type:repository]]
main.go:69: error during command execution: GET https://index.docker.io/v2/library/chainguard-rust-chef/manifests/latest: UNAUTHORIZED: authentication required; [map[Action:pull Class: Name:library/chainguard-rust-chef Type:repository]]

Is there anything I can do to ignore the chainguard-rust-chef parts of the Dockerfile? The --base-image-only flag doesn't make any sense since if a malicious actor managed to publish a new cgr.dev/chainguard/rust image then they could possibly use that to insert an exploit into my built binary.

This is the output of cosign version

sam_cutler@31456 code % cosign version
  ______   ______        _______. __    _______ .__   __.
 /      | /  __  \      /       ||  |  /  _____||  \ |  |
|  ,----'|  |  |  |    |   (----`|  | |  |  __  |   \|  |
|  |     |  |  |  |     \   \    |  | |  | |_ | |  . `  |
|  `----.|  `--'  | .----)   |   |  | |  |__| | |  |\   |
 \______| \______/  |_______/    |__|  \______| |__| \__|
cosign: A tool for Container Signing, Verification and Storage in an OCI registry.

GitVersion:    2.2.2
GitCommit:     bf6b57bc3edf8deb7e225e4dbd2d26c0d432979b
GitTreeState:  "clean"
BuildDate:     2023-12-05T18:59:25Z
GoVersion:     go1.21.4
Compiler:      gc
Platform:      darwin/arm64

Thank you!

haydentherapper commented 9 months ago

@hectorj2f @cpanato Any suggestions?

hectorj2f commented 9 months ago

Initially it seems it cannot replace the label chainguard-rust-chef by the cgr.dev/chain guard/rust image. It wrongly attempts to fetch it from docker hub where it doesn't exist. I need to check whether this is a bug 🔍.

itsibitzi commented 8 months ago

Thanks for the responses so far!

Did you manage to see if it was a bug? In the mean time I can simply verify the signatures for each separate image independently, but that could become error prone if a new layer is added without a corresponding check in our CI.