Skip to content

Commit 275e015

Browse files
authored
Have the keyless cosign sign flow use a single 3LO. (#665)
* Have the keyless `cosign sign` flow use a single 3LO. With this change, the keyless flow builds a single signer for all of the images, which means a single key and 3LO for all of the references we sign: ```shell $ COSIGN_EXPERIMENTAL=true cosign sign ghcr.io/mattmoor/controller ghcr.io/mattmoor/webhook Generating ephemeral keys... Retrieving signed certificate... Your browser will now be opened to: https://oauth2.sigstore.dev/auth/auth?REDACTED Successfully verified SCT... tlog entry created with index: 693418 Pushing signature to: ghcr.io/mattmoor/controller:sha256-b10f4b2e04cde2e799e080068f162ef668c4db3099382798b5fe1a208023105d.sig tlog entry created with index: 693420 Pushing signature to: ghcr.io/mattmoor/webhook:sha256-ed1b1c778685ae0739cd4c6354fa2d724351b01e998a019d1ddc2909c377483d.sig ``` Fixes: #658 Signed-off-by: Matt Moore <[email protected]> * Update the e2e tests as well Signed-off-by: Matt Moore <[email protected]>
1 parent 152eefb commit 275e015

File tree

3 files changed

+44
-42
lines changed

3 files changed

+44
-42
lines changed

cmd/cosign/cli/sign.go

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,11 @@ EXAMPLES
186186
OIDCClientID: *oidcClientID,
187187
OIDCClientSecret: *oidcClientSecret,
188188
}
189-
for _, img := range args {
190-
if err := SignCmd(ctx, ko, annotations.annotations, img, *cert, *upload, *payloadPath, *force, *recursive, *attachment); err != nil {
191-
if *attachment == "" {
192-
return errors.Wrapf(err, "signing %s", img)
193-
}
194-
return errors.Wrapf(err, "signing attachement %s for image %s", *attachment, img)
189+
if err := SignCmd(ctx, ko, annotations.annotations, args, *cert, *upload, *payloadPath, *force, *recursive, *attachment); err != nil {
190+
if *attachment == "" {
191+
return errors.Wrapf(err, "signing %v", args)
195192
}
193+
return errors.Wrapf(err, "signing attachement %s for image %v", *attachment, args)
196194
}
197195
return nil
198196
},
@@ -257,12 +255,7 @@ func getTransitiveImages(rootIndex *remote.Descriptor, repo name.Repository, opt
257255
}
258256

259257
func SignCmd(ctx context.Context, ko KeyOpts, annotations map[string]interface{},
260-
inputImg string, certPath string, upload bool, payloadPath string, force bool, recursive bool, attachment string) error {
261-
// A key file or token is required unless we're in experimental mode!
262-
imageRef, err := getAttachedImageRef(ctx, inputImg, attachment)
263-
if err != nil {
264-
return fmt.Errorf("unable to resolve attachment %s for image %s", attachment, inputImg)
265-
}
258+
imgs []string, certPath string, upload bool, payloadPath string, force bool, recursive bool, attachment string) error {
266259

267260
if EnableExperimental() {
268261
if nOf(ko.KeyRef, ko.Sk) > 1 {
@@ -279,27 +272,36 @@ func SignCmd(ctx context.Context, ko KeyOpts, annotations map[string]interface{}
279272
remote.WithContext(ctx),
280273
}
281274

282-
ref, err := name.ParseReference(imageRef)
283-
if err != nil {
284-
return errors.Wrap(err, "parsing reference")
285-
}
286-
get, err := remote.Get(ref, remoteOpts...)
287-
if err != nil {
288-
return errors.Wrap(err, "getting remote image")
289-
}
275+
var toSign []name.Digest
276+
for _, inputImg := range imgs {
290277

291-
repo := ref.Context()
292-
img := repo.Digest(get.Digest.String())
293-
294-
toSign := []name.Digest{img}
278+
// A key file or token is required unless we're in experimental mode!
279+
imageRef, err := getAttachedImageRef(ctx, inputImg, attachment)
280+
if err != nil {
281+
return fmt.Errorf("unable to resolve attachment %s for image %s", attachment, inputImg)
282+
}
295283

296-
if recursive && get.MediaType.IsIndex() {
297-
imgs, err := getTransitiveImages(get, repo, remoteOpts...)
284+
ref, err := name.ParseReference(imageRef)
298285
if err != nil {
299-
return err
286+
return errors.Wrap(err, "parsing reference")
287+
}
288+
get, err := remote.Get(ref, remoteOpts...)
289+
if err != nil {
290+
return errors.Wrap(err, "getting remote image")
291+
}
292+
293+
repo := ref.Context()
294+
toSign = append(toSign, repo.Digest(get.Digest.String()))
295+
296+
if recursive && get.MediaType.IsIndex() {
297+
imgs, err := getTransitiveImages(get, repo, remoteOpts...)
298+
if err != nil {
299+
return err
300+
}
301+
toSign = append(toSign, imgs...)
300302
}
301-
toSign = append(toSign, imgs...)
302303
}
304+
303305
sv, err := signerFromKeyOpts(ctx, certPath, ko)
304306
if err != nil {
305307
return errors.Wrap(err, "getting signer")
@@ -339,7 +341,7 @@ func SignCmd(ctx context.Context, ko KeyOpts, annotations map[string]interface{}
339341
continue
340342
}
341343

342-
sigRepo, err := TargetRepositoryForImage(ref)
344+
sigRepo, err := TargetRepositoryForImage(img)
343345
if err != nil {
344346
return err
345347
}
@@ -357,7 +359,7 @@ func SignCmd(ctx context.Context, ko KeyOpts, annotations map[string]interface{}
357359
}
358360

359361
// Check if the image is public (no auth in Get)
360-
uploadTLog, err := shouldUploadToTlog(ref, force, ko.RekorURL)
362+
uploadTLog, err := shouldUploadToTlog(img, force, ko.RekorURL)
361363
if err != nil {
362364
return err
363365
}

cmd/cosign/cli/sign_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func TestSignCmdLocalKeyAndSk(t *testing.T) {
3434
Sk: true,
3535
},
3636
} {
37-
err := SignCmd(ctx, ko, nil, "", "", false, "", false, false, "")
37+
err := SignCmd(ctx, ko, nil, nil, "", false, "", false, false, "")
3838
if (errors.Is(err, &KeyParseError{}) == false) {
3939
t.Fatal("expected KeyParseError")
4040
}

test/e2e_test.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func TestSignVerify(t *testing.T) {
9797

9898
// Now sign the image
9999
ko := cli.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc}
100-
must(cli.SignCmd(ctx, ko, nil, imgName, "", true, "", false, false, ""), t)
100+
must(cli.SignCmd(ctx, ko, nil, []string{imgName}, "", true, "", false, false, ""), t)
101101

102102
// Now verify and download should work!
103103
must(verify(pubKeyPath, imgName, true, nil, ""), t)
@@ -108,7 +108,7 @@ func TestSignVerify(t *testing.T) {
108108

109109
// Sign the image with an annotation
110110
annotations := map[string]interface{}{"foo": "bar"}
111-
must(cli.SignCmd(ctx, ko, annotations, imgName, "", true, "", false, false, ""), t)
111+
must(cli.SignCmd(ctx, ko, annotations, []string{imgName}, "", true, "", false, false, ""), t)
112112

113113
// It should match this time.
114114
must(verify(pubKeyPath, imgName, true, map[string]interface{}{"foo": "bar"}, ""), t)
@@ -132,7 +132,7 @@ func TestSignVerifyClean(t *testing.T) {
132132

133133
// Now sign the image
134134
ko := cli.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc}
135-
must(cli.SignCmd(ctx, ko, nil, imgName, "", true, "", false, false, ""), t)
135+
must(cli.SignCmd(ctx, ko, nil, []string{imgName}, "", true, "", false, false, ""), t)
136136

137137
// Now verify and download should work!
138138
must(verify(pubKeyPath, imgName, true, nil, ""), t)
@@ -206,7 +206,7 @@ func TestBundle(t *testing.T) {
206206
}
207207

208208
// Sign the image
209-
must(cli.SignCmd(ctx, ko, nil, imgName, "", true, "", false, false, ""), t)
209+
must(cli.SignCmd(ctx, ko, nil, []string{imgName}, "", true, "", false, false, ""), t)
210210
// Make sure verify works
211211
must(verify(pubKeyPath, imgName, true, nil, ""), t)
212212

@@ -236,14 +236,14 @@ func TestDuplicateSign(t *testing.T) {
236236

237237
// Now sign the image
238238
ko := cli.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc}
239-
must(cli.SignCmd(ctx, ko, nil, imgName, "", true, "", false, false, ""), t)
239+
must(cli.SignCmd(ctx, ko, nil, []string{imgName}, "", true, "", false, false, ""), t)
240240

241241
// Now verify and download should work!
242242
must(verify(pubKeyPath, imgName, true, nil, ""), t)
243243
must(download.SignatureCmd(ctx, imgName), t)
244244

245245
// Signing again should work just fine...
246-
must(cli.SignCmd(ctx, ko, nil, imgName, "", true, "", false, false, ""), t)
246+
must(cli.SignCmd(ctx, ko, nil, []string{imgName}, "", true, "", false, false, ""), t)
247247
// but a duplicate signature should not be a uploaded
248248
sigRepo, err := cli.TargetRepositoryForImage(ref)
249249
if err != nil {
@@ -337,14 +337,14 @@ func TestMultipleSignatures(t *testing.T) {
337337

338338
// Now sign the image with one key
339339
ko := cli.KeyOpts{KeyRef: priv1, PassFunc: passFunc}
340-
must(cli.SignCmd(ctx, ko, nil, imgName, "", true, "", false, false, ""), t)
340+
must(cli.SignCmd(ctx, ko, nil, []string{imgName}, "", true, "", false, false, ""), t)
341341
// Now verify should work with that one, but not the other
342342
must(verify(pub1, imgName, true, nil, ""), t)
343343
mustErr(verify(pub2, imgName, true, nil, ""), t)
344344

345345
// Now sign with the other key too
346346
ko.KeyRef = priv2
347-
must(cli.SignCmd(ctx, ko, nil, imgName, "", true, "", false, false, ""), t)
347+
must(cli.SignCmd(ctx, ko, nil, []string{imgName}, "", true, "", false, false, ""), t)
348348

349349
// Now verify should work with both
350350
must(verify(pub1, imgName, true, nil, ""), t)
@@ -626,7 +626,7 @@ func TestAttachSBOM(t *testing.T) {
626626

627627
// Now sign the sbom with one key
628628
ko1 := cli.KeyOpts{KeyRef: privKeyPath1, PassFunc: passFunc}
629-
must(cli.SignCmd(ctx, ko1, nil, imgName, "", true, "", false, false, "sbom"), t)
629+
must(cli.SignCmd(ctx, ko1, nil, []string{imgName}, "", true, "", false, false, "sbom"), t)
630630

631631
// Now verify should work with that one, but not the other
632632
must(verify(pubKeyPath1, imgName, true, nil, "sbom"), t)
@@ -664,7 +664,7 @@ func TestTlog(t *testing.T) {
664664
PassFunc: passFunc,
665665
RekorURL: rekorURL,
666666
}
667-
must(cli.SignCmd(ctx, ko, nil, imgName, "", true, "", false, false, ""), t)
667+
must(cli.SignCmd(ctx, ko, nil, []string{imgName}, "", true, "", false, false, ""), t)
668668

669669
// Now verify should work!
670670
must(verify(pubKeyPath, imgName, true, nil, ""), t)
@@ -676,7 +676,7 @@ func TestTlog(t *testing.T) {
676676
mustErr(verify(pubKeyPath, imgName, true, nil, ""), t)
677677

678678
// Sign again with the tlog env var on
679-
must(cli.SignCmd(ctx, ko, nil, imgName, "", true, "", false, false, ""), t)
679+
must(cli.SignCmd(ctx, ko, nil, []string{imgName}, "", true, "", false, false, ""), t)
680680
// And now verify works!
681681
must(verify(pubKeyPath, imgName, true, nil, ""), t)
682682
}

0 commit comments

Comments
 (0)