# cosign
Container Signing, Verification and Storage in an OCI registry.
Cosign aims to make signatures **invisible infrastructure**.

## Info
`Cosign` is developed as part of the [`sigstore`](https://sigstore.dev) project.
We also use a slack [slack channel](https://sigstore.slack.com)!
Click [here](https://join.slack.com/t/sigstore/shared_invite/zt-mhs55zh0-XmY3bcfWn4XEyMqUUutbUQ) for the invite link.
## Installation
For now, clone and `go build -o cosign ./cmd`.
I'll publish releases when I'm comfortable supporting this for others to use.
## Quick Start
This shows how to:
* generate a keypair
* sign a container image and store that signature in the registry
* find signatures for a container image, and verify them against a public key
See the [Usage documentation](USAGE.md) for more commands!
### Generate a keypair
```
$ cosign generate-key-pair
Enter password for private key:
Enter again:
Private key written to cosign.key
Public key written to cosign.key
```
### Sign a container and store the signature in the registry
```
$ cosign sign -key cosign.key dlorenc/demo
Enter password for private key:
Pushing signature to: index.docker.io/dlorenc/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8.cosign
```
### 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.
```
$ cosign verify -key cosign.pub dlorenc/demo
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 signature"},"Optional":null}
```
## Detailed Usage
See the [Usage documentation](USAGE.md) for more commands!
## Rekor Support
_Note: this is an experimental feature_
To publish signed artifacts to a Rekor transparency log and verify their existence in the log, set the `TLOG=1` environment variable.
```
TLOG=1 cosign sign -key cosign.key dlorenc/demo
TLOG=1 cosign verify -key cosign.pub dlorenc/demo
```
`cosign` defaults to using the public instance of rekor at [api.rekor.dev](https://api.rekor.dev).
To configure the rekor server, set the `REKOR_SERVER` env variable.
## Caveats
### Intentionally Missing Features
`cosign` only generates ECDSA-P256 keys and uses SHA256 hashes.
Keys are stored in PEM-encoded PKCS8 format.
However, you can use `cosign` to store and retrieve signatures in any format, from any algorithm.
`cosign` does not handle key-distribution or PKI.
`cosign` does not handle expiry or revocation.
See [here](https://github.com/notaryproject/requirements/pull/47) for some discussion on the topic.
`cosign` does not handle public-key management or storage.
There are no keyrings or local state.
### Unintentionally Missing Features
`cosign` will integrate with transparency logs!
See https://github.com/sigstore/cosign/issues/34 for more info.
`cosign` will integrate with even more transparency logs, and a PKI.
See https://github.com/sigStore/fulcio for more info.
### Registry Support
`cosign` uses [go-containerregistry](github.com/google/go-containerregistry) for registry
interactions, which has excellent support, but other registries may have quirks.
Today, `cosign` has only been tested, barely, against GCP's Artifact Registry and Container Registry and DockerHub.
We aim for wide registry support.
Please help test!
See https://github.com/sigstore/cosign/issues/40 for the tracking issue.
### 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:
```
{
"critical": {
"identity": {
"docker-reference": "testing/manifest"
},
"image": {
"Docker-manifest-digest": "sha256:20be...fe55"
},
"type": "cosign container signature"
},
"optional": {
"creator": "atomic",
"timestamp": 1458239713
}
}
```
**Note:** This can be generated for an image reference using `cosign generate <image>`.
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.
#### 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 "racy" today.
To add a signtaure, clients orchestrate a "read-append-write" operation, so the last write
will win in the case of contention.
## Signature Specification
`cosign` is inspired by tools like [minisign](https://jedisct1.github.io/minisign/) and
[signify](https://www.openbsd.org/papers/bsdcan-signify.html).
Generated private keys are stored in PEM format.
The keys encrypted under a password using scrypt as a KDF and nacl/secretbox for encryption.
They have a PEM header of `ENCRYPTED COSIGN PRIVATE KEY`:
```
-----BEGIN ENCRYPTED COSIGN PRIVATE KEY-----
...
-----END ENCRYPTED COSIGN PRIVATE KEY-----
```
Public keys are stored on disk in PEM-encoded standard PKIX format with a header of `PUBLIC KEY`.
```
-----BEGIN PUBLIC KEY-----
NqfC4CpZiE4OGpuYFSSMzXHJqXQ6u1W55prrZIjjZJ0=
-----END PUBLIC KEY-----
```
The inner (base64 encoded) data portion can be supplied directly on the command line without the PEM blocks:
```
$ cosign verify -key NqfC4CpZiE4OGpuYFSSMzXHJqXQ6u1W55prrZIjjZJ0= us-central1-docker.pkg.dev/dlorenc-vmtest2/test/taskrun
```
## Storage Specification
`cosign ` stores signatures in an OCI registry, and uses a naming convention (tag based
on the sha256 of what we're signing) for locating the signature index.
<p align="center">
</p>
`reg.example.com/ubuntu@sha256:703218c0465075f4425e58fac086e09e1de5c340b12976ab9eb8ad26615c3715` has signatures located at `reg.example.com/ubuntu:sha256-703218c0465075f4425e58fac086e09e1de5c340b12976ab9eb8ad26615c3715`
Roughly (ignoring ports in the hostname): `s/:/-/g` and `s/@/:/g` to find the signature index.
See [Race conditions](#race-conditions) for some caveats around this strategy.
Alternative implementations could use transparency logs, local filesystem, a separate repository
registry, an explicit reference to a signature index, a new registry API, grafeas, etc.
### Signing subjects
`cosign` only works for artifacts stored as "manifests" in the registry today.
The proposed mechanism is flexible enough to support signing arbitrary things.
## FAQ
### Who is using this?
Hopefully no one yet. Stay tuned, though.
### Why not use Notary v2
### Why not use containers/image signing
`containers/image` signing is close to `cosign`, and we reuse payload formats.
`cosign` differs in that it signs with ECDSA-P256 keys instead of PGP, and stores
signatures in the registry.
### Why not use TUF?
I believe this tool is complementary to TUF, and they can be used together.
I haven't tried yet, but think we can also reuse a registry for TUF storage.
### Why not use Blockchain?
Just kidding. Nobody actually asked this. Don't be that person.
### Why not use $FOO?
See the next section, [Req