diff --git a/IMPORT.md b/IMPORT.md index 91f54a61390..982b1a6c8be 100644 --- a/IMPORT.md +++ b/IMPORT.md @@ -13,5 +13,5 @@ Public key written to import-cosign.pub ### Sign a container with imported keypair ```shell -$ cosign sign --key import-cosign.key dlorenc/demo +$ cosign sign --key import-cosign.key $IMAGE_DIGEST ``` diff --git a/KEYLESS.md b/KEYLESS.md index a33c2f1beed..e2413f95786 100644 --- a/KEYLESS.md +++ b/KEYLESS.md @@ -8,12 +8,19 @@ Try it out! This signature mode relies on the Sigstore Public Good Instance, which is rapidly heading toward a GA release! We don't have a date yet, but follow along on the [GitHub project](https://github.com/orgs/sigstore/projects/5). +The following examples use this image: + +```shell +$ IMAGE=gcr.io/dlorenc-vmtest2/demo +$ IMAGE_DIGEST=$IMAGE@sha256:97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36 +``` + ## Usage Keyless signing: ```shell -$ COSIGN_EXPERIMENTAL=1 cosign sign gcr.io/dlorenc-vmtest2/demo +$ COSIGN_EXPERIMENTAL=1 cosign sign $IMAGE_DIGEST Generating ephemeral keys... Retrieving signed certificate... Your browser will now be opened to: @@ -24,7 +31,7 @@ Pushing signature to: gcr.io/dlorenc-vmtest2/demo:sha256-97fc222cee7991b5b061d4d Keyless verifying: ```shell -$ COSIGN_EXPERIMENTAL=1 cosign verify gcr.io/dlorenc-vmtest2/demo +$ COSIGN_EXPERIMENTAL=1 cosign verify $IMAGE The following checks were performed on all of these signatures: - The cosign claims were validated - The claims were present in the transparency log @@ -73,21 +80,18 @@ and producing an identity token. Currently this supports Google and GitHub. From a GCE VM, you can use the VM's service account identity to sign an image: ```shell -$ cosign sign --identity-token=$( - gcloud auth print-identity-token \ - --audiences=sigstore) \ - gcr.io/dlorenc-vmtest2/demo +$ IDENTITY_TOKEN=$(gcloud auth print-identity-token --audiences=sigstore) +$ cosign sign --identity-token=$IDENTITY_TOKEN $IMAGE_DIGEST ``` From outside a GCE VM, you can impersonate a GCP IAM service account to sign an image: ```shell -$ cosign sign --identity-token=$( - gcloud auth print-identity-token \ +$ IDENTITY_TOKEN=$(gcloud auth print-identity-token \ --audiences=sigstore \ --include-email \ - --impersonate-service-account my-sa@my-project.iam.gserviceaccount.com) \ - gcr.io/dlorenc-vmtest2/demo + --impersonate-service-account my-sa@my-project.iam.gserviceaccount.com) +$ cosign sign --identity-token=$IDENTITY_TOKEN $IMAGE_DIGEST ``` In order to impersonate an IAM service account, your account must have the @@ -138,7 +142,7 @@ To use this instance, follow the steps below: 1. `gsutil cp -r gs://tuf-root-staging/root.json .` 1. `cd tuf-root-staging` 1. `cosign initialize --mirror=tuf-root-staging --root=root.json` -1. `COSIGN_EXPERIMENTAL=1 cosign sign --oidc-issuer "https://oauth2.sigstage.dev/auth" --fulcio-url "https://fulcio.sigstage.dev" --rekor-url "https://rekor.sigstage.dev" ${IMAGE}` +1. `COSIGN_EXPERIMENTAL=1 cosign sign --oidc-issuer "https://oauth2.sigstage.dev/auth" --fulcio-url "https://fulcio.sigstage.dev" --rekor-url "https://rekor.sigstage.dev" ${IMAGE_DIGEST}` 1. `COSIGN_EXPERIMENTAL=1 cosign verify --rekor-url "https://rekor.sigstage.dev" ${IMAGE}` * Steps 1-4 configures your local environment to use the staging keys and certificates. @@ -157,10 +161,10 @@ We need to clear the local TUF root data and re-initialize with the default prod If you're running your own sigstore services flags are available to set your own endpoint's, e.g ``` - COSIGN_EXPERIMENTAL=1 go run cmd/cosign/main.go sign -oidc-issuer "https://oauth2.example.com/auth" \ + COSIGN_EXPERIMENTAL=1 cosign sign -oidc-issuer "https://oauth2.example.com/auth" \ -fulcio-url "https://fulcio.example.com" \ -rekor-url "https://rekor.example.com" \ - ghcr.io/jdoe/somerepo/testcosign + $IMAGE_DIGEST ``` diff --git a/KMS.md b/KMS.md index 97f42f32879..a046d90608d 100644 --- a/KMS.md +++ b/KMS.md @@ -33,13 +33,20 @@ jnVtSyKZxNzBfNMLLtVxdu8q+AigrGCS2KPmejda9bICTcHQCRUrD5OLGQ== ### Signing and Verification +For the following examples, we have: + +```shell +$ IMAGE=gcr.io/dlorenc-vmtest2/demo +$ IMAGE_DIGEST=$IMAGE@sha256:410a07f17151ffffb513f942a01748dfdb921de915ea6427d61d60b0357c1dcd +``` + To sign and verify using a key managed by a KMS provider, you can pass a provider-specific URI to the `--key` command: ```shell -$ cosign sign --key :// gcr.io/dlorenc-vmtest2/demo +$ cosign sign --key :// $IMAGE_DIGEST Pushing signature to: gcr.io/dlorenc-vmtest2/demo:sha256-410a07f17151ffffb513f942a01748dfdb921de915ea6427d61d60b0357c1dcd.cosign -$ cosign verify --key :// gcr.io/dlorenc-vmtest2/demo +$ cosign verify --key :// $IMAGE Verification for gcr.io/dlorenc-vmtest2/demo -- The following checks were performed on each of these signatures: @@ -54,7 +61,7 @@ You can also export the public key and verify against that file: ```shell $ cosign public-key --key :// > kms.pub -$ cosign verify --key kms.pub gcr.io/dlorenc-vmtest2/demo +$ cosign verify --key kms.pub $IMAGE ``` ### Providers @@ -104,8 +111,8 @@ $ export AWS_CMK_ID=$(aws kms create-key --customer-master-key-spec RSA_4096 \ --description "Cosign Signature Key Pair" \ --query KeyMetadata.KeyId --output text) -$ cosign sign --key awskms:///${AWS_CMK_ID} docker.io/davivcgarcia/hello-world:latest -$ cosign verify --key awskms:///${AWS_CMK_ID} docker.io/davivcgarcia/hello-world:latest | jq . +$ cosign sign --key awskms:///${AWS_CMK_ID} $IMAGE_DIGEST +$ cosign verify --key awskms:///${AWS_CMK_ID} $IMAGE | jq . ``` ### GCP @@ -140,7 +147,7 @@ The following environment variables must be set to let cosign authenticate to Az To create a key using `cosign generate-key-pair --kms azurekms://[VAULT_NAME][VAULT_URI]/[KEY]` you will need a user which has permissions to create keys in Key Vault. For example `Key Vault Crypto Officer` role. -To sign images using `cosign sign --key azurekms://[VAULT_NAME][VAULT_URI]/[KEY] [IMAGE]` you will need a user which has permissions to the sign action such as the `Key Vault Crypto User` role. +To sign images using `cosign sign --key azurekms://[VAULT_NAME][VAULT_URI]/[KEY] [IMAGE DIGEST]` you will need a user which has permissions to the sign action such as the `Key Vault Crypto User` role. ### Hashicorp Vault diff --git a/PKCS11.md b/PKCS11.md index 076c157e6bf..35c900452a7 100644 --- a/PKCS11.md +++ b/PKCS11.md @@ -3,6 +3,13 @@ The `cosign` command line tool optionally supports PKCS11 tokens for signing. This support is enabled through the [crypto11](https://github.com/ThalesIgnite/crypto11) and the [pkcs11](https://github.com/miekg/pkcs11) libraries, which are not included in the standard release. Use [`make cosign-pivkey-pkcs11key`](https://github.com/sigstore/cosign/blob/a8d1cc1132d4a019a62ff515b9375c8c5b98a5c5/Makefile#L52), or `go build -tags=pkcs11key`, to build `cosign` with support for PKCS11 tokens. +For the following examples, we have: + +```shell +$ IMAGE=gcr.io/dlorenc-vmtest2/demo +$ IMAGE_DIGEST=$IMAGE@sha256:410a07f17151ffffb513f942a01748dfdb921de915ea6427d61d60b0357c1dcd +``` + ## Quick Start ### Setup @@ -55,14 +62,14 @@ If `pin-value` is not present in the URI, `cosign` expects the PIN to be set usi You can then use the normal `cosign` commands to sign images and blobs with your PKCS11 key. ```shell -$ cosign sign --key "" gcr.io/dlorenc-vmtest2/demo +$ cosign sign --key "" $IMAGE_DIGEST Pushing signature to: gcr.io/dlorenc-vmtest2/demo:sha256-410a07f17151ffffb513f942a01748dfdb921de915ea6427d61d60b0357c1dcd.sig ``` To verify, you can either use the PKCS11 token key directly: ```shell -$ cosign verify --key "" gcr.io/dlorenc-vmtest2/demo +$ cosign verify --key "" $IMAGE Verification for gcr.io/dlorenc-vmtest2/demo -- The following checks were performed on each of these signatures: - The cosign claims were validated @@ -77,7 +84,7 @@ Or export the public key and verify against that: ```shell $ cosign public-key --key "" > pub.key -$ cosign verify --key pub.key gcr.io/dlorenc-vmtest2/demo +$ cosign verify --key pub.key $IMAGE_DIGEST Verification for gcr.io/dlorenc-vmtest2/demo -- The following checks were performed on each of these signatures: - The cosign claims were validated diff --git a/README.md b/README.md index 96b44a86541..803740d7cd8 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,16 @@ NOTE: you will need access to a container registry for cosign to work with. [ttl.sh](https://ttl.sh) offers free, short-lived (ie: hours), anonymous container image hosting if you just want to try these commands out. +For instance: + +```shell +$ SRC_IMAGE=busybox +$ SRC_DIGEST=$(crane digest busybox) +$ IMAGE_URI=ttl.sh/$(uuidgen | head -c 8):1h +$ crane cp $SRC_IMAGE@$SRC_DIGEST $IMAGE_URI:1h +$ IMAGE_URI_DIGEST=$IMAGE_URI@$SRC_DIGEST +``` + ### Generate a keypair ```shell @@ -84,8 +94,12 @@ Public key written to cosign.pub ### Sign a container and store the signature in the registry +Note that you should always sign images based on their digest (`@sha256:...`) +rather than a tag (`:latest`) because otherwise you might sign something you +didn't intend to! + ```shell -$ cosign sign --key cosign.key dlorenc/demo +$ cosign sign --key cosign.key $IMAGE_URI_DIGEST Enter password for private key: Pushing signature to: index.docker.io/dlorenc/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8.sig ``` @@ -105,7 +119,7 @@ Note that these signed payloads include the digest of the container image, which sure these "detached" signatures cover the correct image. ```shell -$ cosign verify --key cosign.pub dlorenc/demo +$ cosign verify --key cosign.pub $IMAGE_URI The following checks were performed on these signatures: - The cosign claims were validated - The signatures were verified against the specified public key @@ -169,33 +183,40 @@ You can publish an artifact with `cosign upload blob`: ```shell $ echo "my first artifact" > artifact -$ cosign upload blob -f artifact gcr.io/dlorenc-vmtest2/artifact -Uploading file from [artifact] to [gcr.io/dlorenc-vmtest2/artifact:latest] with media type [text/plain; charset=utf-8] -File is available directly at [us.gcr.io/v2/dlorenc-vmtest2/readme/blobs/sha256:b57400c0ad852a7c2f6f7da4a1f94547692c61f3e921a49ba3a41805ae8e1e99] -us.gcr.io/dlorenc-vmtest2/readme@sha256:4aa3054270f7a70b4528f2064ee90961788e1e1518703592ae4463de3b889dec +$ BLOB_SUM=$(shasum -a 256 artifact | cut -d' ' -f 1) +c69d72c98b55258f9026f984e4656f0e9fd3ef024ea3fac1d7e5c7e6249f1626 artifact +$ BLOB_NAME=my-artifact-$(uuidgen | head -c 8) +$ BLOB_URI=ttl.sh/$BLOB_NAME:1h +$ BLOB_URI_DIGEST=$(cosign upload blob -f artifact $BLOB_URI) +Uploading file from [artifact] to [ttl.sh/my-artifact-f42c22e0:5m] with media type [text/plain] +File [artifact] is available directly at [ttl.sh/v2/my-artifact-f42c22e0/blobs/sha256:c69d72c98b55258f9026f984e4656f0e9fd3ef024ea3fac1d7e5c7e6249f1626] +Uploaded image to: +ttl.sh/my-artifact-f42c22e0@sha256:790d47850411e902aabebc3a684eeb78fcae853d4dd6e1cc554d70db7f05f99f ``` Your users can download it from the "direct" url with standard tools like curl or wget: ```shell -$ curl -L gcr.io/v2/dlorenc-vmtest2/artifact/blobs/sha256:97f16c28f6478f3c02d7fff4c7f3c2a30041b72eb6852ca85b919fd85534ed4b > artifact +$ curl -L ttl.sh/v2/$BLOB_NAME/blobs/sha256:$BLOB_SUM > artifact-fetched ``` The digest is baked right into the URL, so they can check that as well: ```shell -$ curl -L gcr.io/v2/dlorenc-vmtest2/artifact/blobs/sha256:97f16c28f6478f3c02d7fff4c7f3c2a30041b72eb6852ca85b919fd85534ed4b | shasum -a 256 -97f16c28f6478f3c02d7fff4c7f3c2a30041b72eb6852ca85b919fd85534ed4b - +$ cat artifact-fetched | shasum -a 256 +c69d72c98b55258f9026f984e4656f0e9fd3ef024ea3fac1d7e5c7e6249f1626 - ``` You can sign it with the normal `cosign sign` command and flags: ```shell -$ cosign sign --key cosign.key gcr.io/dlorenc-vmtest2/artifact +$ cosign sign --key cosign.key $BLOB_URI_DIGEST Enter password for private key: -Pushing signature to: gcr.io/dlorenc-vmtest2/artifact:sha256-3f612a4520b2c245d620d0cca029f1173f6bea76819dde8543f5b799ea3c696c.sig +Pushing signature to: ttl.sh/my-artifact-f42c22e0 ``` +As usual, make sure to reference any images you sign by their digest to make sure you don't sign the wrong thing! + #### sget We also include the `sget` command for safer, automatic verification of signatures and integration with our binary transparency log, Rekor. @@ -249,7 +270,7 @@ Creating Tekton Bundle: - Added TaskRun: to image Pushed Tekton Bundle to us.gcr.io/dlorenc-vmtest2/pipeline@sha256:124e1fdee94fe5c5f902bc94da2d6e2fea243934c74e76c2368acdc8d3ac7155 -$ cosign sign --key cosign.key us.gcr.io/dlorenc-vmtest2/pipeline:latest +$ cosign sign --key cosign.key us.gcr.io/dlorenc-vmtest2/pipeline@sha256:124e1fdee94fe5c5f902bc94da2d6e2fea243934c74e76c2368acdc8d3ac7155 Enter password for private key: tlog entry created with index: 5086 Pushing signature to: us.gcr.io/dlorenc-vmtest2/demo:sha256-124e1fdee94fe5c5f902bc94da2d6e2fea243934c74e76c2368acdc8d3ac7155.sig @@ -263,7 +284,7 @@ Cosign can upload these using the `cosign wasm upload` command: ```shell $ cosign upload wasm -f hello.wasm us.gcr.io/dlorenc-vmtest2/wasm -$ cosign sign --key cosign.key us.gcr.io/dlorenc-vmtest2/wasm +$ cosign sign --key cosign.key us.gcr.io/dlorenc-vmtest2/wasm@sha256:9e7a511fb3130ee4641baf1adc0400bed674d4afc3f1b81bb581c3c8f613f812 Enter password for private key: tlog entry created with index: 5198 Pushing signature to: us.gcr.io/dlorenc-vmtest2/wasm:sha256-9e7a511fb3130ee4641baf1adc0400bed674d4afc3f1b81bb581c3c8f613f812.sig @@ -279,11 +300,10 @@ Cosign can then sign these images as they can any other OCI image. ```shell $ bee build ./examples/tcpconnect/tcpconnect.c localhost:5000/tcpconnect:test $ bee push localhost:5000/tcpconnect:test -$ cosign sign --key cosign.key localhost:5000/tcpconnect:test +$ cosign sign --key cosign.key localhost:5000/tcpconnect@sha256:7a91c50d922925f152fec96ed1d84b7bc6b2079c169d68826f6cf307f22d40e6 Enter password for private key: Pushing signature to: localhost:5000/tcpconnect $ cosign verify --key cosign.pub localhost:5000/tcpconnect:test -cosign verify --key pubkey.pem localhost:5001/tcpconnect:test Verification for localhost:5000/tcpconnect:test -- The following checks were performed on each of these signatures: @@ -302,7 +322,7 @@ The specification for these is defined [here](https://github.com/in-toto/attesta You can create and sign one from a local predicate file using the following commands: ```shell -$ cosign attest --predicate --key cosign.key +$ cosign attest --predicate --key cosign.key $IMAGE_URI_DIGEST ``` All of the standard key management systems are supported. @@ -311,7 +331,7 @@ Payloads are signed using the DSSE signing spec, defined [here](https://github.c To verify: ```shell -$ cosign verify-attestation --key cosign.pub +$ cosign verify-attestation --key cosign.pub $IMAGE_URI ``` ## Detailed Usage @@ -353,7 +373,7 @@ Today, `cosign` has been tested and works against the following registries: We aim for wide registry support. To `sign` images in registries which do not yet fully support [OCI media types](https://github.com/sigstore/cosign/blob/main/SPEC.md#object-types), one may need to use `COSIGN_DOCKER_MEDIA_TYPES` to fall back to legacy equivalents. For example: ```shell -COSIGN_DOCKER_MEDIA_TYPES=1 cosign sign --key cosign.key legacy-registry.example.com/my/image +COSIGN_DOCKER_MEDIA_TYPES=1 cosign sign --key cosign.key legacy-registry.example.com/my/image@$DIGEST ``` Please help test and file bugs if you see issues! @@ -366,8 +386,8 @@ To publish signed artifacts to a Rekor transparency log and verify their existen set the `COSIGN_EXPERIMENTAL=1` environment variable. ```shell -$ COSIGN_EXPERIMENTAL=1 cosign sign --key cosign.key dlorenc/demo -$ COSIGN_EXPERIMENTAL=1 cosign verify --key cosign.pub dlorenc/demo +$ COSIGN_EXPERIMENTAL=1 cosign sign --key cosign.key $IMAGE_URI_DIGEST +$ COSIGN_EXPERIMENTAL=1 cosign verify --key cosign.pub $IMAGE_URI ``` `cosign` defaults to using the public instance of rekor at [rekor.sigstore.dev](https://rekor.sigstore.dev). @@ -418,7 +438,7 @@ That looks like: } ``` -**Note:** This can be generated for an image reference using `cosign generate `. +**Note:** This can be generated for an image reference using `cosign generate $IMAGE_URI_DIGEST`. I'm happy to switch this format to something else if it makes sense. See https://github.com/notaryproject/nv2/issues/40 for one option. @@ -445,7 +465,7 @@ This will replace the repo in the provided image like this: ```shell $ export COSIGN_REPOSITORY=gcr.io/my-new-repo -$ gcr.io/dlorenc-vmtest2/demo -> gcr.io/my-new-repo/demo:sha256-DIGEST.sig +$ cosign sign --key cosign.key $IMAGE_URI_DIGEST ``` So the signature for `gcr.io/dlorenc-vmtest2/demo` will be stored in `gcr.io/my-new-repo/demo:sha256-DIGEST.sig`. @@ -460,8 +480,8 @@ Note: different registries might expect different formats for the "repository." repository. For example, ```shell - COSIGN_REPOSITORY=us-docker.pkg.dev/my-new-repo/demo - gcr.io/dlorenc-vmtest2/demo --> us-docker.pkg.dev/my-new-repo/demo:sha256-DIGEST.sig + $ export COSIGN_REPOSITORY=us-docker.pkg.dev/my-new-repo/demo + $ cosign sign --key cosign.key $IMAGE_URI_DIGEST ``` where the `sha256-DIGEST` will match the digest for @@ -633,19 +653,22 @@ If you would like to attest that a specific tag (or set of tags) should point at run something like: ```shell +$ docker push $IMAGE_URI +The push refers to repository [dlorenc/demo] +994393dc58e7: Pushed +5m: digest: sha256:1304f174557314a7ed9eddb4eab12fed12cb0cd9809e4c28f29af86979a3c870 size: 528 $ TAG=sign-me -$ DGST=$(crane digest dlorenc/demo:$TAG) -$ cosign sign --key cosign.key -a tag=$TAG dlorenc/demo@$DGST +$ cosign sign --key cosign.key -a tag=$TAG $IMAGE_URI_DIGEST Enter password for private key: -Pushing signature to: dlorenc/demo:sha256-97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36.sig +Pushing signature to: dlorenc/demo:1304f174557314a7ed9eddb4eab12fed12cb0cd9809e4c28f29af86979a3c870.sig ``` Then you can verify that the tag->digest mapping is also covered in the signature, using the `-a` flag to `cosign verify`. -This example verifies that the digest `$TAG` points to (`sha256:97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36`) -has been signed, **and also** that the `$TAG`: +This example verifies that the digest `$TAG` which points to (`sha256:1304f174557314a7ed9eddb4eab12fed12cb0cd9809e4c28f29af86979a3c870`) +has been signed, **and also** that the `tag` annotation has the value `sign-me`: ```shell -$ cosign verify --key cosign.pub -a tag=$TAG dlorenc/demo:$TAG | jq . +$ cosign verify --key cosign.pub -a tag=$TAG $IMAGE_URI | jq . { "Critical": { "Identity": { @@ -729,7 +752,7 @@ it to act as an attestation to the **signature(s) themselves**. Before we sign the signature artifact, we first give it a memorable name so we can find it later. ```shell -$ cosign sign --key cosign.key -a sig=original dlorenc/demo +$ cosign sign --key cosign.key -a sig=original $IMAGE_URI_DIGEST Enter password for private key: Pushing signature to: dlorenc/demo:sha256-97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36.sig $ cosign verify --key cosign.pub dlorenc/demo | jq . @@ -749,10 +772,12 @@ $ cosign verify --key cosign.pub dlorenc/demo | jq . } ``` + + Now give that signature a memorable name, then sign that: ```shell -$ crane tag $(cosign triangulate dlorenc/demo) mysignature +$ crane tag $(cosign triangulate $IMAGE_URI) mysignature 2021/02/15 20:22:55 dlorenc/demo:mysignature: digest: sha256:71f70e5d29bde87f988740665257c35b1c6f52dafa20fab4ba16b3b1f4c6ba0e size: 556 $ cosign sign --key cosign.key -a sig=counter dlorenc/demo:mysignature Enter password for private key: diff --git a/TOKENS.md b/TOKENS.md index 6ab13e255a0..54662aed290 100644 --- a/TOKENS.md +++ b/TOKENS.md @@ -14,6 +14,13 @@ See [`go-piv`'s installation instructions for your platform.](https://github.com We recommend using an application provided by your hardware vendor to manage keys and permissions for advanced use-cases, but `cosign piv-tool` should work well for most users. +The following exmamples use this image: + +```shell +$ IMAGE=gcr.io/dlorenc-vmtest2/demo +$ IMAGE_DIGEST=$IMAGE@sha256:410a07f17151ffffb513f942a01748dfdb921de915ea6427d61d60b0357c1dcd +``` + ## Quick Start ### Setup @@ -91,7 +98,7 @@ You can then use the normal `cosign` commands to sign images and blobs with your **NOTE**: The default PIN is `123456`. ```shell -$ cosign sign --sk gcr.io/dlorenc-vmtest2/demo +$ cosign sign --sk $IMAGE_DIGEST Enter PIN for security key: Please tap security key... Pushing signature to: gcr.io/dlorenc-vmtest2/demo:sha256-410a07f17151ffffb513f942a01748dfdb921de915ea6427d61d60b0357c1dcd.sig @@ -100,7 +107,7 @@ Pushing signature to: gcr.io/dlorenc-vmtest2/demo:sha256-410a07f17151ffffb513f94 To verify, you can either use the hardware key directly: ```shell -$ cosign verify --sk gcr.io/dlorenc-vmtest2/demo +$ cosign verify --sk $IMAGE_DIGEST Verification for gcr.io/dlorenc-vmtest2/demo -- The following checks were performed on each of these signatures: @@ -116,7 +123,7 @@ Or export the public key and verify against that: ```shell $ cosign public-key --sk > pub.key -$ cosign verify --key pub.key gcr.io/dlorenc-vmtest2/demo +$ cosign verify --key pub.key $IMAGE Verification for gcr.io/dlorenc-vmtest2/demo -- The following checks were performed on each of these signatures: diff --git a/USAGE.md b/USAGE.md index 26e5c858905..a13607f72f1 100644 --- a/USAGE.md +++ b/USAGE.md @@ -1,15 +1,24 @@ # Detailed Usage +Use the following image references in the below. + +```shell +$ IMAGE=dlorenc/demo +$ IMAGE_DIGEST=$IMAGE@sha256:87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8 +``` + +For signing, we require digests to prevent race conditions, so be sure to use `$IMAGE_DIGEST`. + ## Sign a container multiple times Multiple signatures can be "attached" to a single container image: ```shell -$ cosign sign --key cosign.key dlorenc/demo +$ cosign sign --key cosign.key $IMAGE_DIGEST Enter password for private key: Pushing signature to: index.docker.io/dlorenc/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8.sig -$ cosign sign --key other.key dlorenc/demo +$ cosign sign --key other.key $IMAGE_DIGEST Enter password for private key: Pushing signature to: index.docker.io/dlorenc/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8.sig ``` @@ -20,9 +29,9 @@ The `-a` flag can be used to add annotations to the generated, signed payload. This flag can be repeated: ```shell -$ cosign sign --key other.key -a foo=bar dlorenc/demo +$ cosign sign --key other.key -a foo=bar $IMAGE_DIGEST Enter password for private key: -Pushing signature to: index.docker.io/dlorenc/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8.sig +Pushing signature to: index.docker.io/dlorenc/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8 ``` These values are included in the signed payload under the `Optional` section. @@ -39,7 +48,7 @@ they can be verified with the `-a` flag to `cosign verify`. The payload must be specified as a path to a file: ```shell -$ cosign sign --key cosign.key --payload README.md dlorenc/demo +$ cosign sign --key cosign.key --payload README.md $IMAGE_DIGEST Using payload from: README.md Enter password for private key: Pushing signature to: index.docker.io/dlorenc/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8.sig @@ -51,14 +60,14 @@ Signatures are uploaded to an OCI artifact stored with a predictable name. This name can be located with the `cosign triangulate` command: ```shell -cosign triangulate dlorenc/demo +cosign triangulate $IMAGE index.docker.io/dlorenc/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8.sig ``` They can be viewed with `crane`: ```shell -crane manifest $(cosign triangulate gcr.io/dlorenc-vmtest2/demo) | jq . +crane manifest $(cosign triangulate $IMAGE) | jq . { "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", @@ -91,7 +100,7 @@ crane manifest $(cosign triangulate gcr.io/dlorenc-vmtest2/demo) | jq . Some registries support deletion too (DockerHub does not): ```shell -$ cosign clean gcr.io/dlorenc-vmtest2/demo +$ cosign clean $IMAGE ``` ## Sign but skip upload (to store somewhere else) @@ -100,7 +109,7 @@ The base64 encoded signature is printed to stdout. This can be stored somewhere else. ```shell -$ cosign sign --key key.pem --upload=false dlorenc/demo +$ cosign sign --key key.pem --upload=false $IMAGE_DIGEST Qr883oPOj0dj82PZ0d9mQ2lrdM0lbyLSXUkjt6ejrxtHxwe7bU6Gr27Sysgk1jagf1htO/gvkkg71oJiwWryCQ== ``` @@ -109,14 +118,14 @@ Qr883oPOj0dj82PZ0d9mQ2lrdM0lbyLSXUkjt6ejrxtHxwe7bU6Gr27Sysgk1jagf1htO/gvkkg71oJi The json payload is printed to stdout: ```shell -$ cosign generate dlorenc/demo +$ cosign generate $IMAGE_DIGEST {"Critical":{"Identity":{"docker-reference":""},"Image":{"Docker-manifest-digest":"87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8"},"Type":"cosign container image signature"},"Optional":null} ``` This can be piped directly into openssl: ```shell -$ cosign generate dlorenc/demo | openssl... +$ cosign generate $IMAGE_DIGEST | openssl... ``` ## Upload a generated signature @@ -125,21 +134,21 @@ The signature is passed via the `--signature` flag. It can be a file: ```shell -$ cosign attach signature --signature file.sig dlorenc/demo +$ cosign attach signature --signature file.sig $IMAGE_DIGEST Pushing signature to: dlorenc/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8.sig ``` the base64-encoded signature: ```shell -$ cosign attach signature --signature Qr883oPOj0dj82PZ0d9mQ2lrdM0lbyLSXUkjt6ejrxtHxwe7bU6Gr27Sysgk1jagf1htO/gvkkg71oJiwWryCQ== dlorenc/demo +$ cosign attach signature --signature Qr883oPOj0dj82PZ0d9mQ2lrdM0lbyLSXUkjt6ejrxtHxwe7bU6Gr27Sysgk1jagf1htO/gvkkg71oJiwWryCQ== $IMAGE_DIGEST Pushing signature to: dlorenc/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def.sig ``` or, `-` for stdin for chaining from other commands: ```shell -$ cosign generate dlorenc/demo | openssl... | cosign attach signature --signature -- dlorenc/demo +$ cosign generate $IMAGE_DIGEST | openssl... | cosign attach signature --signature - $IMAGE_DIGEST Pushing signature to: dlorenc/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def.sig ``` @@ -153,7 +162,7 @@ By default, `cosign` validates that this digest matches the container during `co If you are using other payload formats with `cosign`, you can use the `--check-claims=false` flag: ```shell -$ cosign verify --check-claims=false --key cosign.pub dlorenc/demo +$ cosign verify --check-claims=false --key cosign.pub $IMAGE Warning: the following claims have not been verified: {"Critical":{"Identity":{"docker-reference":""},"Image":{"Docker-manifest-digest":"87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8"},"Type":"cosign container image signature"},"Optional":null} ``` @@ -164,7 +173,7 @@ verify any claims in the payload. Annotations made in the original signature (`cosign sign -a foo=bar`) are present under the `Optional` section of the payload: ```shell -$ cosign verify --key cosign.pub dlorenc/demo | jq . +$ cosign verify --key cosign.pub $IMAGE | jq . { "Critical": { "Identity": { @@ -187,15 +196,15 @@ The payload may contain other key-value pairs. ```shell # This works -$ cosign verify -a --key cosign.pub dlorenc/demo +$ cosign verify -a --key cosign.pub $IMAGE {"Critical":{"Identity":{"docker-reference":""},"Image":{"Docker-manifest-digest":"97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36"},"Type":"cosign container image signature"},"Optional":{"sig":"original"}} # This works too -$ cosign verify -a sig=original --key cosign.pub dlorenc/demo +$ cosign verify -a sig=original --key cosign.pub $IMAGE {"Critical":{"Identity":{"docker-reference":""},"Image":{"Docker-manifest-digest":"97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36"},"Type":"cosign container image signature"},"Optional":{"sig":"original"}} # This doesn't work -$ cosign verify -a sig=original -a=foo=bar --key cosign.pub dlorenc/demo +$ cosign verify -a sig=original -a=foo=bar --key cosign.pub $IMAGE error: no matching claims: invalid or missing annotation in claim: map[sig:original] ``` @@ -205,7 +214,7 @@ invalid or missing annotation in claim: map[sig:original] Each signature is printed to stdout in a json format: ``` -$ cosign download signature us-central1-docker.pkg.dev/dlorenc-vmtest2/test/taskrun +$ cosign download signature $IMAGE {"Base64Signature":"Ejy6ipGJjUzMDoQFePWixqPBYF0iSnIvpMWps3mlcYNSEcRRZelL7GzimKXaMjxfhy5bshNGvDT5QoUJ0tqUAg==","Payload":"eyJDcml0aWNhbCI6eyJJZGVudGl0eSI6eyJkb2NrZXItcmVmZXJlbmNlIjoiIn0sIkltYWdlIjp7IkRvY2tlci1tYW5pZmVzdC1kaWdlc3QiOiI4N2VmNjBmNTU4YmFkNzliZWVhNjQyNWEzYjI4OTg5ZjAxZGQ0MTcxNjQxNTBhYjNiYWFiOThkY2JmMDRkZWY4In0sIlR5cGUiOiIifSwiT3B0aW9uYWwiOm51bGx9"} ``` diff --git a/cmd/cosign/cli/sign.go b/cmd/cosign/cli/sign.go index c5ebcd1683b..07ce0b3de27 100644 --- a/cmd/cosign/cli/sign.go +++ b/cmd/cosign/cli/sign.go @@ -34,49 +34,50 @@ func Sign() *cobra.Command { Short: "Sign the supplied container image.", Long: `Sign the supplied container image. -Images should be specified by digest (example.com/image@sha256:abcdef...) rather -than tag (example.com/image:latest). +Make sure to sign the image by its digest (@sha256:...) rather than by tag +(:latest) so that you actually sign what you think you're signing! This prevents +race conditions or (worse) malicious tampering. `, - Example: ` cosign sign --key | [--payload ] [-a key=value] [--upload=true|false] [-f] [-r] + Example: ` cosign sign --key | [--payload ] [-a key=value] [--upload=true|false] [-f] [-r] # sign a container image with Google sign-in (experimental) - COSIGN_EXPERIMENTAL=1 cosign sign + COSIGN_EXPERIMENTAL=1 cosign sign # sign a container image with a local key pair file - cosign sign --key cosign.key + cosign sign --key cosign.key # sign a multi-arch container image AND all referenced, discrete images - cosign sign --key cosign.key --recursive + cosign sign --key cosign.key --recursive # sign a container image and add annotations - cosign sign --key cosign.key -a key1=value1 -a key2=value2 + cosign sign --key cosign.key -a key1=value1 -a key2=value2 # sign a container image with a key stored in an environment variable - cosign sign --key env://[ENV_VAR] + cosign sign --key env://[ENV_VAR] # sign a container image with a key pair stored in Azure Key Vault - cosign sign --key azurekms://[VAULT_NAME][VAULT_URI]/[KEY] + cosign sign --key azurekms://[VAULT_NAME][VAULT_URI]/[KEY] # sign a container image with a key pair stored in AWS KMS - cosign sign --key awskms://[ENDPOINT]/[ID/ALIAS/ARN] + cosign sign --key awskms://[ENDPOINT]/[ID/ALIAS/ARN] # sign a container image with a key pair stored in Google Cloud KMS - cosign sign --key gcpkms://projects/[PROJECT]/locations/global/keyRings/[KEYRING]/cryptoKeys/[KEY]/versions/[VERSION] + cosign sign --key gcpkms://projects/[PROJECT]/locations/global/keyRings/[KEYRING]/cryptoKeys/[KEY]/versions/[VERSION] # sign a container image with a key pair stored in Hashicorp Vault - cosign sign --key hashivault://[KEY] + cosign sign --key hashivault://[KEY] # sign a container image with a key pair stored in a Kubernetes secret - cosign sign --key k8s://[NAMESPACE]/[KEY] + cosign sign --key k8s://[NAMESPACE]/[KEY] # sign a container image with a key, attaching a certificate and certificate chain - cosign sign --key cosign.key --cert cosign.crt --cert-chain chain.crt + cosign sign --key cosign.key --cert cosign.crt --cert-chain chain.crt # sign a container in a registry which does not fully support OCI media types - COSIGN_DOCKER_MEDIA_TYPES=1 cosign sign --key cosign.key legacy-registry.example.com/my/image + COSIGN_DOCKER_MEDIA_TYPES=1 cosign sign --key cosign.key legacy-registry.example.com/my/image@ # sign a container image and not upload transparency log - cosign sign --key cosign.key --no-tlog-upload=true `, + cosign sign --key cosign.key --no-tlog-upload=true `, Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { diff --git a/doc/cosign_sign.md b/doc/cosign_sign.md index 6ee24a90e10..caa4105526a 100644 --- a/doc/cosign_sign.md +++ b/doc/cosign_sign.md @@ -6,8 +6,9 @@ Sign the supplied container image. Sign the supplied container image. -Images should be specified by digest (example.com/image@sha256:abcdef...) rather -than tag (example.com/image:latest). +Make sure to sign the image by its digest (@sha256:...) rather than by tag +(:latest) so that you actually sign what you think you're signing! This prevents +race conditions or (worse) malicious tampering. ``` @@ -17,46 +18,46 @@ cosign sign [flags] ### Examples ``` - cosign sign --key | [--payload ] [-a key=value] [--upload=true|false] [-f] [-r] + cosign sign --key | [--payload ] [-a key=value] [--upload=true|false] [-f] [-r] # sign a container image with Google sign-in (experimental) - COSIGN_EXPERIMENTAL=1 cosign sign + COSIGN_EXPERIMENTAL=1 cosign sign # sign a container image with a local key pair file - cosign sign --key cosign.key + cosign sign --key cosign.key # sign a multi-arch container image AND all referenced, discrete images - cosign sign --key cosign.key --recursive + cosign sign --key cosign.key --recursive # sign a container image and add annotations - cosign sign --key cosign.key -a key1=value1 -a key2=value2 + cosign sign --key cosign.key -a key1=value1 -a key2=value2 # sign a container image with a key stored in an environment variable - cosign sign --key env://[ENV_VAR] + cosign sign --key env://[ENV_VAR] # sign a container image with a key pair stored in Azure Key Vault - cosign sign --key azurekms://[VAULT_NAME][VAULT_URI]/[KEY] + cosign sign --key azurekms://[VAULT_NAME][VAULT_URI]/[KEY] # sign a container image with a key pair stored in AWS KMS - cosign sign --key awskms://[ENDPOINT]/[ID/ALIAS/ARN] + cosign sign --key awskms://[ENDPOINT]/[ID/ALIAS/ARN] # sign a container image with a key pair stored in Google Cloud KMS - cosign sign --key gcpkms://projects/[PROJECT]/locations/global/keyRings/[KEYRING]/cryptoKeys/[KEY]/versions/[VERSION] + cosign sign --key gcpkms://projects/[PROJECT]/locations/global/keyRings/[KEYRING]/cryptoKeys/[KEY]/versions/[VERSION] # sign a container image with a key pair stored in Hashicorp Vault - cosign sign --key hashivault://[KEY] + cosign sign --key hashivault://[KEY] # sign a container image with a key pair stored in a Kubernetes secret - cosign sign --key k8s://[NAMESPACE]/[KEY] + cosign sign --key k8s://[NAMESPACE]/[KEY] # sign a container image with a key, attaching a certificate and certificate chain - cosign sign --key cosign.key --cert cosign.crt --cert-chain chain.crt + cosign sign --key cosign.key --cert cosign.crt --cert-chain chain.crt # sign a container in a registry which does not fully support OCI media types - COSIGN_DOCKER_MEDIA_TYPES=1 cosign sign --key cosign.key legacy-registry.example.com/my/image + COSIGN_DOCKER_MEDIA_TYPES=1 cosign sign --key cosign.key legacy-registry.example.com/my/image@ # sign a container image and not upload transparency log - cosign sign --key cosign.key --no-tlog-upload=true + cosign sign --key cosign.key --no-tlog-upload=true ``` ### Options