github.com/venafi-iw/cosign@v1.3.4/README.md (about) 1 # cosign 2 3 Container Signing, Verification and Storage in an OCI registry. 4 5 [![Go Report Card](https://goreportcard.com/badge/github.com/sigstore/cosign)](https://goreportcard.com/report/github.com/sigstore/cosign) 6 [![e2e-tests](https://github.com/sigstore/cosign/actions/workflows/e2e_tests.yml/badge.svg)](https://github.com/sigstore/cosign/actions/workflows/e2e_tests.yml) 7 8 Cosign aims to make signatures **invisible infrastructure**. 9 10 Cosign supports: 11 12 * Hardware and KMS signing 13 * Bring-your-own PKI 14 * Our free OIDC PKI ([Fulcio](https://github.com/sigstore/fulcio)) 15 * Built-in binary transparency and timestamping service ([Rekor](https://github.com/sigstore/rekor)) 16 17 ![intro](images/intro.gif) 18 19 ## Info 20 21 `Cosign` is developed as part of the [`sigstore`](https://sigstore.dev) project. 22 We also use a [slack channel](https://sigstore.slack.com)! 23 Click [here](https://join.slack.com/t/sigstore/shared_invite/zt-mhs55zh0-XmY3bcfWn4XEyMqUUutbUQ) for the invite link. 24 25 ## Installation 26 27 For Homebrew, Arch, Nix, GitHub Action, and Kubernetes installs see the [installation docs](https://docs.sigstore.dev/cosign/installation). 28 29 For Linux and macOS binaries see the [GitHub release assets](https://github.com/sigstore/cosign/releases/latest). 30 31 ## Developer Installation 32 33 If you have Go 1.16+, you can setup a development environment: 34 35 $ git clone https://github.com/sigstore/cosign 36 $ cd cosign 37 $ go install ./cmd/cosign 38 $ $(go env GOPATH)/bin/cosign 39 40 ## Quick Start 41 42 This shows how to: 43 44 * generate a keypair 45 * sign a container image and store that signature in the registry 46 * find signatures for a container image, and verify them against a public key 47 48 See the [Usage documentation](USAGE.md) for more commands! 49 50 See the [FUN.md](FUN.md) documentation for some fun tips and tricks! 51 52 NOTE: you will need access to a container registry for cosign to work with. 53 [ttl.sh](https://ttl.sh) offers free, short-lived (ie: hours), anonymous container image 54 hosting if you just want to try these commands out. 55 56 ### Generate a keypair 57 58 ```shell 59 $ cosign generate-key-pair 60 Enter password for private key: 61 Enter again: 62 Private key written to cosign.key 63 Public key written to cosign.pub 64 ``` 65 66 ### Sign a container and store the signature in the registry 67 68 ```shell 69 $ cosign sign --key cosign.key dlorenc/demo 70 Enter password for private key: 71 Pushing signature to: index.docker.io/dlorenc/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8.sig 72 ``` 73 74 The cosign command above prompts the user to enter the password for the private key. 75 The user can either manually enter the password, or if the environment variable `COSIGN_PASSWORD` is set then it is used automatically. 76 77 78 ### Verify a container against a public key 79 80 This command returns `0` if *at least one* `cosign` formatted signature for the image is found 81 matching the public key. 82 See the detailed usage below for information and caveats on other signature formats. 83 84 Any valid payloads are printed to stdout, in json format. 85 Note that these signed payloads include the digest of the container image, which is how we can be 86 sure these "detached" signatures cover the correct image. 87 88 ```shell 89 $ cosign verify --key cosign.pub dlorenc/demo 90 The following checks were performed on these signatures: 91 - The cosign claims were validated 92 - The signatures were verified against the specified public key 93 {"Critical":{"Identity":{"docker-reference":""},"Image":{"Docker-manifest-digest":"sha256:87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8"},"Type":"cosign container image signature"},"Optional":null} 94 ``` 95 96 ## `Cosign` is 1.0! 97 98 This means the core feature set of `cosign` is considered ready for production use. 99 This core set includes: 100 101 ### Key Management 102 103 * fixed, text-based keys generated using `cosign generate-key-pair` 104 * cloud KMS-based keys generated using `cosign generate-key-pair -kms` 105 * keys generated on hardware tokens using the PIV interface using `cosign piv-tool` 106 * Kubernetes-secret based keys generated using `cosign generate-key-pair k8s://namespace/secretName` 107 108 ### Artifact Types 109 110 * OCI and Docker Images 111 * Other artifacts that can be stored in a container registry, including: 112 * Tekton Bundles 113 * Helm Charts 114 * WASM modules 115 * (probably anything else, feel free to add things to this list) 116 * Text files and other binary blobs, using `cosign sign-blob` 117 118 ### What ** is not ** production ready? 119 120 While parts of `cosign` are stable, we are continuing to experiment and add new features. 121 The following feature set is not considered stable yet, but we are committed to stabilizing it over time! 122 123 #### Anything under the `COSIGN_EXPERIMENTAL` environment variable 124 125 * Integration with the `Rekor` transparency log 126 * Keyless signatures using the `Fulcio` CA 127 128 #### Formats/Specifications 129 130 While the `cosign` code for uploading, signing, retrieving, and verifying several artifact types is stable, 131 the format specifications for some of those types may not be considered stable yet. 132 Some of these are developed outside of the `cosign` project, so we are waiting for them to stabilize first. 133 134 These include: 135 136 * The SBOM specification for storing SBOMs in a container registry 137 * The In-Toto attestation format 138 139 ## Working with Other Artifacts 140 141 OCI registries are useful for storing more than just container images! 142 `Cosign` also includes some utilities for publishing generic artifacts, including binaries, scripts, and configuration files using the OCI protocol. 143 144 This section shows how to leverage these for an easy-to-use, backwards-compatible artifact distribution system that integrates well with the rest of Sigstore. 145 146 ### Blobs 147 148 You can publish an artifact with `cosign upload blob`: 149 150 ```shell 151 $ echo "my first artifact" > artifact 152 $ cosign upload blob -f artifact gcr.io/dlorenc-vmtest2/artifact 153 Uploading file from [artifact] to [gcr.io/dlorenc-vmtest2/artifact:latest] with media type [text/plain; charset=utf-8] 154 File is available directly at [us.gcr.io/v2/dlorenc-vmtest2/readme/blobs/sha256:b57400c0ad852a7c2f6f7da4a1f94547692c61f3e921a49ba3a41805ae8e1e99] 155 us.gcr.io/dlorenc-vmtest2/readme@sha256:4aa3054270f7a70b4528f2064ee90961788e1e1518703592ae4463de3b889dec 156 ``` 157 158 Your users can download it from the "direct" url with standard tools like curl or wget: 159 160 ```shell 161 $ curl -L gcr.io/v2/dlorenc-vmtest2/artifact/blobs/sha256:97f16c28f6478f3c02d7fff4c7f3c2a30041b72eb6852ca85b919fd85534ed4b > artifact 162 ``` 163 164 The digest is baked right into the URL, so they can check that as well: 165 166 ```shell 167 $ curl -L gcr.io/v2/dlorenc-vmtest2/artifact/blobs/sha256:97f16c28f6478f3c02d7fff4c7f3c2a30041b72eb6852ca85b919fd85534ed4b | shasum -a 256 168 97f16c28f6478f3c02d7fff4c7f3c2a30041b72eb6852ca85b919fd85534ed4b - 169 ``` 170 171 You can sign it with the normal `cosign sign` command and flags: 172 173 ```shell 174 $ cosign sign --key cosign.key gcr.io/dlorenc-vmtest2/artifact 175 Enter password for private key: 176 Pushing signature to: gcr.io/dlorenc-vmtest2/artifact:sha256-3f612a4520b2c245d620d0cca029f1173f6bea76819dde8543f5b799ea3c696c.sig 177 ``` 178 #### sget 179 180 We also include the `sget` command for safer, automatic verification of signatures and integration with our binary transparency log, Rekor. 181 182 To install `sget`, if you have Go 1.16+, you can directly run: 183 184 $ go install github.com/sigstore/cosign/cmd/sget@latest 185 186 and the resulting binary will be placed at `$GOPATH/bin/sget` (or `$GOBIN/sget`, if set). 187 188 Just like `curl`, `sget` can be used to fetch artifacts by digest using the OCI URL. 189 Digest verification is automatic: 190 191 ```shell 192 $ sget us.gcr.io/dlorenc-vmtest2/readme@sha256:4aa3054270f7a70b4528f2064ee90961788e1e1518703592ae4463de3b889dec > artifact 193 ``` 194 195 You can also use `sget` to fetch contents by tag. 196 Fetching contents without verifying them is dangerous, so we require the artifact be signed in this case: 197 198 ```shell 199 $ sget gcr.io/dlorenc-vmtest2/artifact 200 error: public key must be specified when fetching by tag, you must fetch by digest or supply a public key 201 202 $ sget --key cosign.pub us.gcr.io/dlorenc-vmtest2/readme > foo 203 204 Verification for us.gcr.io/dlorenc-vmtest2/readme -- 205 The following checks were performed on each of these signatures: 206 - The cosign claims were validated 207 - Existence of the claims in the transparency log was verified offline 208 - The signatures were verified against the specified public key 209 - Any certificates were verified against the Fulcio roots. 210 ``` 211 212 The signature, claims and transparency log proofs are all verified automatically by sget as part of the download. 213 214 `curl | bash` isn't a great idea, but `sget | bash` is less-bad. 215 216 #### Tekton Bundles 217 218 [Tekton](https://tekton.dev) bundles can be uploaded and managed within an OCI registry. 219 The specification is [here](https://tekton.dev/docs/pipelines/tekton-bundle-contracts/). 220 This means they can also be signed and verified with `cosign`. 221 222 Tekton Bundles can currently be uploaded with the [tkn cli](github.com/tekton/cli), but we may add this support to 223 `cosign` in the future. 224 225 ```shell 226 $ tkn bundle push us.gcr.io/dlorenc-vmtest2/pipeline:latest -f task-output-image.yaml 227 Creating Tekton Bundle: 228 - Added TaskRun: to image 229 230 Pushed Tekton Bundle to us.gcr.io/dlorenc-vmtest2/pipeline@sha256:124e1fdee94fe5c5f902bc94da2d6e2fea243934c74e76c2368acdc8d3ac7155 231 $ cosign sign --key cosign.key us.gcr.io/dlorenc-vmtest2/pipeline:latest 232 Enter password for private key: 233 tlog entry created with index: 5086 234 Pushing signature to: us.gcr.io/dlorenc-vmtest2/demo:sha256-124e1fdee94fe5c5f902bc94da2d6e2fea243934c74e76c2368acdc8d3ac7155.sig 235 ``` 236 237 #### WASM 238 239 Web Assembly Modules can also be stored in an OCI registry, using this [specification](https://github.com/solo-io/wasm/tree/master/spec). 240 241 Cosign can upload these using the `cosign wasm upload` command: 242 243 ```shell 244 $ cosign upload wasm -f hello.wasm us.gcr.io/dlorenc-vmtest2/wasm 245 $ cosign sign --key cosign.key us.gcr.io/dlorenc-vmtest2/wasm 246 Enter password for private key: 247 tlog entry created with index: 5198 248 Pushing signature to: us.gcr.io/dlorenc-vmtest2/wasm:sha256-9e7a511fb3130ee4641baf1adc0400bed674d4afc3f1b81bb581c3c8f613f812.sig 249 ``` 250 251 #### In-Toto Attestations 252 253 Cosign also has built-in support for [in-toto](https://in-toto.io) attestations. 254 The specification for these is defined [here](https://github.com/in-toto/attestation). 255 256 You can create and sign one from a local predicate file using the following commands: 257 258 ```shell 259 $ cosign attest --predicate <file> --key cosign.key <image> 260 ``` 261 262 All of the standard key management systems are supported. 263 Payloads are signed using the DSSE signing spec, defined [here](https://github.com/secure-systems-lab/dsse). 264 265 To verify: 266 267 ```shell 268 $ cosign verify-attestation --key cosign.pub <image> 269 ``` 270 271 ## Detailed Usage 272 273 See the [Usage documentation](USAGE.md) for more commands! 274 275 ## Hardware-based Tokens 276 277 See the [Hardware Tokens documentation](TOKENS.md) for information on how to use `cosign` with hardware. 278 279 ## Keyless 280 281 🚨 🚨 🚨 See [here](KEYLESS.md) for info on the experimental Keyless signatures mode. 🚨 🚨 🚨 282 283 ## Registry Support 284 285 `cosign` uses [go-containerregistry](https://github.com/google/go-containerregistry) for registry 286 interactions, which has generally excellent compatibility, but some registries may have quirks. 287 288 Today, `cosign` has been tested and works against the following registries: 289 290 * AWS Elastic Container Registry 291 * GCP's Artifact Registry and Container Registry 292 * Docker Hub 293 * Azure Container Registry 294 * JFrog Artifactory Container Registry 295 * The CNCF distribution/distribution Registry 296 * GitLab Container Registry 297 * GitHub Container Registry 298 * The CNCF Harbor Registry 299 * Digital Ocean Container Registry 300 * Sonatype Nexus Container Registry 301 * Alibaba Cloud Container Registry 302 * Red Hat Quay Container Registry 3.6+ 303 - Note: Cosign does not work with the Quay.io hosted service 304 305 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: 306 ```shell 307 COSIGN_DOCKER_MEDIA_TYPES=1 cosign sign --key cosign.key legacy-registry.example.com/my/image 308 ``` 309 310 Please help test and file bugs if you see issues! 311 Instructions can be found in the [tracking issue](https://github.com/sigstore/cosign/issues/40). 312 313 ## Rekor Support 314 _Note: this is an experimental feature_ 315 316 To publish signed artifacts to a Rekor transparency log and verify their existence in the log 317 set the `COSIGN_EXPERIMENTAL=1` environment variable. 318 319 ```shell 320 $ COSIGN_EXPERIMENTAL=1 cosign sign --key cosign.key dlorenc/demo 321 $ COSIGN_EXPERIMENTAL=1 cosign verify --key cosign.pub dlorenc/demo 322 ``` 323 324 `cosign` defaults to using the public instance of rekor at [rekor.sigstore.dev](https://rekor.sigstore.dev). 325 To configure the rekor server, use the -`rekor-url` flag 326 327 ## Caveats 328 329 ### Intentionally Missing Features 330 331 `cosign` only generates ECDSA-P256 keys and uses SHA256 hashes. 332 Keys are stored in PEM-encoded PKCS8 format. 333 However, you can use `cosign` to store and retrieve signatures in any format, from any algorithm. 334 335 ### Unintentionally Missing Features 336 337 `cosign` will integrate with transparency logs! 338 See https://github.com/sigstore/cosign/issues/34 for more info. 339 340 `cosign` will integrate with even more transparency logs, and a PKI. 341 See https://github.com/sigStore/fulcio for more info. 342 343 `cosign` will also support The Update Framework for delegations, key discovery and expiration. 344 See https://github.com/sigstore/cosign/issues/86 for more info! 345 346 ### Things That Should Probably Change 347 348 #### Payload Formats 349 350 `cosign` only supports Red Hat's [simple signing](https://www.redhat.com/en/blog/container-image-signing) 351 format for payloads. 352 That looks like: 353 354 ```json 355 { 356 "critical": { 357 "identity": { 358 "docker-reference": "testing/manifest" 359 }, 360 "image": { 361 "Docker-manifest-digest": "sha256:20be...fe55" 362 }, 363 "type": "cosign container image signature" 364 }, 365 "optional": { 366 "creator": "Bob the Builder", 367 "timestamp": 1458239713 368 } 369 } 370 ``` 371 **Note:** This can be generated for an image reference using `cosign generate <image>`. 372 373 I'm happy to switch this format to something else if it makes sense. 374 See https://github.com/notaryproject/nv2/issues/40 for one option. 375 376 377 #### Registry Details 378 379 `cosign` signatures are stored as separate objects in the OCI registry, with only a weak 380 reference back to the object they "sign". 381 This means this relationship is opaque to the registry, and signatures *will not* be deleted 382 or garbage-collected when the image is deleted. 383 Similarly, they **can** easily be copied from one environment to another, but this is not 384 automatic. 385 386 Multiple signatures are stored in a list which is unfortunately "racy" today. 387 To add a signature, clients orchestrate a "read-append-write" operation, so the last write 388 will win in the case of contention. 389 390 ##### Specifying Registry 391 `cosign` will default to storing signatures in the same repo as the image it is signing. 392 To specify a different repo for signatures, you can set the `COSIGN_REPOSITORY` environment variable. 393 394 This will replace the repo in the provided image like this: 395 ``` 396 $ export COSIGN_REPOSITORY=gcr.io/my-new-repo 397 $ gcr.io/dlorenc-vmtest2/demo -> gcr.io/my-new-repo/demo:sha256-DIGEST.sig 398 ``` 399 So the signature for `gcr.io/dlorenc-vmtest2/demo` will be stored in `gcr.io/my-new-repo/demo:sha256-DIGEST.sig`. 400 401 402 ## Signature Specification 403 404 `cosign` is inspired by tools like [minisign](https://jedisct1.github.io/minisign/) and 405 [signify](https://www.openbsd.org/papers/bsdcan-signify.html). 406 407 Generated private keys are stored in PEM format. 408 The keys encrypted under a password using scrypt as a KDF and nacl/secretbox for encryption. 409 410 They have a PEM header of `ENCRYPTED COSIGN PRIVATE KEY`: 411 412 ``` 413 -----BEGIN ENCRYPTED COSIGN PRIVATE KEY----- 414 ... 415 -----END ENCRYPTED COSIGN PRIVATE KEY----- 416 ``` 417 418 Public keys are stored on disk in PEM-encoded standard PKIX format with a header of `PUBLIC KEY`. 419 ``` 420 -----BEGIN PUBLIC KEY----- 421 MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELigCnlLNKgOglRTx1D7JhI7eRw99 422 QolE9Jo4QUxnbMy5nUuBL+UZF9qqfm/Dg1BNeHRThHzWh2ki9vAEgWEDOw== 423 -----END PUBLIC KEY----- 424 ``` 425 426 ## Storage Specification 427 428 `cosign` stores signatures in an OCI registry, and uses a naming convention (tag based 429 on the sha256 of what we're signing) for locating the signature index. 430 431 <p align="center"> 432 <img src="/images/signatures.dot.svg" /> 433 </p> 434 435 `reg.example.com/ubuntu@sha256:703218c0465075f4425e58fac086e09e1de5c340b12976ab9eb8ad26615c3715` has signatures located at `reg.example.com/ubuntu:sha256-703218c0465075f4425e58fac086e09e1de5c340b12976ab9eb8ad26615c3715.sig` 436 437 Roughly (ignoring ports in the hostname): `s/:/-/g` and `s/@/:/g` to find the signature index. 438 439 See [Race conditions](#race-conditions) for some caveats around this strategy. 440 441 Alternative implementations could use transparency logs, local filesystem, a separate repository 442 registry, an explicit reference to a signature index, a new registry API, grafeas, etc. 443 444 ### Signing subjects 445 446 `cosign` only works for artifacts stored as "manifests" in the registry today. 447 The proposed mechanism is flexible enough to support signing arbitrary things. 448 449 ### KMS Support 450 451 `cosign` supports using a KMS provider to generate and sign keys. 452 Right now cosign supports Hashicorp Vault, AWS KMS, GCP KMS, Azure Key Vault and we are hoping to support more in the future! 453 454 See the [KMS docs](KMS.md) for more details. 455 456 ### OCI Artifacts 457 458 Push an artifact to a registry using [oras](https://github.com/deislabs/oras) (in this case, `cosign` itself!): 459 460 ```shell 461 $ oras push us-central1-docker.pkg.dev/dlorenc-vmtest2/test/artifact ./cosign 462 Uploading f53604826795 cosign 463 Pushed us-central1-docker.pkg.dev/dlorenc-vmtest2/test/artifact 464 Digest: sha256:551e6cce7ed2e5c914998f931b277bc879e675b74843e6f29bc17f3b5f692bef 465 ``` 466 467 Now sign it! Using `cosign` of course: 468 469 ```shell 470 $ cosign sign --key cosign.key us-central1-docker.pkg.dev/dlorenc-vmtest2/test/artifact@sha256:551e6cce7ed2e5c914998f931b277bc879e675b74843e6f29bc17f3b5f692bef 471 Enter password for private key: 472 Pushing signature to: us-central1-docker.pkg.dev/dlorenc-vmtest2/test/artifact:sha256-551e6cce7ed2e5c914998f931b277bc879e675b74843e6f29bc17f3b5f692bef.sig 473 ``` 474 475 Finally, verify `cosign` with `cosign` again: 476 477 ```shell 478 $ cosign verify --key cosign.pub us-central1-docker.pkg.dev/dlorenc-vmtest2/test/artifact@sha256:551e6cce7ed2e5c914998f931b277bc879e675b74843e6f29bc17f3b5f692bef 479 The following checks were performed on each of these signatures: 480 - The cosign claims were validated 481 - The claims were present in the transparency log 482 - The signatures were integrated into the transparency log when the certificate was valid 483 - The signatures were verified against the specified public key 484 - Any certificates were verified against the Fulcio roots. 485 486 {"Critical":{"Identity":{"docker-reference":""},"Image":{"Docker-manifest-digest":"sha256:551e6cce7ed2e5c914998f931b277bc879e675b74843e6f29bc17f3b5f692bef"},"Type":"cosign container image signature"},"Optional":null} 487 ``` 488 489 ## FAQ 490 491 ### Why not use Notary v2 492 493 It's hard to answer this briefly. 494 This post contains some comparisons: 495 496 [Notary V2 and Cosign](https://medium.com/@dlorenc/notary-v2-and-cosign-b816658f044d) 497 498 If you find other comparison posts, please send a PR here and we'll link them all. 499 500 ### Why not use containers/image signing 501 502 `containers/image` signing is close to `cosign`, and we reuse payload formats. 503 `cosign` differs in that it signs with ECDSA-P256 keys instead of PGP, and stores 504 signatures in the registry. 505 506 ### Why not use TUF? 507 508 I believe this tool is complementary to TUF, and they can be used together. 509 I haven't tried yet, but think we can also reuse a registry for TUF storage. 510 511 ### Why not use Blockchain? 512 513 Just kidding. Nobody actually asked this. Don't be that person. 514 515 ### Why not use $FOO? 516 517 See the next section, [Requirements](#Requirements). 518 I designed this tool to meet a few specific requirements, and didn't find 519 anything else that met all of these. 520 If you're aware of another system that does meet these, please let me know! 521 522 ## Design Requirements 523 524 * No external services for signature storage, querying, or retrieval 525 * We aim for as much registry support as possible 526 * Everything should work over the registry API 527 * PGP should not be required at all. 528 * Users must be able to find all signatures for an image 529 * Signers can sign an image after push 530 * Multiple entities can sign an image 531 * Signing an image does not mutate the image 532 * Pure-go implementation 533 534 ## Future Ideas 535 536 ### Registry API Changes 537 538 The naming convention and read-modify-write update patterns we use to store things in 539 a registry a bit, well, "hacky". 540 I think they're the best (only) real option available today, but if the registry API 541 changes we can improve these. 542 543 ### Other Types 544 545 `cosign` can sign anything in a registry. 546 These examples show signing a single image, but you could also sign a multi-platform `Index`, 547 or any other type of artifact. 548 This includes Helm Charts, Tekton Pipelines, and anything else currently using OCI registries 549 for distribution. 550 551 This also means new artifact types can be uploaded to a registry and signed. 552 One interesting type to store and sign would be TUF repositories. 553 I haven't tried yet, but I'm fairly certain TUF could be implemented on top of this. 554 555 ### Tag Signing 556 557 `cosign` signatures protect the digests of objects stored in a registry. 558 The optional `annotations` support (via the `-a` flag to `cosign sign`) can be used to add extra 559 data to the payload that is signed and protected by the signature. 560 One use-case for this might be to sign a tag->digest mapping. 561 562 If you would like to attest that a specific tag (or set of tags) should point at a digest, you can 563 run something like: 564 565 ```shell 566 $ TAG=sign-me 567 $ DGST=$(crane digest dlorenc/demo:$TAG) 568 $ cosign sign --key cosign.key -a tag=$TAG dlorenc/demo@$DGST 569 Enter password for private key: 570 Pushing signature to: dlorenc/demo:sha256-97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36.sig 571 ``` 572 573 Then you can verify that the tag->digest mapping is also covered in the signature, using the `-a` flag to `cosign verify`. 574 This example verifies that the digest `$TAG` points to (`sha256:97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36`) 575 has been signed, **and also** that the `$TAG`: 576 577 ```shell 578 $ cosign verify --key cosign.pub -a tag=$TAG dlorenc/demo:$TAG | jq . 579 { 580 "Critical": { 581 "Identity": { 582 "docker-reference": "" 583 }, 584 "Image": { 585 "Docker-manifest-digest": "97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36" 586 }, 587 "Type": "cosign container image signature" 588 }, 589 "Optional": { 590 "tag": "sign-me" 591 } 592 } 593 ``` 594 595 Timestamps could also be added here, to implement TUF-style freeze-attack prevention. 596 597 ### Base Image/Layer Signing 598 599 Again, `cosign` can sign anything in a registry. 600 You could use `cosign` to sign an image that is intended to be used as a base image, 601 and include that provenance metadata in resulting derived images. 602 This could be used to enforce that an image was built from an authorized base image. 603 604 Rough Idea: 605 * OCI manifests have an ordered list of `layer` `Descriptors`, which can contain annotations. 606 See [here](https://github.com/opencontainers/image-spec/blob/master/manifest.md) for the 607 specification. 608 * A base image is an ordered list of layers to which other layers are appended, as well as an 609 initial configuration object that is mutated. 610 * A derived image is free to completely delete/destroy/recreate the config from its base image, 611 so signing the config would provided limited value. 612 * We can sign the full set of ordered base layers, and attach that signature as an annotation to 613 the **last** layer in the resulting child image. 614 615 This example manifest manifest represents an image that has been built from a base image with two 616 layers. 617 One additional layer is added, forming the final image. 618 619 ```json 620 { 621 "schemaVersion": 2, 622 "config": { 623 "mediaType": "application/vnd.oci.image.config.v1+json", 624 "size": 7023, 625 "digest": "sha256:b5b2b2c507a0944348e0303114d8d93aaaa081732b86451d9bce1f432a537bc7" 626 }, 627 "layers": [ 628 { 629 "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", 630 "size": 32654, 631 "digest": "sha256:9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0" 632 }, 633 { 634 "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", 635 "size": 16724, 636 "digest": "sha256:3c3a4604a545cdc127456d94e421cd355bca5b528f4a9c1905b15da2eb4a4c6b", 637 "annotations": { 638 "dev.cosign.signature.baseimage": "Ejy6ipGJjUzMDoQFePWixqPBYF0iSnIvpMWps3mlcYNSEcRRZelL7GzimKXaMjxfhy5bshNGvDT5QoUJ0tqUAg==" 639 } 640 }, 641 { 642 "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", 643 "size": 73109, 644 "digest": "sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736" 645 } 646 ], 647 } 648 ``` 649 650 Note that this could be applied recursively, for multiple intermediate base images. 651 652 ### Counter-Signing 653 654 Cosign signatures (and their protected payloads) are stored as artifacts in a registry. 655 These signature objects can also be signed, resulting in a new, "counter-signature" artifact. 656 This "counter-signature" protects the signature (or set of signatures) **and** the referenced artifact, which allows 657 it to act as an attestation to the **signature(s) themselves**. 658 659 Before we sign the signature artifact, we first give it a memorable name so we can find it later. 660 661 ```shell 662 $ cosign sign --key cosign.key -a sig=original dlorenc/demo 663 Enter password for private key: 664 Pushing signature to: dlorenc/demo:sha256-97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36.sig 665 $ cosign verify --key cosign.pub dlorenc/demo | jq . 666 { 667 "Critical": { 668 "Identity": { 669 "docker-reference": "" 670 }, 671 "Image": { 672 "Docker-manifest-digest": "97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36" 673 }, 674 "Type": "cosign container image signature" 675 }, 676 "Optional": { 677 "sig": "original" 678 } 679 } 680 ``` 681 682 Now give that signature a memorable name, then sign that: 683 684 ```shell 685 $ crane tag $(cosign triangulate dlorenc/demo) mysignature 686 2021/02/15 20:22:55 dlorenc/demo:mysignature: digest: sha256:71f70e5d29bde87f988740665257c35b1c6f52dafa20fab4ba16b3b1f4c6ba0e size: 556 687 $ cosign sign --key cosign.key -a sig=counter dlorenc/demo:mysignature 688 Enter password for private key: 689 Pushing signature to: dlorenc/demo:sha256-71f70e5d29bde87f988740665257c35b1c6f52dafa20fab4ba16b3b1f4c6ba0e.sig 690 $ cosign verify --key cosign.pub dlorenc/demo:mysignature 691 {"Critical":{"Identity":{"docker-reference":""},"Image":{"Docker-manifest-digest":"71f70e5d29bde87f988740665257c35b1c6f52dafa20fab4ba16b3b1f4c6ba0e"},"Type":"cosign container image signature"},"Optional":{"sig":"counter"}} 692 ``` 693 694 Finally, check the original signature: 695 696 ```shell 697 $ crane manifest dlorenc/demo@sha256:71f70e5d29bde87f988740665257c35b1c6f52dafa20fab4ba16b3b1f4c6ba0e 698 { 699 "schemaVersion": 2, 700 "config": { 701 "mediaType": "application/vnd.oci.image.config.v1+json", 702 "size": 233, 703 "digest": "sha256:3b25a088710d03f39be26629d22eb68cd277a01673b9cb461c4c24fbf8c81c89" 704 }, 705 "layers": [ 706 { 707 "mediaType": "application/vnd.oci.descriptor.v1+json", 708 "size": 217, 709 "digest": "sha256:0e79a356609f038089088ec46fd95f4649d04de989487220b1a0adbcc63fadae", 710 "annotations": { 711 "dev.sigstore.cosign/signature": "5uNZKEP9rm8zxAL0VVX7McMmyArzLqtxMTNPjPO2ns+5GJpBeXg+i9ILU+WjmGAKBCqiexTxzLC1/nkOzD4cDA==" 712 } 713 } 714 ] 715 } 716 ``` 717 718 ## Security 719 720 Should you discover any security issues, please refer to sigstore's [security 721 process](https://github.com/sigstore/community/blob/main/SECURITY.md)