# Sign Docker Images with Docker Content Trust

**URL:** <https://discuss.circleci.com/t/sign-docker-images-with-docker-content-trust/40319>\
**Category:** Support Solutions\
**Tags:** docker\
**Created:** [June 8, 2021, 7:07pm UTC](https://discuss.circleci.com/t/sign-docker-images-with-docker-content-trust/40319 "2021-06-08T19:07:19Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![mike](https://sea2.discourse-cdn.com/circleci/user_avatar/discuss.circleci.com/mike/32/24230_2.png) [@mike](https://discuss.circleci.com/u/mike)\
**Post date:** [June 8, 2021, 7:07pm UTC](https://discuss.circleci.com/t/sign-docker-images-with-docker-content-trust/40319/1 "2021-06-08T19:07:19Z")

</div>

# Sign Docker Images with Docker Content Trust

[Docker Content Trust](https://docs.docker.com/engine/security/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.

### Requirements

1. This guide assumes the use of a [Machine Executor](https://circleci.com/docs/2.0/executor-types/#using-machine). A [Docker Executor](https://circleci.com/docs/2.0/executor-types/#using-docker) with [Remote Docker (setup\_remote\docker)](https://circleci.com/docs/2.0/building-docker-images/) could potentially be used as well with a few additional steps.
2. A valid [Dockerhub](https://hub.docker.com/) account
3. The following instructions assume the use of the default Dockerhub notary server at [https://notary.docker.io](https://notary.docker.io)

### Following the [official documentation](https://docs.docker.com/engine/security/trust/#signing-images-with-docker-content-trust), create and add delegation key pair

This step will contain an abridged version from the [official documention](https://docs.docker.com/engine/security/trust/#signing-images-with-docker-content-trust). It is recommended that all customers review and understand that documentation for creating and [managing their keys for content trust](https://docs.docker.com/engine/security/trust/trust_key_mng/).

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](https://docs.docker.com/engine/security/trust/) about securing and maintain the root key.

We’ll create the delegation key pair and make note of the location.

```auto
$ 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.

```auto
$ 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.

```auto
$ 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

```

### Store the delegation private key for use on CircleCI

Make use of the `base64` command to encode the private key to be stored as a [Project Environment Variable](https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-project) or in [Contexts](https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-context).

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 `role: circlecikey`.

```auto
base64 ~/.docker/trust/private/eef7c96f206094f178XXXXXXXXXXXXe77def77571b5889XXXXXXXXXXXXXX.key

```

We’ll copy that output and store that in either a [Project Environment Variable](https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-project) or in [Contexts](https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-context) with the name `DCT_KEY`

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 `DCT_HASH`.

### Store the delegation private key passphrase

Store the passphrase for the delegation private key in either a [Project Environment Variable](https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-project) or in [Contexts](https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-context) as `DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE`. This special environment variable is described in more detail in the [official documentation](https://docs.docker.com/engine/security/trust/trust_automation/).

### Store the Dockerhub username and password

Create and store environment variables in either a [Project Environment Variable](https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-project) or in [Contexts](https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-context) to log into Dockerhub. We’ll name those `DOCKER_USERNAME` and `DOCKER_PASSWORD` and they’ll hold the Dockerhub username and password.

### Example Job to build, push, and sign a tagged image

```auto
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

```

### Resources

You are highly encouraged to read the official documention:

> **[Content trust in Docker](https://docs.docker.com/engine/security/trust/)**
>
> Enabling content trust in Docker

[https://docs.docker.com/engine/security/trust/trust\_automation/](https://docs.docker.com/engine/security/trust/trust%5C_automation/)
