Skip to content

Commit 7eb0302

Browse files
committed
Support multiple --sign-container-identity
With this change, cosign sign can be run only once when an image has multiple pull references. Closes #4330 Signed-off-by: Emily Zheng <[email protected]>
1 parent 45bda40 commit 7eb0302

File tree

3 files changed

+55
-30
lines changed

3 files changed

+55
-30
lines changed

cmd/cosign/cli/options/sign.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ type SignOptions struct {
4040
TSAServerName string
4141
TSAServerURL string
4242
IssueCertificate bool
43-
SignContainerIdentity string
43+
SignContainerIdentities []string
4444
RecordCreationTimestamp bool
4545
NewBundleFormat bool
4646
UseSigningConfig bool
@@ -137,7 +137,7 @@ func (o *SignOptions) AddFlags(cmd *cobra.Command) {
137137
cmd.Flags().BoolVar(&o.IssueCertificate, "issue-certificate", false,
138138
"issue a code signing certificate from Fulcio, even if a key is provided")
139139

140-
cmd.Flags().StringVar(&o.SignContainerIdentity, "sign-container-identity", "",
140+
cmd.Flags().StringArrayVar(&o.SignContainerIdentities, "sign-container-identity", nil,
141141
"manually set the .critical.docker-reference field for the signed identity, which is useful when image proxies are being used where the pull reference should match the signature")
142142

143143
cmd.Flags().BoolVar(&o.RecordCreationTimestamp, "record-creation-timestamp", false, "set the createdAt timestamp in the signature artifact to the time it was created; by default, cosign sets this to the zero value")

cmd/cosign/cli/sign/sign.go

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -392,16 +392,26 @@ func signDigestBundle(ctx context.Context, digest name.Digest, ko options.KeyOpt
392392
func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko options.KeyOpts, signOpts options.SignOptions,
393393
annotations map[string]interface{}, se oci.SignedEntity) error {
394394
var err error
395+
var payloads [][]byte
395396
// The payload can be passed to skip generation.
396397
if len(payload) == 0 {
397-
payload, err = (&sigPayload.Cosign{
398-
Image: digest,
399-
ClaimedIdentity: signOpts.SignContainerIdentity,
400-
Annotations: annotations,
401-
}).MarshalJSON()
402-
if err != nil {
403-
return fmt.Errorf("payload: %w", err)
398+
identities := signOpts.SignContainerIdentities
399+
if len(identities) == 0 {
400+
identities = append(identities, "")
401+
}
402+
for _, identity := range identities {
403+
payload, err = (&sigPayload.Cosign{
404+
Image: digest,
405+
ClaimedIdentity: identity,
406+
Annotations: annotations,
407+
}).MarshalJSON()
408+
if err != nil {
409+
return fmt.Errorf("payload: %w", err)
410+
}
411+
payloads = append(payloads, payload)
404412
}
413+
} else {
414+
payloads = append(payloads, payload)
405415
}
406416

407417
sv, genKey, err := SignerFromKeyOpts(ctx, signOpts.Cert, signOpts.CertChain, ko)
@@ -447,14 +457,21 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti
447457
s = irekor.NewSigner(s, rClient)
448458
}
449459

450-
ociSig, _, err := s.Sign(ctx, bytes.NewReader(payload))
451-
if err != nil {
452-
return err
453-
}
460+
ociSigs := make([]oci.Signature, len(payloads))
461+
b64sigs := make([]string, len(payloads))
454462

455-
b64sig, err := ociSig.Base64Signature()
456-
if err != nil {
457-
return err
463+
for i, payload := range payloads {
464+
ociSig, _, err := s.Sign(ctx, bytes.NewReader(payload))
465+
if err != nil {
466+
return err
467+
}
468+
ociSigs[i] = ociSig
469+
470+
b64sig, err := ociSig.Base64Signature()
471+
if err != nil {
472+
return err
473+
}
474+
b64sigs[i] = b64sig
458475
}
459476

460477
outputSignature := signOpts.OutputSignature
@@ -463,7 +480,7 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti
463480
if signOpts.Recursive {
464481
outputSignature = fmt.Sprintf("%s-%s", outputSignature, strings.Replace(digest.DigestStr(), ":", "-", 1))
465482
}
466-
if err := os.WriteFile(outputSignature, []byte(b64sig), 0600); err != nil {
483+
if err := os.WriteFile(outputSignature, []byte(strings.Join(b64sigs, "\n")), 0600); err != nil {
467484
return fmt.Errorf("create signature file: %w", err)
468485
}
469486
}
@@ -473,7 +490,7 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti
473490
if signOpts.Recursive {
474491
outputPayload = fmt.Sprintf("%s-%s", outputPayload, strings.Replace(digest.DigestStr(), ":", "-", 1))
475492
}
476-
if err := os.WriteFile(outputPayload, payload, 0600); err != nil {
493+
if err := os.WriteFile(outputPayload, bytes.Join(payloads, []byte("\n")), 0600); err != nil {
477494
return fmt.Errorf("create payload file: %w", err)
478495
}
479496
}
@@ -492,16 +509,20 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti
492509
}
493510

494511
if ko.BundlePath != "" {
495-
signedPayload, err := fetchLocalSignedPayload(ociSig)
496-
if err != nil {
497-
return fmt.Errorf("failed to fetch signed payload: %w", err)
498-
}
512+
var contents [][]byte
513+
for _, ociSig := range ociSigs {
514+
signedPayload, err := fetchLocalSignedPayload(ociSig)
515+
if err != nil {
516+
return fmt.Errorf("failed to fetch signed payload: %w", err)
517+
}
499518

500-
contents, err := json.Marshal(signedPayload)
501-
if err != nil {
502-
return fmt.Errorf("failed to marshal signed payload: %w", err)
519+
content, err := json.Marshal(signedPayload)
520+
if err != nil {
521+
return fmt.Errorf("failed to marshal signed payload: %w", err)
522+
}
523+
contents = append(contents, content)
503524
}
504-
if err := os.WriteFile(ko.BundlePath, contents, 0600); err != nil {
525+
if err := os.WriteFile(ko.BundlePath, bytes.Join(contents, []byte("\n")), 0600); err != nil {
505526
return fmt.Errorf("create bundle file: %w", err)
506527
}
507528
ui.Infof(ctx, "Wrote bundle to file %s", ko.BundlePath)
@@ -512,9 +533,13 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti
512533
}
513534

514535
// Attach the signature to the entity.
515-
newSE, err := mutate.AttachSignatureToEntity(se, ociSig, mutate.WithDupeDetector(dd), mutate.WithRecordCreationTimestamp(signOpts.RecordCreationTimestamp))
516-
if err != nil {
517-
return err
536+
var newSE oci.SignedEntity
537+
for _, ociSig := range ociSigs {
538+
newSE, err = mutate.AttachSignatureToEntity(se, ociSig, mutate.WithDupeDetector(dd), mutate.WithRecordCreationTimestamp(signOpts.RecordCreationTimestamp))
539+
if err != nil {
540+
return err
541+
}
542+
se = newSE
518543
}
519544

520545
// Publish the signatures associated with this entity

doc/cosign_sign.md

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)