Signy is an experimental tool that implements the CNAB Security specification. It implements signing and verifying for CNAB bundles in the canonical formats (thin and thick bundles). As an added feature, it also supports pushing and pulling of container images alongside in-toto metadata with the signy image
command.
- the CNAB security specification uses TUF as a protocol for distributing trust metadata about bundles. This implementation uses Notary, a Go implementation of the TUF specification.
- this project has been tested using the open source Notary and Docker distribution.
- currently, the in-toto signing key for the root layout is passed in the TUF
custom
object. This invalidates the security model, and the priority is to move the distribution of that key out of bound (possibly using a TUF signing key - targets, for example). - if pushing in-toto metadata, this tool assumes the in-toto metadata has already been generated using a different workflow.
- authentication currently has some transient issues. For now, it is best to use a local registry and trust server (see instructions below).
$ cd $GOPATH/src/github.com
$ mkdir cnabio && cd cnabio && git clone https://github.com/cnabio/signy && cd signy
$ make bootstrap build
$ mv bin/signy $GOPATH/bin
- Run local Docker Distribution and Notary services:
# Setup Docker Distribution and Notary.
$ ./scripts/bootstrap.sh
# Start Docker Distribution and Notary.
$ ./scripts/signy-start.sh
- Before running Signy, test pushing and pulling from local registry and Notary server:
# Push a signed hello-world image.
$ ./scripts/docker-push.sh
# Pull the signed hello-world image.
$ ./scripts/docker-pull.sh
At this point, Signy can be used by passing the Notary CA and URL to the trust server:
$ signy --tlscacert=$NOTARY_CA --server https://localhost:4443
- Computing the SHA256 digest of a canonical CNAB bundle, pushing it to the trust server, then pushing the bundle using
cnab-to-oci
:
$ ./scripts/signy-sign.sh testdata/cnab/bundle.json localhost:5000/cnab/thin-bundle:v1
INFO[0000] Starting to copy image cnab/helloworld:0.1.1
INFO[0000] Completed image cnab/helloworld:0.1.1 copy
INFO[0000] Generated relocation map: relocation.ImageRelocationMap{"cnab/helloworld:0.1.1":"localhost:5000/cnab/thin-bundle@sha256:a59a4e74d9cc89e4e75dfb2cc7ea5c108e4236ba6231b53081a9e2506d1197b6"}
INFO[0000] Pushed successfully, with digest "sha256:b4936e42304c184bafc9b06dde9ea1f979129e09a021a8f40abc07f736de9268"
INFO[0000] Pushed trust data for localhost:5000/cnab/thin-bundle:v1: c7e92bd51f059d60b15ad456edf194648997d739f60799b37e08edafd88a81b5
- Verifying the metadata in the trusted collection for a CNAB bundle against the bundle pushed to an OCI registry
$ ./scripts/signy-verify.sh localhost:5000/cnab/thin-bundle:v1
INFO[0000] Pulled trust data for localhost:5000/thin-bundle:v1, with role targets - SHA256: c7e92bd51f059d60b15ad456edf194648997d739f60799b37e08edafd88a81b5
INFO[0000] Pulling bundle from registry: localhost:5000/thin-bundle:v1
INFO[0000] Computed SHA: c7e92bd51f059d60b15ad456edf194648997d739f60799b37e08edafd88a81b5
INFO[0000] The SHA sums are equal: c7e92bd51f059d60b15ad456edf194648997d739f60799b37e08edafd88a81b5
- Listing the targets for a trusted collection:
$ ./scripts/signy-list.sh
0.1.1 d9dfd104723ea5b037000931a876e98e5e0bf492d665436d123d0dfc7c40c8e8
- Computing the SHA256 digest of a thick bundle, then pushing it to a trust sever
$ signy --tlscacert=$NOTARY_CA --server https://localhost:4443 sign --thick testdata/cnab/helloworld-0.1.1.tgz localhost:5000/thick-bundle:v1
INFO[0000] Pushed trust data for localhost:5000/thick-bundle:v1: 540cc4dc213548ebbdffb2ab0ef58729e089d1887edbcde6eeca851de624da70
- Verifying the metadata for a local thick bundle
$ signy --tlscacert=$NOTARY_CA --server https://localhost:4443 verify --thick --local testdata/cnab/helloworld-0.1.1.tgz localhost:5000/thick-bundle:v1
INFO[0000] Pulled trust data for localhost:5000/thick-bundle:v1, with role targets - SHA256: 540cc4dc213548ebbdffb2ab0ef58729e089d1887edbcde6eeca851de624da70
INFO[0000] Computed SHA: 540cc4dc213548ebbdffb2ab0ef58729e089d1887edbcde6eeca851de624da70
INFO[0000] The SHA sums are equal: 540cc4dc213548ebbdffb2ab0ef58729e089d1887edbcde6eeca851de624da70
- Add in-toto metadata when signing a thin bundle:
$ ./scripts/signy-sign.sh testdata/cnab/bundle.json localhost:5000/thin-intoto:v2 --in-toto --layout testdata/intoto/root.layout --links testdata/intoto --layout-key testdata/intoto/alice.pub
INFO[0000] Adding In-Toto layout and links metadata to TUF
INFO[0000] Pushed trust data for localhost:5000/thin-intoto:v2: c7e92bd51f059d60b15ad456edf194648997d739f60799b37e08edafd88a81b5
INFO[0000] Starting to copy image cnab/helloworld:0.1.1
INFO[0001] Completed image cnab/helloworld:0.1.1 copy
INFO[0001] Generated relocation map: relocation.ImageRelocationMap{"cnab/helloworld:0.1.1":"localhost:5000/thin-intoto@sha256:a59a4e74d9cc89e4e75dfb2cc7ea5c108e4236ba6231b53081a9e2506d1197b6"}
INFO[0001] Pushed successfully, with digest "sha256:b4936e42304c184bafc9b06dde9ea1f979129e09a021a8f40abc07f736de9268"
- verifying the signature of a thin bundle and running the in-toto verifications in a container:
$ ./scripts/signy-verify.sh localhost:5000/thin-intoto:v2 --in-toto
INFO[0000] Pulled trust data for localhost:5000/thin-intoto:v2, with role targets - SHA256: c7e92bd51f059d60b15ad456edf194648997d739f60799b37e08edafd88a81b5
INFO[0000] Pulling bundle from registry: localhost:5000/thin-intoto:v2
INFO[0000] Computed SHA: c7e92bd51f059d60b15ad456edf194648997d739f60799b37e08edafd88a81b5
INFO[0000] The SHA sums are equal: c7e92bd51f059d60b15ad456edf194648997d739f60799b37e08edafd88a81b5
INFO[0000] Writing In-Toto metadata files into /tmp/intoto-verification169227773
INFO[0000] copying file /in-toto/layout.template in container for verification...
INFO[0000] copying file /in-toto/key.pub in container for verification...
INFO[0000] copying file in-toto/package.2f89b927.link in container for verification...
INFO[0000] copying file in-toto/write-code.776a00e2.link in container for verification...
INFO[0000] copying file in-toto/foo.tar.gz in container for verification...
INFO[0000] Loading layout...
INFO[0000] Loading layout key(s)...
INFO[0000] Verifying layout signatures...
INFO[0001] Verifying layout expiration...
INFO[0001] Reading link metadata files...
INFO[0001] Verifying link metadata signatures...
INFO[0001] Verifying sublayouts...
INFO[0001] Verifying alignment of reported commands...
INFO[0001] Verifying command alignment for 'write-code.776a00e2.link'...
INFO[0001] Verifying command alignment for 'package.2f89b927.link'...
INFO[0001] Verifying threshold constraints...
INFO[0001] Skipping threshold verification for step 'write-code' with threshold '1'...
INFO[0001] Skipping threshold verification for step 'package' with threshold '1'...
INFO[0001] Verifying Step rules...
INFO[0001] Verifying material rules for 'write-code'...
INFO[0001] Verifying product rules for 'write-code'...
INFO[0001] Verifying 'ALLOW foo.py'...
INFO[0001] Verifying material rules for 'package'...
INFO[0001] Verifying 'MATCH foo.py WITH PRODUCTS FROM write-code'...
INFO[0001] Verifying 'DISALLOW *'...
INFO[0001] Verifying product rules for 'package'...
INFO[0001] Verifying 'ALLOW foo.tar.gz'...
INFO[0001] Verifying 'ALLOW foo.py'...
INFO[0001] Executing Inspection commands...
INFO[0001] Executing command for inspection 'untar'...
INFO[0001] Running 'untar'...
INFO[0001] Recording materials '.'...
INFO[0001] Running command 'tar xfz foo.tar.gz'...
INFO[0001] Recording products '.'...
INFO[0001] Creating link metadata...
INFO[0001] Verifying Inspection rules...
INFO[0001] Verifying material rules for 'untar'...
INFO[0001] Verifying 'MATCH foo.tar.gz WITH PRODUCTS FROM package'...
INFO[0001] Verifying 'DISALLOW foo.tar.gz'...
INFO[0001] Verifying product rules for 'untar'...
INFO[0001] Verifying 'MATCH foo.py WITH PRODUCTS FROM write-code'...
INFO[0001] Verifying 'DISALLOW foo.py'...
INFO[0001] The software product passed all verification.
- similarly for a thick bundle:
$ signy --tlscacert=$NOTARY_CA --server https://localhost:4443 sign testdata/cnab/helloworld-0.1.1.tgz --thick localhost:5000/thick-bundle-signature:v2 --in-toto --layout testdata/intoto/root.layout --links testdata/intoto --layout-key testdata/intoto/alice.pub
INFO[0000] Adding In-Toto layout and links metadata to TUF
INFO[0000] Pushed trust data for localhost:5000/thick-bundle-signature:v2: 540cc4dc213548ebbdffb2ab0ef58729e089d1887edbcde6eeca851de624da70
$ signy --tlscacert=$NOTARY_CA --server https://localhost:4443 verify localhost:5000/thick-bundle-signature:v2 --thick --local testdata/cnab/helloworld-0.1.1.tgz --in-toto
Notes:
- see current limitations about the in-toto signing key of the root layout
signy --tlscacert root-ca.crt image push -i [image]
This command is nearly identical to the docker CLI command docker push
when the environment variable DOCKER_CONTENT_TRUST=1
and DOCKER_CONTENT_TRUST_SERVER=[server:4443]
are set. In addition to signing the digest, we require in-toto metadata to push to the trust server. Unlike signy sign
where the in-toto metadata is optional, it is required for signy push
.
-h, --help help for push
-i, --image string container image to push (must be built on your local system)
--layout string Path to the in-toto root layout file (default "intoto/root.layout")
--layout-key string Path to the in-toto root layout public keys (default "intoto/root.pub")
--links string Path to the in-toto links directory (default "intoto/")
--registryCredentials string docker registry credentials (api key or password), uses the PUSH_REGISTRY_CREDENTIALS environment variable
--registryUser string docker registry user, also uses the PUSH_REGISTRY_USER environment variable
To pull an image and verify its digest SHA and in-toto metadata:
`signy --tlscacert root-ca.crt image pull -i [image]`
This will pull the image from the registry, verify its digest against what is stored in TUF/Notary, and verify the in-toto metadata that was pulled down from TUF/Notary.
TODO - signy image
:
- Currently signy image pull
copies all files from the current directory into the in-toto temp directory for verification. For most in-toto proof-of-concepts, a .tgz or .tar file is typically used. This was an easy way to get those files in for verification.
- Have an option to pull the in-toto metadata to a different directory.
- Provide a better way to docker login
. Currently you must provide a login to the registry as a command line param or as environment variables "PUSH_REGISTRY_USER" and "PUSH_REGISTRY_CREDENTIALS". Look into how docker push
does this.
- The image is pulled prior to testing the digest against the digest in Notary and prior to the in-toto verify. If the verify fails, we do not remove the image.
- Only does VerifyOnOS. Should add VerifyInContainer like signy verify
does.
### Tearing down
- Stop all services:
```bash
./scripts/stop.sh
On the first push to a repository, Signy generates the signing keys (using Notary). To avoid introducing the passphrases every time, set the following environment variables with the corresponding passphrases:
$ export SIGNY_ROOT_PASSPHRASE=PassPhrase#123
$ export SIGNY_TARGETS_PASSPHRASE=PassPhrase#123
$ export SIGNY_RELEASES_PASSPHRASE=PassPhrase#123
This project welcomes all contributions. See the issue queue for existing issues, and make sure to also check the CNAB Security specification.