Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Honor creation timestamp for signatures again #3549

Merged
merged 4 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 23 additions & 20 deletions cmd/cosign/cli/options/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,27 @@ import (

// SignOptions is the top level wrapper for the sign command.
type SignOptions struct {
Key string
Cert string
CertChain string
Upload bool
Output string // deprecated: TODO remove when the output flag is fully deprecated
OutputSignature string // TODO: this should be the root output file arg.
OutputPayload string
OutputCertificate string
PayloadPath string
Recursive bool
Attachment string
SkipConfirmation bool
TlogUpload bool
TSAClientCACert string
TSAClientCert string
TSAClientKey string
TSAServerName string
TSAServerURL string
IssueCertificate bool
SignContainerIdentity string
Key string
Cert string
CertChain string
Upload bool
Output string // deprecated: TODO remove when the output flag is fully deprecated
OutputSignature string // TODO: this should be the root output file arg.
OutputPayload string
OutputCertificate string
PayloadPath string
Recursive bool
Attachment string
SkipConfirmation bool
TlogUpload bool
TSAClientCACert string
TSAClientCert string
TSAClientKey string
TSAServerName string
TSAServerURL string
IssueCertificate bool
SignContainerIdentity string
RecordCreationTimestamp bool

Rekor RekorOptions
Fulcio FulcioOptions
Expand Down Expand Up @@ -130,4 +131,6 @@ func (o *SignOptions) AddFlags(cmd *cobra.Command) {

cmd.Flags().StringVar(&o.SignContainerIdentity, "sign-container-identity", "",
"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")

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")
}
5 changes: 4 additions & 1 deletion cmd/cosign/cli/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ race conditions or (worse) malicious tampering.
cosign sign --key cosign.key --tlog-upload=false <IMAGE DIGEST>

# sign a container image by manually setting the container image identity
cosign sign --sign-container-identity <NEW IMAGE DIGEST> <IMAGE DIGEST>`,
cosign sign --sign-container-identity <NEW IMAGE DIGEST> <IMAGE DIGEST>

# sign a container image and honor the creation timestamp of the signature
cosign sign --key cosign.key --record-creation-timestamp <IMAGE DIGEST>`,

Args: cobra.MinimumNArgs(1),
PersistentPreRun: options.BindViper,
Expand Down
2 changes: 1 addition & 1 deletion cmd/cosign/cli/sign/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti
}

// Attach the signature to the entity.
newSE, err := mutate.AttachSignatureToEntity(se, ociSig, mutate.WithDupeDetector(dd))
newSE, err := mutate.AttachSignatureToEntity(se, ociSig, mutate.WithDupeDetector(dd), mutate.WithRecordCreationTimestamp(signOpts.RecordCreationTimestamp))
if err != nil {
return err
}
Expand Down
4 changes: 4 additions & 0 deletions doc/cosign_sign.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/oci/mutate/mutate.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,5 +377,5 @@ func (so *signOpts) dedupeAndReplace(sig oci.Signature, basefn func() (oci.Signa
}
return ReplaceSignatures(replace)
}
return AppendSignatures(base, sig)
return AppendSignatures(base, so.rct, sig)
}
11 changes: 9 additions & 2 deletions pkg/oci/mutate/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ type ReplaceOp interface {
type SignOption func(*signOpts)

type signOpts struct {
dd DupeDetector
ro ReplaceOp
dd DupeDetector
ro ReplaceOp
rct bool
}

func makeSignOpts(opts ...SignOption) *signOpts {
Expand All @@ -59,6 +60,12 @@ func WithReplaceOp(ro ReplaceOp) SignOption {
}
}

func WithRecordCreationTimestamp(rct bool) SignOption {
return func(so *signOpts) {
so.rct = rct
}
}

type signatureOpts struct {
annotations map[string]string
bundle *bundle.RekorBundle
Expand Down
16 changes: 15 additions & 1 deletion pkg/oci/mutate/signatures.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ import (
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/sigstore/cosign/v2/internal/pkg/now"
"github.com/sigstore/cosign/v2/pkg/oci"
)

// AppendSignatures produces a new oci.Signatures with the provided signatures
// appended to the provided base signatures.
func AppendSignatures(base oci.Signatures, sigs ...oci.Signature) (oci.Signatures, error) {
func AppendSignatures(base oci.Signatures, recordCreationTimestamp bool, sigs ...oci.Signature) (oci.Signatures, error) {
adds := make([]mutate.Addendum, 0, len(sigs))
for _, sig := range sigs {
ann, err := sig.Annotations()
Expand All @@ -42,6 +43,19 @@ func AppendSignatures(base oci.Signatures, sigs ...oci.Signature) (oci.Signature
return nil, err
}

if recordCreationTimestamp {
t, err := now.Now()
if err != nil {
return nil, err
}

// Set the Created date to time of execution
img, err = mutate.CreatedAt(img, v1.Time{Time: t})
if err != nil {
return nil, err
}
}

return &sigAppender{
Image: img,
base: base,
Expand Down
16 changes: 11 additions & 5 deletions pkg/oci/mutate/signatures_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,17 @@ func TestAppendSignatures(t *testing.T) {
t.Fatalf("NewSignature() = %v", err)
}

oneSig, err := AppendSignatures(base, s1)
oneSig, err := AppendSignatures(base, false, s1)
if err != nil {
t.Fatalf("AppendSignatures() = %v", err)
}

twoSig, err := AppendSignatures(oneSig, s2)
twoSig, err := AppendSignatures(oneSig, false, s2)
if err != nil {
t.Fatalf("AppendSignatures() = %v", err)
}

threeSig, err := AppendSignatures(oneSig, s2, s3)
threeSig, err := AppendSignatures(oneSig, true, s2, s3)
if err != nil {
t.Fatalf("AppendSignatures() = %v", err)
}
Expand All @@ -73,7 +73,13 @@ func TestAppendSignatures(t *testing.T) {

if testCfg, err := threeSig.ConfigFile(); err != nil {
t.Fatalf("ConfigFile() = %v", err)
} else if !testCfg.Created.Time.IsZero() {
t.Errorf("Date of Signature was not Zero")
} else if testCfg.Created.Time.IsZero() {
t.Errorf("Date of Signature was Zero")
}

if testDefaultCfg, err := twoSig.ConfigFile(); err != nil {
t.Fatalf("ConfigFile() = %v", err)
} else if !testDefaultCfg.Created.Time.IsZero() {
t.Errorf("Date of Signature was Zero")
}
}
14 changes: 14 additions & 0 deletions pkg/oci/static/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/google/go-containerregistry/pkg/v1/types"
"github.com/sigstore/cosign/v2/internal/pkg/now"
"github.com/sigstore/cosign/v2/pkg/oci"
"github.com/sigstore/cosign/v2/pkg/oci/signed"
)
Expand All @@ -48,6 +49,19 @@ func NewFile(payload []byte, opts ...Option) (oci.File, error) {
// Add annotations from options
img = mutate.Annotations(img, o.Annotations).(v1.Image)

if o.RecordCreationTimestamp {
t, err := now.Now()
if err != nil {
return nil, err
}

// Set the Created date to time of execution
img, err = mutate.CreatedAt(img, v1.Time{Time: t})
if err != nil {
return nil, err
}
}

return &file{
SignedImage: signed.Image(img),
layer: layer,
Expand Down
13 changes: 13 additions & 0 deletions pkg/oci/static/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ func TestNewFile(t *testing.T) {
t.Fatalf("NewFile() = %v", err)
}

timestampedFile, err := NewFile([]byte(payload), WithLayerMediaType("foo"), WithAnnotations(map[string]string{"foo": "bar"}), WithRecordCreationTimestamp(true))

if err != nil {
t.Fatalf("NewFile() = %v", err)
}

layers, err := file.Layers()
if err != nil {
t.Fatalf("Layers() = %v", err)
Expand Down Expand Up @@ -129,6 +135,13 @@ func TestNewFile(t *testing.T) {
if !fileCfg.Created.Time.IsZero() {
t.Errorf("Date of Signature was not Zero")
}
tsCfg, err := timestampedFile.ConfigFile()
if err != nil {
t.Fatalf("ConfigFile() = %v", err)
}
if tsCfg.Created.Time.IsZero() {
t.Errorf("Date of Signature was Zero")
}
})

t.Run("check annotations", func(t *testing.T) {
Expand Down
22 changes: 15 additions & 7 deletions pkg/oci/static/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@ import (
type Option func(*options)

type options struct {
LayerMediaType types.MediaType
ConfigMediaType types.MediaType
Bundle *bundle.RekorBundle
RFC3161Timestamp *bundle.RFC3161Timestamp
Cert []byte
Chain []byte
Annotations map[string]string
LayerMediaType types.MediaType
ConfigMediaType types.MediaType
Bundle *bundle.RekorBundle
RFC3161Timestamp *bundle.RFC3161Timestamp
Cert []byte
Chain []byte
Annotations map[string]string
RecordCreationTimestamp bool
}

func makeOptions(opts ...Option) (*options, error) {
Expand Down Expand Up @@ -112,3 +113,10 @@ func WithCertChain(cert, chain []byte) Option {
o.Chain = chain
}
}

// WithRecordCreationTimestamp sets the feature flag to honor the creation timestamp to time of running
func WithRecordCreationTimestamp(rct bool) Option {
return func(o *options) {
o.RecordCreationTimestamp = rct
}
}
Loading