1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-03-17 20:47:50 +02:00

feat: use digest to sign docker images/manifests (#3556)

this drives it home by using the actual images/manifest digests to sign
with cosign by default.

the default signing command is changing in this PR, but since `digest`
should be always there (if not, the pipeline will fail way earlier), it
should be fine.

refs https://github.com/goreleaser/goreleaser/issues/3496
refs https://github.com/goreleaser/goreleaser/pull/3540

Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com>
This commit is contained in:
Carlos Alexandro Becker 2022-11-15 08:21:18 -03:00 committed by GitHub
parent 2a46d627c7
commit b55b9976c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 21 additions and 9 deletions

View File

@ -137,6 +137,7 @@ const (
ExtraBinaries = "Binaries"
ExtraRefresh = "Refresh"
ExtraReplaces = "Replaces"
ExtraDigest = "Digest"
)
// Extras represents the extra fields in an artifact.

View File

@ -20,7 +20,7 @@ import (
const (
dockerConfigExtra = "DockerConfig"
dockerDigestExtra = "Digest"
dockerDigestExtra = artifact.ExtraDigest
useBuildx = "buildx"
useDocker = "docker"

View File

@ -154,6 +154,7 @@ func signone(ctx *context.Context, cfg config.Sign, art *artifact.Artifact) ([]*
env["artifactName"] = art.Name // shouldn't be used
env["artifact"] = art.Path
env["artifactID"] = art.ID()
env["digest"] = artifact.ExtraOr(*art, artifact.ExtraDigest, "")
tmplEnv, err := templateEnvS(ctx, cfg.Env)
if err != nil {

View File

@ -28,7 +28,7 @@ func (DockerPipe) Default(ctx *context.Context) error {
cfg.Cmd = "cosign"
}
if len(cfg.Args) == 0 {
cfg.Args = []string{"sign", "--key=cosign.key", "$artifact"}
cfg.Args = []string{"sign", "--key=cosign.key", "${artifact}@${digest}"}
}
if cfg.Artifacts == "" {
cfg.Artifacts = "none"

View File

@ -28,7 +28,7 @@ func TestDockerSignDefault(t *testing.T) {
require.NoError(t, err)
require.Equal(t, ctx.Config.DockerSigns[0].Cmd, "cosign")
require.Equal(t, ctx.Config.DockerSigns[0].Signature, "")
require.Equal(t, ctx.Config.DockerSigns[0].Args, []string{"sign", "--key=cosign.key", "$artifact"})
require.Equal(t, ctx.Config.DockerSigns[0].Args, []string{"sign", "--key=cosign.key", "${artifact}@${digest}"})
require.Equal(t, ctx.Config.DockerSigns[0].Artifacts, "none")
}
@ -54,12 +54,15 @@ func TestDockerSignArtifacts(t *testing.T) {
testlib.CheckPath(t, "cosign")
key := "cosign.key"
cmd := "sh"
args := []string{"-c", "echo ${artifact} > ${signature} && cosign sign --key=" + key + " --upload=false ${artifact} > ${signature}"}
args := []string{"-c", "echo ${artifact}@${digest} > ${signature} && cosign sign --key=" + key + " --upload=false ${artifact}@${digest} > ${signature}"}
password := "password"
img1 := "ghcr.io/caarlos0/goreleaser-docker-manifest-actions-example:1.2.1-amd64"
img1Digest := "sha256:d7bf8be1b156cc0cd9d2e33765a69bc968d4ef6b2dea9b207d63129b9709862a"
img2 := "ghcr.io/caarlos0/goreleaser-docker-manifest-actions-example:1.2.1-arm64v8"
img2Digest := "sha256:551801b7f42f8c33bfabb06e25804c2aca14776d2b7df33e07de54e887910b72"
man1 := "ghcr.io/caarlos0/goreleaser-docker-manifest-actions-example:1.2.1"
man1Digest := "sha256:b5db21408555f1ef5d68008a0a03a7caba3f29b62c64f1404e139b005a20bf03"
for name, cfg := range map[string]struct {
Signs []config.Sign
@ -88,7 +91,7 @@ func TestDockerSignArtifacts(t *testing.T) {
Stdin: &password,
Cmd: "cosign",
Certificate: `{{ replace (replace (replace .Env.artifact "/" "-") ":" "-") "." "" }}.pem`,
Args: []string{"sign", "--output-certificate=${certificate}", "--key=" + key, "--upload=false", "${artifact}"},
Args: []string{"sign", "--output-certificate=${certificate}", "--key=" + key, "--upload=false", "${artifact}@${digest}"},
},
},
},
@ -165,7 +168,8 @@ func TestDockerSignArtifacts(t *testing.T) {
Path: img1,
Type: artifact.DockerImage,
Extra: map[string]interface{}{
artifact.ExtraID: "img1",
artifact.ExtraID: "img1",
artifact.ExtraDigest: img1Digest,
},
})
ctx.Artifacts.Add(&artifact.Artifact{
@ -173,7 +177,8 @@ func TestDockerSignArtifacts(t *testing.T) {
Path: img2,
Type: artifact.DockerImage,
Extra: map[string]interface{}{
artifact.ExtraID: "img2",
artifact.ExtraID: "img2",
artifact.ExtraDigest: img2Digest,
},
})
ctx.Artifacts.Add(&artifact.Artifact{
@ -181,7 +186,8 @@ func TestDockerSignArtifacts(t *testing.T) {
Path: man1,
Type: artifact.DockerManifest,
Extra: map[string]interface{}{
artifact.ExtraID: "man1",
artifact.ExtraID: "man1",
artifact.ExtraDigest: man1Digest,
},
})

View File

@ -28,7 +28,7 @@ docker_signs:
# Command line templateable arguments for the command
#
# defaults to `["sign", "--key=cosign.key", "${artifact}"]`
# defaults to `["sign", "--key=cosign.key", "${artifact}@${digest}"]`
args: ["sign", "--key=cosign.key", "--upload=false", "${artifact}"]
@ -77,12 +77,16 @@ docker_signs:
These environment variables might be available in the fields that are templateable:
- `${artifact}`: the path to the artifact that will be signed [^1]
- `${digest}`: the digest of the image/manifest that will be signed [^2]
- `${artifactID}`: the ID of the artifact that will be signed
- `${certificate}`: the certificate file name, if provided
[^1]: notice that this might contain `/` characters, which depending on how
you use it might evaluate to actual paths within the file system. Use with
care.
[^2]: those are extracted automatically when running Docker push from within
GoReleaser. Using the digest helps making sure you're signing the right image
and avoid concurrency issues.
## Common usage example