diff --git a/cmd/cosign/cli/attest.go b/cmd/cosign/cli/attest.go index 644b85bf3524..66334471780e 100644 --- a/cmd/cosign/cli/attest.go +++ b/cmd/cosign/cli/attest.go @@ -31,7 +31,7 @@ func Attest() *cobra.Command { cmd := &cobra.Command{ Use: "attest", Short: "Attest the supplied container image.", - Example: ` cosign attest --key | [--predicate ] [--a key=value] [--no-upload=true|false] [--f] [--r] + Example: ` cosign attest --key | [--predicate ] [--a key=value] [--no-upload=true|false] [--record-creation-timestamp=true|false] [--f] [--r] # attach an attestation to a container image Google sign-in cosign attest --timeout 90s --predicate --type @@ -58,7 +58,10 @@ func Attest() *cobra.Command { COSIGN_DOCKER_MEDIA_TYPES=1 cosign attest --predicate --type --key cosign.key legacy-registry.example.com/my/image # supply attestation via stdin - echo | cosign attest --predicate - `, + echo | cosign attest --predicate - + + # attach an attestation to a container image and honor the creation timestamp of the signature + cosign attest --predicate --type --key cosign.key --record-creation-timestamp `, Args: cobra.MinimumNArgs(1), PersistentPreRun: options.BindViper, @@ -86,17 +89,18 @@ func Attest() *cobra.Command { TSAServerURL: o.TSAServerURL, } attestCommand := attest.AttestCommand{ - KeyOpts: ko, - RegistryOptions: o.Registry, - CertPath: o.Cert, - CertChainPath: o.CertChain, - NoUpload: o.NoUpload, - PredicatePath: o.Predicate.Path, - PredicateType: o.Predicate.Type, - Replace: o.Replace, - Timeout: ro.Timeout, - TlogUpload: o.TlogUpload, - RekorEntryType: o.RekorEntryType, + KeyOpts: ko, + RegistryOptions: o.Registry, + CertPath: o.Cert, + CertChainPath: o.CertChain, + NoUpload: o.NoUpload, + PredicatePath: o.Predicate.Path, + PredicateType: o.Predicate.Type, + Replace: o.Replace, + Timeout: ro.Timeout, + TlogUpload: o.TlogUpload, + RekorEntryType: o.RekorEntryType, + RecordCreationTimestamp: o.RecordCreationTimestamp, } for _, img := range args { diff --git a/cmd/cosign/cli/attest/attest.go b/cmd/cosign/cli/attest/attest.go index 0f1be95ae916..abfb25e83248 100644 --- a/cmd/cosign/cli/attest/attest.go +++ b/cmd/cosign/cli/attest/attest.go @@ -71,16 +71,17 @@ func uploadToTlog(ctx context.Context, sv *sign.SignerVerifier, rekorURL string, type AttestCommand struct { options.KeyOpts options.RegistryOptions - CertPath string - CertChainPath string - NoUpload bool - PredicatePath string - PredicateType string - Replace bool - Timeout time.Duration - TlogUpload bool - TSAServerURL string - RekorEntryType string + CertPath string + CertChainPath string + NoUpload bool + PredicatePath string + PredicateType string + Replace bool + Timeout time.Duration + TlogUpload bool + TSAServerURL string + RekorEntryType string + RecordCreationTimestamp bool } // nolint @@ -226,6 +227,7 @@ func (c *AttestCommand) Exec(ctx context.Context, imageRef string) error { signOpts := []mutate.SignOption{ mutate.WithDupeDetector(dd), + mutate.WithRecordCreationTimestamp(c.RecordCreationTimestamp), } if c.Replace { diff --git a/cmd/cosign/cli/options/attest.go b/cmd/cosign/cli/options/attest.go index 9090ce1d9c6e..8139cddaefab 100644 --- a/cmd/cosign/cli/options/attest.go +++ b/cmd/cosign/cli/options/attest.go @@ -21,16 +21,17 @@ import ( // AttestOptions is the top level wrapper for the attest command. type AttestOptions struct { - Key string - Cert string - CertChain string - NoUpload bool - Recursive bool - Replace bool - SkipConfirmation bool - TlogUpload bool - TSAServerURL string - RekorEntryType string + Key string + Cert string + CertChain string + NoUpload bool + Recursive bool + Replace bool + SkipConfirmation bool + TlogUpload bool + TSAServerURL string + RekorEntryType string + RecordCreationTimestamp bool Rekor RekorOptions Fulcio FulcioOptions @@ -86,4 +87,7 @@ func (o *AttestOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().StringVar(&o.TSAServerURL, "timestamp-server-url", "", "url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr") + + cmd.Flags().BoolVar(&o.RecordCreationTimestamp, "record-creation-timestamp", false, + "set the createdAt timestamp in the attestation artifact to the time it was created; by default, cosign sets this to the zero value") } diff --git a/doc/cosign_attest.md b/doc/cosign_attest.md index ccd9bd8043f6..02ded8881d5d 100644 --- a/doc/cosign_attest.md +++ b/doc/cosign_attest.md @@ -37,6 +37,9 @@ cosign attest [flags] # supply attestation via stdin echo | cosign attest --predicate - + + # attach an attestation to a container image and honor the creation timestamp of the signature + cosign attest --predicate --type --key cosign.key --record-creation-timestamp ``` ### Options @@ -62,6 +65,7 @@ cosign attest [flags] --oidc-provider string Specify the provider to get the OIDC token from (Optional). If unset, all options will be tried. Options include: [spiffe, google, github-actions, filesystem, buildkite-agent] --oidc-redirect-url string OIDC redirect URL (Optional). The default oidc-redirect-url is 'http://localhost:0/auth/callback'. --predicate string path to the predicate file. + --record-creation-timestamp set the createdAt timestamp in the attestation artifact to the time it was created; by default, cosign sets this to the zero value -r, --recursive if a multi-arch image is specified, additionally sign each discrete image --registry-password string registry basic auth password --registry-token string registry bearer auth token