Cosign
Container Signing, Verification and Storage in an OCI registry
About Cosign
This large README is shown as a plain-text preview. Read the full README at the source
<p align="center">
<img style="max-width: 100%;width: 300px;" src="https://raw.githubusercontent.com/sigstore/community/main/artwork/cosign/horizontal/color/sigstore_cosign-horizontal-color.svg" alt="Cosign logo"/>
</p>
# cosign
Signing OCI containers (and other artifacts) using [Sigstore](https://sigstore.dev/)!
[](https://goreportcard.com/report/github.com/sigstore/cosign)
[](https://github.com/sigstore/cosign/actions/workflows/e2e-tests.yml)
[](https://bestpractices.coreinfrastructure.org/projects/5715)
[](https://securityscorecards.dev/viewer/?uri=github.com/sigstore/cosign)
Cosign aims to make signatures **invisible infrastructure**.
Cosign supports:
* "Keyless signing" with the Sigstore public good Fulcio certificate authority and Rekor transparency log (default)
* Hardware and KMS signing
* Signing with a cosign generated encrypted private/public keypair
* Container Signing, Verification and Storage in an OCI registry.
* Bring-your-own PKI
## Info
`Cosign` is developed as part of the [`sigstore`](https://sigstore.dev) project.
We also use a [slack channel](https://sigstore.slack.com)!
Click [here](https://join.slack.com/t/sigstore/shared_invite/zt-47srvpyn6-j8Ek5hGBwKN32IjLw8BvYA) for the invite link.
## Installation
For Homebrew, Arch, Nix, GitHub Action, and Kubernetes installs see the [installation docs](https://docs.sigstore.dev/cosign/system_config/installation/).
For Linux, macOS and Windows binaries, see the [GitHub release assets](https://github.com/sigstore/cosign/releases/latest).
:rotating_light: If you are downloading releases of cosign from our GCS bucket - please see more information on the July 31, 2023 [deprecation notice](https://blog.sigstore.dev/cosign-releases-bucket-deprecation/) :rotating_light:
## Developer Installation
If you have Go 1.22+, you can setup a development environment:
```shell
$ git clone https://github.com/sigstore/cosign
$ cd cosign
$ go install ./cmd/cosign
$ $(go env GOPATH)/bin/cosign
```
## Contributing
If you are interested in contributing to `cosign`, please read the [contributing documentation](./CONTRIBUTING.md).
Future Cosign development will be focused the next major release which will be based on
[sigstore-go](https://github.com/sigstore/sigstore-go). Maintainers will be focused on feature development within
sigstore-go. Contributions to sigstore-go, particularly around bring-your-own keys and signing, are appreciated.
Please see the [issue tracker](https://github.com/sigstore/sigstore-go/issues) for good first issues.
Cosign 2.x is a stable release and will continue to receive periodic feature updates and bug fixes. PRs
that are small in scope and size are most likely to be quickly reviewed.
PRs which significantly modify or break the API will not be accepted. PRs which are significant in size but do not
introduce breaking changes may be accepted, but will be considered lower priority than PRs in sigstore-go.
## Dockerfile
Here is how to install and use cosign inside a Dockerfile through the ghcr.io/sigstore/cosign/cosign image:
```shell
FROM ghcr.io/sigstore/cosign/cosign:v2.4.1 as cosign-bin
# Source: https://github.com/chainguard-images/images/tree/main/images/static
FROM cgr.dev/chainguard/static:latest
COPY --from=cosign-bin /ko-app/cosign /usr/local/bin/cosign
ENTRYPOINT [ "cosign" ]
```
## Quick Start
This shows how to:
* sign a container image with the default identity-based "keyless signing" method (see [the documentation for more information](https://docs.sigstore.dev/cosign/signing/overview/))
* verify the container image
* explore broader keyless blob signing/verification flows in the [Sigstore Cosign Quickstart](https://docs.sigstore.dev/quickstart/quickstart-cosign/)
### 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 $IMAGE
Generating ephemeral keys...
Retrieving signed certificate...
Note that there may be personally identifiable information associated with this signed artifact.
This may include the email address associated with the account with which you authenticate.
This information will be used for signing this artifact and will be stored in public transparency logs and cannot be removed later.
By typing 'y', you attest that you grant (or have permission to grant) and agree to have this information stored permanently in transparency logs.
Are you sure you would like to continue? [y/N] y
Your browser will now be opened to:
https://oauth2.sigstore.dev/auth/auth?access_type=online&client_id=sigstore&code_challenge=OrXitVKUZm2lEWHVt1oQWR4HZvn0rSlKhLcltglYxCY&code_challenge_method=S256&nonce=2KvOWeTFxYfxyzHtssvlIXmY6Jk&redirect_uri=http%3A%2F%2Flocalhost%3A57102%2Fauth%2Fcallback&response_type=code&scope=openid+email&state=2KvOWfbQJ1caqScgjwibzK2qJmb
Successfully verified SCT...
tlog entry created with index: 12086900
Pushing signature to: $IMAGE
```
Cosign will prompt you to authenticate via OIDC, where you'll sign in with your email address.
Under the hood, cosign will request a code signing certificate from the Fulcio certificate authority.
The subject of the certificate will match the email address you logged in with.
Cosign will then store the signature and certificate in the Rekor transparency log, and upload the signature to the OCI registry alongside the image you're signing.
### Verify a container
To verify the image, you'll need to pass in the expected certificate subject and certificate issuer via the `--certificate-identity` and `--certificate-oidc-issuer` flags:
```
cosign verify $IMAGE --certificate-identity=$IDENTITY --certificate-oidc-issuer=$OIDC_ISSUER
```
You can also pass in a regex for the certificate identity and issuer flags, `--certificate-identity-regexp` and `--certificate-oidc-issuer-regexp`.
### Verify a container against a public key
This command returns `0` if *at least one* `cosign` formatted signature for the image is found
matching the public key.
See the detailed usage below for information and caveats on other signature formats.
Any valid payloads are printed to stdout, in json format.
Note that these signed payloads include the digest of the container image, which is how we can be
sure these "detached" signatures cover the correct image.
```shell
$ cosign verify --key cosign.pub $IMAGE_URI:1h
The following checks were performed on these signatures:
- The cosign claims were validated
- The signatures were verified against the specified public key
{"Critical":{"Identity":{"docker-reference":""},"Image":{"Docker-manifest-digest":"sha256:87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8"},"Type":"cosign container image signature"},"Optional":null}
```
### Verify a container in an air-gapped environment
**Note:** This section is out of date.
**Note:** Most verification workflows require periodically requesting service keys from a TUF repository.
For airgapped verification of signatures using the public-good instance, you will need to retrieve the
[trusted root](https://github.com/sigstore/root-signing/blob/main/targets/trusted_root.json) file from the production
TUF repository. The contents of this file will change without notification. By not using TUF, you will need
to build your own mechanism to keep your airgapped copy of this file up-to-date.
Cosign can do completely offline verification by verifying a [bundle](./specs/SIGNATURE_SPEC.md#properties) which is typically distributed as an annotation on the image manifest.
As long as this annotation is present, then offline verification can be done.
This bundle annotation is always included by default for keyless signing, so the default `cosign sign` functionality will include all materials needed for offline verification.
To verify an image in an air-gapped environment, the image and signatures must be available locally on the filesystem.
An image can be saved locally using `cosign save` (note, this step must be done with a network connection):
```
cosign initialize # This will pull in the latest TUF root
cosign save $IMAGE_NAME --dir ./path/to/dir
```
Now, in an air-gapped environment, this local image can be verified:
```shell
cosign verify \
--certificate-identity $CERT_IDENTITY \
--certificate-oidc-issuer $CERT_OIDC_ISSUER \
--offline=true \
--new-bundle-format=false \ # for artifacts signed without the new protobuf bundle format
--trusted-root ~/.sigstore/root/tuf-repo-cdn.sigstore.dev/targets/trusted_root.json \ # default location of trusted root
--local-image ./path/to/dir
```
You'll need to pass in expected values for `$CERT_IDENTITY` and `$CERT_OIDC_ISSUER` to correctly verify this image.
If you signed with a keypair, the same command will work, assuming the public key material is present locally:
```
cosign verify --key cosign.pub --offline --local-image ./path/to/dir
```
### Identity-based blob signing and verification
Use keyless blob signing (`cosign sign-blob` without `--key`) and verify against the expected signer identity:
```shell
$ cosign sign-blob artifact --bundle artifact.sigstore.json --yes
$ cosign verify-blob artifact \
--bundle artifact.sigstore.json \
--certificate-identity "https://github.com/ORG/REPO/.github/workflows/release.yml@refs/heads/main" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
```
### Troubleshooting
If you encounter issues with Cosign, first make sure you are using a recent release: The Cosign project actively supports the most recent release as well as the last release in the v2 series.
#### Common issues and remedies
1. Verification fails with `failed to verify timestamps: threshold not met for verified log entry integrated timestamps: 0 < 1`: You may be verifying a signature that requires RFC3161 timestamp support
* Upgrade to most recent Cosign or
* With Cosign 2.6.x, use `--use-signed-timestamps`
1. Verification fails with `no signatures found`: You may be verifying an image signature that requires support for Rekor v2 transparency log
* Upgrade to most recent Cosign
1. Signing fails with HTTP errors: Signing with Cosign depends on multiple Sigstore services. Retrying on failure may be a useful workaround if any of these services fail -- filing issues for specific failures is also appreciated
#### My problem is something else
Please open an [issue](https://github.com/sigstore/cosign/issues/new/choose) or ask in the [slack channel](#info).
## Working with Other Artifacts
OCI registries are useful for storing more than just container images!
`Cosign` also includes some utilities for publishing generic artifacts, including binaries, scripts, and configuration files using the OCI protocol.
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.
See [the documentation](https://docs.sigstore.dev/cosign/signing/other_types/) for more information.
### Blobs
You can publish an artifact with `cosign upload blob`:
```shell
$ echo "my first artifact" > artifact
$ BLOB_SUM=$(shasum -a 256 artifact | cut -d' ' -f 1) && echo "$BLOB_SUM"
c69d72c98b55258f9026f984e4656f0e9fd3ef024ea3fac1d7e5c7e6249f1626
$ BLOB_NAME=my-artifact-$(uuidgen | head -c 8 | tr 'A-Z' 'a-z')
$ BLOB_URI=ttl.sh/$BLOB_NAME:1h
$ BLOB_URI_DIGEST=$(cosign upload blob -f artifact $BLOB_URI) && echo "$BLOB_URI_DIGEST"
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 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
$ 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 $BLOB_URI_DIGEST
Enter password for private key:
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!
#### Tekton Bundles
[Tekton](https://tekton.dev) bundles can be uploaded and managed within an OCI registry.
The specification is [here](https://tekton.dev/docs/pipelines/tekton-bundle-contracts/).
This means they can also be signed and verified with `cosign`.
Tekton Bundles can currently be uploaded with the [tkn cli](https://github.com/tektoncd/cli), but we may add this support to
`cosign` in the future.
```shell
$ tkn bundle push us.gcr.io/dlorenc-vmtest2/pipeline:latest -f task-output-image.yaml
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@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
```
#### WASM
Web Assembly Modules can also be stored in an OCI registry, using this [specification](https://github.com/solo-io/wasm/tree/master/spec).
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@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
```
#### eBPF
[eBPF](https://ebpf.io) modules can also be stored in an OCI registry, using this [specification](https://github.com/solo-io/bumblebee/tree/main/spec).
The image below was built using the `bee` tool. More information can be found [here](https://github.com/solo-io/bumblebee/)
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@sha256:7a91c50d922925f152fec96ed1d84b7bc6b2079c169d68826f6cf307f22d40e6
Enter password for private key:
Pushing signature to: localhost:5000/tcpconnect
$ cosign verify --key cosign.pub localhost:5000/tcpconnect:test
Verification for localhost:5000/tcpconnect:test --
The following checks were performed on each of these signatures:
- The cosign claims were validated
- The signatures were verified against the specified public key
[{"critical":{"identity":{"docker-reference":"localhost:5000/tcpconnect"},"image":{"docker-manifest-digest":"sha256:7a91c50d922925f152fec96ed1d84b7bc6b2079c169d68826f6cf307f22d40e6"},"type":"cosign container image signature"},"optional":null}]
```
#### In-Toto Attestations
Cosign also has built-in support for [in-toto](https://in-toto.io) attestations.
The specification for these is defined [here](https://github.com/in-toto/attestation).
You can create and sign one from a local predicate file using the following commands:
```shell
$ cosign attest --predicate <file> --key cosign.key $IMAGE_URI_DIGEST
```
All of the standard key management systems are supported.
Payloads are signed using the DSSE signing spec, defined [here](https://github.com/secure-systems-lab/dsse).
To verify:
```shell
$ cosign verify-attestation --key cosign.pub $IMAGE_URI
```
## Detailed Usage
See the [Usage documentation](https://docs.sigstore.dev/cosign/signing/overview/) for more information.
## Hardware-based Tokens
See the [Hardware Tokens documentation](https://docs.sigstore.dev/cosign/key_management/hardware-based-tokens/) for information on how to use `cosign` with hardware.
## Registry Support
`cosign` uses [go-containerregistry](https://github.com/google/go-containerregistry) for registry
interactions, which has generally excellent compatibility, but some registries may have quirks.
Today, `cosign` has been tested and works against the following registries:
* AWS Elastic Container Registry
* GCP's Artifact Registry and Container Registry
* Docker Hub
* Azure Container Registry
* JFrog Artifactory Container Registry
* The CNCF distribution/distribution Registry
* GitLab Container Registry
* GitHub Container Registry
* The CNCF Harbor Registry
* Digital Ocean Container Registry
* Sonatype Nexus Container Registry
* Alibaba Cloud Container Registry
* Red Hat Quay Container Registry 3.6+ / Red Hat quay.io
* Elastic Container Registry
* IBM Cloud Container Registry
* Cloudsmith Container Registry
* The CNCF zot Registry
* OVHcloud Managed Private Registry
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/specs/SIGNATURE_SPEC.md), 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@$DIGEST
```
Please help test and file bugs if you see issues!
Instructions can be found in the [tracking issue](https://github.com/sigstore/cosign/issues/40).
## Caveats
### Intentionally Missing Features
`cosign` only generates ECDSA-P256 keys and uses SHA256 hashes, for both ephemeral keyless signing and managed key signing.
Keys are stored in PEM-encoded PKCS8 format.
However, you can use `cosign` to store and retrieve signatures in any format, from any algorithm.
### Things That Should Probably Change
#### Payload Formats
`cosign` only supports Red Hat's [simple signing](https://www.redhat.com/en/blog/container-image-signing)
format for payloads.
That looks like:
```json
{
"critical": {
"identity": {
"docker-reference": "testing/manifest"
},
"image": {
"Docker-manifest-digest": "sha256:20be...fe55"
},
"type": "cosign container image signature"
},
"optional": {
"creator": "Bob the Builder",
"timestamp": 1458239713
}
}
```
**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/notation/issues/40 for one option.
#### Registry Details
`cosign` signatures are stored as separate objects in the OCI registry, with only a weak
reference back to the object they "sign".
This means this relationship is opaque to the registry, and signatures *will not* be deleted
or garbage-collected when the image is deleted.
Similarly, they **can** easily be copied from one environment to another, but this is not
automatic.
Multiple signatures are stored in a list which is unfortunately a race condition today.
To add a signature, clients orchestrate a "read-append-write" operation, so the last write
will win in the case of contention.
Frequently Asked Questions
What is Cosign?
Cosign is a Zero Trust library for the Go programming language. Container Signing, Verification and Storage in an OCI registry
How many GitHub stars does Cosign have?
Cosign has 6,388 GitHub stars in the directory's latest synchronization.
How do I install Cosign?
Install Cosign with the Go module system using `go get sigstore/cosign`. Check the repository for the current installation instructions.
What category does Cosign belong to?
Cosign is listed under Zero Trust, specifically Zero Trust.