Signing
The general signing format with the cosign sign
command is as follows.
$ cosign sign --key <key path>|<kms uri> [--payload <path>] [-a key=value] [--upload=true|false] [-f] [-r] <image uri>
We'll use user/demo
as our example image in the following commands.
Sign with a local key pair
This usage is a common use case that uses traditional key signing from a key pair.
$ cosign sign --key cosign.key user/demo
If you need to generate local keys, you can do so by running cosign generate-key-pair
.
Keyless signing
You can use Cosign to sign without keys by authenticating with an OIDC (OpenID Connect) protocol supported by Sigstore. Currently, you can authenticate with Google, GitHub, or Microsoft.
$ COSIGN_EXPERIMENTAL=1 cosign sign user/demo
This will open a browser window to authenticate your credentials for the signature.
Sign a container multiple times
Multiple signatures can be "attached" to a single container image:
$ cosign sign --key cosign.key user/demo
Enter password for private key:
Pushing signature to: index.docker.io/user/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8.sig
$ cosign sign --key other.key user/demo
Enter password for private key:
Pushing signature to: index.docker.io/user/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8.sig
This only signs the digest, but you can pass by tag or digest.
Add annotations with a signature
The -a
flag can be used to add annotations to the generated, signed payload.
This flag can be repeated:
$ cosign sign --key other.key -a foo=bar user/demo
Enter password for private key:
Pushing signature to: index.docker.io/user/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8.sig
These values are included in the signed payload under the Optional
section.
"Optional":{"baz":"bat","foo":"bar"}
They can be verified with the -a
flag as part of the cosign verify
command.
Sign and attach a certificate and certificate chain
You can sign a container and attach an existing certificate and certificate chain to an image. Note that you cannot currently generate a certificate chain but can use an existing chain.
$ cosign sign --key cosign.key --cert cosign.crt --cert-chain chain.crt user/demo
Sign with a key pair stored elsewhere
Cosign can use environment variables and KMS (Key Management Service) APIs, in addition to fixed keys.
When referring to a key managed by a KMS provider, cosign
takes a go-cloud style URI to refer to the specific provider. The URI path syntax is provider specific.
$ cosign sign --key <some provider>://<some key> gcr.io/user-vmtest2/demo
Pushing signature to: gcr.io/user-vmtest2/demo:sha256-410a07f17151ffffb513f942a01748dfdb921de915ea6427d61d60b0357c1dcd.cosign
Read more about this in our KMS Support page.
Key stored in an environment variable
$ cosign sign --key env://[ENV_VAR] user/demo
Key stored in Azure Key Vault
$ cosign sign --key azurekms://[VAULT_NAME][VAULT_URI]/[KEY] user/demo
Key stored in AWS KMS
$ cosign sign --key awskms://[ENDPOINT]/[ID/ALIAS/ARN] user/demo
Key stored in Google Cloud KMS
$ cosign sign --key gcpkms://projects/[PROJECT]/locations/global/keyRings/[KEYRING]/cryptoKeys/[KEY]/versions/[VERSION] user/demo
Key stored in Hashicorp Vault
$ cosign sign --key hashivault://[KEY] user/demo
Key stored in a Kubernetes secret
$ cosign sign --key k8s://[NAMESPACE]/[KEY] user/demo
Sign and upload a generated payload (in another format, from another tool)
The payload must be specified as a path to a file.
$ cosign sign --key cosign.key --payload README.md user/demo
Using payload from: README.md
Enter password for private key:
Pushing signature to: index.docker.io/user/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8.sig
You can also sign with another tool.
Cosign uses standard PKIX cryptographic formats, here's a full example with openssl
:
# Generate a keypair
$ openssl ecparam -name prime256v1 -genkey -noout -out openssl.key
$ openssl ec -in openssl.key -pubout -out openssl.pub
# Generate the payload to be signed
$ cosign generate us.gcr.io/user-vmtest2/demo > payload.json
# Sign it and convert to base64
$ openssl dgst -sha256 -sign openssl.key -out payload.sig payload.json
$ cat payload.sig | base64 > payloadbase64.sig
# Upload the signature
$ cosign attach signature --payload payload.json --signature payloadbase64.sig us.gcr.io/user-vmtest2/demo
# Verify!
$ cosign verify --key openssl.pub us.gcr.io/user-vmtest2/demo
Verification for us.gcr.io/user-vmtest2/demo --
The following checks were performed on each of these signatures:
- The cosign claims were validated
- The signatures were verified against the specified public key
- Any certificates were verified against the Fulcio roots.
{"critical":{"identity":{"docker-reference":"us.gcr.io/user-vmtest2/demo"},"image":{"docker-manifest-digest":"sha256:124e1fdee94fe5c5f902bc94da2d6e2fea243934c74e76c2368acdc8d3ac7155"},"type":"cosign container image signature"},"optional":null}
Sign but skip upload (to store somewhere else)
The upload is skipped by using the --upload=false
flag (default true). To capture the output use the --output-signature FILE
and/or --output-certificate FILE
flags.
$ cosign sign --key key.pem --upload=false --output-signature demo.sig --output-certificate demo.crt user/demo
Generate the signature payload (to sign with another tool)
The json payload is printed to stdout:
$ cosign generate user/demo
{"Critical":{"Identity":{"docker-reference":""},"Image":{"Docker-manifest-digest":"87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8"},"Type":"cosign container image signature"},"Optional":null}
This can be piped directly into OpenSSL.
$ cosign generate user/demo | openssl...
Upload a generated signature
The signature is passed via the --signature
flag.
It can be a file:
$ cosign attach signature --signature file.sig user/demo
Pushing signature to: user/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8.sig
The base64-encoded signature:
$ cosign attach signature --signature Qr883oPOj0dj82PZ0d9mQ2lrdM0lbyLSXUkjt6ejrxtHxwe7bU6Gr27Sysgk1jagf1htO/gvkkg71oJiwWryCQ== user/demo
Pushing signature to: user/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def.sig
Or, -
for stdin
for chaining from other commands:
$ cosign generate user/demo | openssl... | cosign attach signature --signature -- user/demo
Pushing signature to: user/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def.sig
Signature location and management
Signatures are uploaded to an OCI artifact stored with a predictable name.
This name can be located with the cosign triangulate
command:
$ cosign triangulate user/demo
index.docker.io/user/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8.sig
They can be reviewed with crane
:
$ crane manifest $(cosign triangulate gcr.io/user-vmtest2/demo) | jq .
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 342,
"digest": "sha256:f5de0db6e714055d48b4bb3a374e9630c4923fa704d9311da6a2740cf625aaba"
},
"layers": [
{
"mediaType": "application/vnd.dev.cosign.simplesigning.v1+json",
"size": 210,
"digest": "sha256:1119abab63e605dcc281019bad0424744178b6f61ba57378701fe7391994c999",
"annotations": {
"dev.cosignproject.cosign/signature": "MEUCIG0ZmgqE3qTrHWp+HF9CrxsNH57Cck3cQI+zNNrUwSHfAiEAm+2eY/Z6ixQwjLbTraDN5ZB/P1Z5k/KwIoblry65r+s="
}
},
{
"mediaType": "application/vnd.dev.cosign.simplesigning.v1+json",
"size": 219,
"digest": "sha256:583246418c2afd5bfe29694793d07da37ffd552aadf8879b1d98047178b80398",
"annotations": {
"dev.cosignproject.cosign/signature": "MEUCIF/+szLKKA2q2+c86AXeWR7UeD5yYpW7p0waHordxNjhAiEAm5e+Hm7Jhv9JpSwHpTc6aGLSkL6/Acm/z+b8mhfGXqY="
}
}
]
}
Some registries support deletion too (DockerHub does not):
$ cosign clean gcr.io/user-vmtest2/demo