Sign an imageEstimated reading time: 5 minutes
By default, when you push an image to DTR, the Docker CLI client doesn’t sign the image.
You can configure the Docker CLI client to sign the images you push to DTR. This allows whoever pulls your image to validate if they are getting the image you created, or a forged one.
To sign an image you can run:
export DOCKER_CONTENT_TRUST=1 docker push <dtr-domain>/<repository>/<image>:<tag>
This pushes the image to DTR and creates trust metadata. It also creates public and private key pairs to sign the trust metadata, and push that metadata to the Notary Server internal to DTR.
Sign images that UCP can trust
With the command above you’ll be able to sign your DTR images, but UCP won’t trust them because it can’t tie the private key you’re using to sign the images to your UCP account.
To sign images in a way that UCP trusts them you need to:
- Configure your Notary client
- Initialize trust metadata for the repository
- Delegate signing to the keys in your UCP client bundle
In this example we’re going to pull an NGINX image from Docker Store,
re-tag it as
dtr.example.org/dev/nginx:1, push the image to DTR and sign it
in a way that is trusted by UCP. If you manage multiple repositories, you’ll
have to do the same procedure for every one of them.
Configure your Notary client
Start by configuring your Notary client. This ensures the Docker and Notary CLI clients know about your UCP private keys.
Initialize the trust metadata
Then you need to initialize the trust metadata for the new repository, and
the easiest way to do it is by pushing an image to that repository. Navigate to
the DTR web UI, and create a repository for your image.
In this example we’ve created the
From the Docker CLI client, pull an NGINX image from Docker Store, re-tag it, sign and push it to DTR.
# Pull NGINX from Docker Store docker pull nginx:latest # Re-tag NGINX docker tag nginx:latest dtr.example.org/dev/nginx:1 # Log into DTR docker login dtr.example.org # Sign and push the image to DTR export DOCKER_CONTENT_TRUST=1 docker push dtr.example.org/dev/nginx:1
This pushes the image to DTR and initializes the trust metadata for that repository.
DTR shows that the image is signed, but UCP won’t trust the image because it doesn’t have any information about the private keys used to sign the image.
Delegate trust to your UCP keys
To sign images in a way that is trusted by UCP, you need to delegate trust, so that you can sign images with the private keys in your UCP client bundle.
When delegating trust you associate a public key certificate with a role name. UCP requires that you delegate trust to two different roles:
<role>is the UCP team the user belongs to
In this example we’ll delegate trust to
# Delegate trust, and add that public key with the role targets/releases notary delegation add --publish \ dtr.example.org/dev/nginx targets/releases \ --all-paths <ucp-cert.pem> # Delegate trust, and add that public key with the role targets/admin notary delegation add --publish \ dtr.example.org/dev/nginx targets/admin \ --all-paths <ucp-cert.pem>
To push the new signing metadata to the Notary server, you’ll have to push the image again:
docker push dtr.example.org/dev/nginx:1
Under the hood
Both Docker and Notary CLI clients interact with the Notary server to:
- Keep track of the metadata of signed images
- Validate the signatures of the images you pull
This metadata is also kept locally in
. |-- private | |-- root_keys | | `-- 993ad247476da081e45fdb6c28edc4462f0310a55da4acf1e08404c551d94c14.key | `-- tuf_keys | `-- dtr.example.org | `-- dev | `-- nginx | |-- 98a93b2e52c594de4d13d7268a4a5f28ade5fc1cb5f44cc3a4ab118572a86848.key | `-- f7917aef77d0d4bf8204af78c0716dac6649346ebea1c4cde7a1bfa363c502ce.key `-- tuf `-- dtr.example.org `-- dev `-- nginx |-- changelist `-- metadata |-- root.json |-- snapshot.json |-- targets.json `-- timestamp.json
private directory contains the private keys the Docker CLI client uses
to sign the images. Make sure you create backups of this directory so that
you don’t lose your signing keys.
The Docker and Notary CLI clients integrates with Yubikey. If you have a Yubikey
plugged in when initializing trust for a repository, the root key is stored on
the Yubikey instead of in the trust directory.
When you run any command that needs the
root key, Docker and Notary CLI
clients look on the Yubikey first, and uses the trust directory as a fallback.
tuf directory contains the trust metadata for the images you’ve
signed. For each repository there are four files.
||Has data about other keys and their roles. This data is signed by the root key.|
||Has data about the digest and size for an image. This data is signed by the target key.|
||Has data about the version number of the root.json and targets.json files. This data is signed by the snapshot key.|
||Has data about the digest, size, and version number for the snapshot.json file. This data is signed by the timestamp key.|