Docker Content Trust provides additional security when using and publishing Docker Images. In this article, we’ll make use of DCT to sign an image tag within a CircleCI job.
- This guide assumes the use of a Machine Executor. A Docker Executor with Remote Docker (setup_remote\docker) could potentially be used as well with a few additional steps.
- A valid Dockerhub account
- The following instructions assume the use of the default Dockerhub notary server at https://notary.docker.io
Following the official documentation, create and add delegation key pair
This step will contain an abridged version from the official documention. It is recommended that all customers review and understand that documentation for creating and managing their keys for content trust.
The following process assumes a root key has already been created. If you do not yet have a root key set up, you will be prompted to generate a new root key and set a passphrase. It is highly recommended that you review the official documentation about securing and maintain the root key.
We’ll create the delegation key pair and make note of the location.
$ mkdir dct $ cd dct $ docker trust key generate circlecikey Generating key for circlecikey... Enter passphrase for new circlecikey key with ID eef7c96: Repeat passphrase for new circlecikey key with ID eef7c96: Successfully generated and loaded private key. Corresponding public key available: /Users/example/dct/circlecikey.pub
Then add the delegation public key to the defaul Dockerhub notary server. Be sure to have the correct path to the public key file (*.pub). Replace examplenamespace and exampleimage with your namespace and image name. The process will ask for the password for the root key created earlier and then ask to create a new key password.
$ docker trust signer add --key circlecikey.pub circlecikey examplenamespace/examplenamespace Adding signer "examplesignername" to examplenamespace/exampleimage... Initializing signed repository for examplenamespace/exampleimage... Enter passphrase for root key with ID 63d2c1a: Enter passphrase for new repository key with ID 10a128a: Repeat passphrase for new repository key with ID 10a128a: Successfully initialized "examplenamespace/exampleimage" Successfully added signer: circlecikey to examplenamespace/exampleimage
We’ll then use the repository key passphrase created in the previous step to sign our image. Make sure the image tag has already been created. We’ll use the passphrase from the
key generate step when we generated the delegation key pair. This should sign and push the image and tag.
$ docker build . -t examplenamespace/exampleimage:0.1.0 [+] Building 0.1s (6/6) FINISHED ... $ docker trust sign examplenamespace/exampleimage:0.1.0 Signing and pushing trust data for local image examplenamespace/exampleimage:0.1.0, may overwrite remote trust data ... Signing and pushing trust metadata Enter passphrase for circlecikey key with ID eef7c96: Successfully signed docker.io/examplenamespace/exampleimage:0.1.0
The delegation private key will be stored by default in the
~/docker/trust/private directory. The filename will be the key hash with
.key as the filename extention. The 6 characters from the
docker trust key generate circleci step will be the the first six characters of the file name. In our case this was
eef7c9. The file contents will also contain
We’ll also create and store a second environment variable with the full hash as the private key name will need the same filename as we have locally. If the file is
~/.docker/trust/private/eef7c96f206094f178XXXXXXXXXXXXe77def77571b5889XXXXXXXXXXXXXX.key the hash would be
eef7c96f206094f178XXXXXXXXXXXXe77def77571b5889XXXXXXXXXXXXXX. For this example, the environment variable name should be
Store the passphrase for the delegation private key in either a Project Environment Variable or in Contexts as
DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE. This special environment variable is described in more detail in the official documentation.
Create and store environment variables in either a Project Environment Variable or in Contexts to log into Dockerhub. We’ll name those
DOCKER_PASSWORD and they’ll hold the Dockerhub username and password.
jobs: build-push-sign: machine: image: ubuntu-2004:202104-01 steps: - checkout - run: name: Build, push, and sign tagged image command: | # Make sure directory exists mkdir -p $HOME/.docker/trust/private # Decode and store signer key to file named as the key hash echo $DCT_KEY | base64 --decode > $HOME/.docker/trust/private/$DCT_HASH.key # Set required permissions level on key file chmod 600 $HOME/.docker/trust/private/$KEY_HASH.key # Build image docker build . -t examplenamespace/exampleimage:0.1.0 # Tag image docker tag hello-world examplenamespace/exampleimage:0.1.0 # Log into docker echo "$DOCKER_PASSWORD" | docker login --username $DOCKER_USERNAME --password-stdin # Load key for signing docker trust key load $HOME/.docker/trust/private/$KEY_HASH.key --name circlecikey # Sign docker trust sign examplenamespace/exampleimage:0.1.0 # Push docker push examplenamespace/exampleimage:0.1.0 # Verify signature docker trust inspect --pretty examplenamespace/exampleimage:0.1.0
You are highly encouraged to read the official documention: