Skip to content

Latest commit

 

History

History
executable file
·
399 lines (281 loc) · 16.5 KB

5-content-trust.md

File metadata and controls

executable file
·
399 lines (281 loc) · 16.5 KB

Lab 5 : Docker Content Trust

Difficulty: Magic

Time: 20 minutes

Tasks:

What is Docker Content Trust?

Content trust allows image operations with a remote Docker registry to enforce client-side signing and verification of image tags. Content trust enables digital signatures for data sent to and received from remote Docker registries. These signatures allow Docker client-side interfaces to verify the integrity and publisher of specific image tags.

Image publishers can sign their images. Image consumers can ensure that the images they use are signed. Both publishers and consumers can be either individuals or organizations. Docker’s content trust supports users and automated processes pipelines.

Docker Content Trust works with Docker Hub as well as Docker Trusted Registry (with Notary integration experimental feature in 1.4).

Prerequisites

  • You will be using node-0
  • An existing Docker Hub account
  • SSH onto the provided <username>-node-0 instance in AWS
  • Logged into Docker Hub with the Docker client

Task 1: Create a new Docker Hub repository

Before you enable Docker Content Trust, you must create a new temporary repository on Docker Hub. You'll use this temporary repository for the lab.

  1. Log into your node-0 instance.

  2. Use the Docker command-line client to log into Docker Hub.

     $ docker login
     Username: <username>
     Password: <password>
     Email: <email>
     WARNING: login credentials saved in /home/ubuntu/.docker/config.json
     Login Succeeded
    
  3. Pull the busybox image:

     $ docker pull busybox
    
  4. Create a new tag for the busybox image using your namespace.

Your Docker Hub account is your namespace.

    $ docker tag busybox <username>/dctrust:latest
  1. Push this unsigned image to Docker Hub:

     $ docker push <username>/dctrust:latest
    
  2. Open <a href="https://hub.docker.com target="_blank">Docker Hub in your browser and login.

At this point you should have a new unsigned image repository dctrust (with the latest tag) under your Docker Hub account.

On Docker Hub

Task 2: Enable Content Trust

Currently, content trust is disabled by default. To enable it, set the DOCKER_CONTENT_TRUST environment variable in your environment as follows:

$ export DOCKER_CONTENT_TRUST=1

Once you set this environment variable, every Docker operation is secure. Any future Docker commands executed based on signatures.

Now that you've enabled content trust, try to pull the image you just pushed.

$ docker pull <username>/dctrust:latest
no trust data available

You'll notice that the Docker client did not pull the image. This is because the image was not signed.

Task 3: Push a signed image

To create the trust data for an image, you need push an image with DOCKER_CONTENT_TRUST enabled. The first push of your new image, Docker prompts for two new passphrases for a root key and a repository key.

  1. Create a new tag for the busybox image:

     $ docker tag busybox <username>/dctrust:signed
    
  2. Push the image making sure to enter two new passphrases when prompted.

     $ docker push <username>/dctrust:signed
    

Example output:

    $ docker push kizbitz/dctrust:signed
    The push refers to a repository [docker.io/kizbitz/dctrust] (len: 1)
    2c5ac3f849df: Image already exists
    ab2b8a86ca6c: Image already exists
    signed: digest: sha256:b33669e38aef420ff10d4787c07afe11a679564f65c31bde39572c9196f3e143 size: 3214
    Signing and pushing trust metadata
    You are about to create a new root signing key passphrase. This passphrase
    will be used to protect the most sensitive key in your signing system. Please
    choose a long, complex passphrase and be careful to keep the password and the
    key file itself secure and backed up. It is highly recommended that you use a
    password manager to generate the passphrase and keep it safe. There will be no
    way to recover this key. You can find the key in your config directory.
    Enter passphrase for new root key with id 020aa4f:
    Repeat passphrase for new root key with id 020aa4f:
    Enter passphrase for new repository key with id docker.io/kizbitz/dctrust (ab6b057):
    Repeat passphrase for new repository key with id docker.io/kizbitz/dctrust (ab6b057):
    Finished initializing "docker.io/kizbitz/dctrust"

Task 4: Pulling images

At this point in your Docker hub repository you have two different images/tags:

Image Description
dctrust:latest This image is still unsigned and cannot be pulled when content trust is enabled.
dctrust:signed This image is signed and can be pulled if content trust is enabled or disabled.

At this point, you have trust enabled.

  1. Pull the latest image and then the signed image.

     $ docker pull kizbitz/dctrust:latest
     No trust data for latest
     ubuntu@node-0:~$ docker pull kizbitz/dctrust:signed
     Pull (1 of 1): kizbitz/dctrust:signed@sha256:b33669e38aef420ff10d4787c07afe11a679564f65c31bde39572c9196f3e143
     sha256:b33669e38aef420ff10d4787c07afe11a679564f65c31bde39572c9196f3e143: Pulling from kizbitz/dctrust
     Digest: sha256:b33669e38aef420ff10d4787c07afe11a679564f65c31bde39572c9196f3e143
     Status: Downloaded newer image for kizbitz/dctrust@sha256:b33669e38aef420ff10d4787c07afe11a679564f65c31bde39572c9196f3e143
     Tagging kizbitz/dctrust@sha256:b33669e38aef420ff10d4787c07afe11a679564f65c31bde39572c9196f3e143 as kizbitz/dctrust:signed
    
  2. Now pull images but temporarily disable content trust with the --disable-content-trust flag.

     $ docker pull --disable-content-trust kizbitz/dctrust:latest
     latest: Pulling from kizbitz/latest
     Digest: sha256:f3fefef65b040546adab73e2e6a624376373b0f12e83a5e5a921d9cd9059953c
     Status: Image is up to date for kizbitz/dctrust:latest
     $ docker pull --disable-content-trust kizbitz/dctrust:signed
     signed: Pulling from kizbitz/dctrust
     Digest: sha256:357cb702777f1bdf9a6241e8cf9d17b05d30fc203e7e4e51464a067e826c7906
     Status: Downloaded newer image for kizbitz/dctrust:signed
    

Task 5: Docker Content Trust with Yubikey

Please Note: This task can only be completed on Mac/Linux machines. All the following steps will be completed from the local Docker Toolbox (DockerCon edition) and NOT from your EC2 instances. This task requires a Yubikey 4 (Edge/Neo will not work). lsusb can tell you about which version you have. In order for this tutorial to work the output should include:

$ lsusb | grep Yubikey
Bus 020 Device 031: ID 1050:0406 1050 Yubikey 4 U2F+CCID

In this task, you will use the Yubikey to sign an image and push it to Docker Hub. This step requires installing a spceial DockerCon Toolbox.

For MAC Users:

Step 1: Installing Docker Toolbox

Please note that this step will require you to have updated version of virtualbox and therefore would require you to stop any Virtualbox VMs. It will also require a laptop restart at the end.

Download and install the experimental Docker Toolbox here. Then open the downloaded package and follow the steps to complete the installation.

After the installation is complete, launch the Docker Quickstart Terminal.

Step 2: Plug in your Yubikey (touch sensor facing up)

Step 3: Check the available keys. You should see no keys as shown below:

My-Macbook-Pro:~ user$ notary key list

# Root keys:

# Signing keys:

Step 4: Generate a new Root Key

##WARNING: The root key is really important. You should be careful not lose it or delete it. Make sure to use a dummy repo in this step in the case you delete it accidentally.

To generate a new root key, simply do the following:

My-Macbook-Pro:~ user$ notary key generate
You are about to create a new root signing key passphrase. This passphrase
will be used to protect the most sensitive key in your signing system. Please
choose a long, complex passphrase and be careful to keep the password and the
key file itself secure and backed up. It is highly recommended that you use a
password manager to generate the passphrase and keep it safe. There will be no
way to recover this key. You can find the key in your config directory.
Enter passphrase for new root key with ID 37e0ee8: <ENTER A PASSWORD>
Repeat passphrase for new root key with ID 37e0ee8:<ENTER SAME PASSWORD>
Generated new ecdsa root key with keyID:
****************************

Check the new key:

My-Macbook-Pro:~ user$ notary key list

# Root keys:
******************************************************* - yubikey

Step 5: Sign an image with the new root key. First, pull a small image to use:

My-Macbook-Pro:~ user$ docker pull alpine
Using default tag: latest
Pull (1 of 1): alpine:latest@sha256:074de05bbd8554cf454a19094df34985c8674f54e14474731427a2a31d1970ec
sha256:074de05bbd8554cf454a19094df34985c8674f54e14474731427a2a31d1970ec: Pulling from library/alpine
3b4d28ce80e4: Pull complete
Digest: sha256:074de05bbd8554cf454a19094df34985c8674f54e14474731427a2a31d1970ec
Status: Downloaded newer image for alpine@sha256:074de05bbd8554cf454a19094df34985c8674f54e14474731427a2a31d1970ec
Tagging alpine@sha256:074de05bbd8554cf454a19094df34985c8674f54e14474731427a2a31d1970ec as alpine:latest

Tag an image with your Docker Hub username:

$ docker tag alpine <DOCKER_HUB_USERNAME>/alpine:signed

Ensure the Docker Content Trust is enabled

$ export DOCKER_CONTENT_TRUST=1

Ensure that you are logged in Docker Hub:

$ docker login
Username: <DOCKER_HUB_USERNAME>
Password:<YOUR_PASSWORD>
Email:<YOUR_EMAIL>
WARNING: login credentials saved in /Users/<YOUR_USERNAME>/.docker/config.json
Login Succeeded

Push the new image using docker-x, the experimental Docker engine. During the push process, you will be prompted to touch the Yubikey sensor to perform signing. You will also be prompted to provide a new passphrase to be used to encrypt the repository key.

$ docker-x push DOCKER_HUB_USERNAME/alpine:signed
The push refers to a repository [docker.io/DOCKER_HUB_USERNAME/alpine] (len: 1)
3b4d28ce80e4: Image already exists
signed: digest: sha256:0ec83084fcf6a8a96f80ccda270ccefa743601b33048bcc74e970e82d96efade size: 1608
Signing and pushing trust metadata
Please touch the attached Yubikey to perform signing.
Enter passphrase for new repository key with ID 4ec62d9 (docker.io/DOCKER_HUB_USERNAME/alpine):
Repeat passphrase for new repository key with ID 4ec62d9 (docker.io/DOCKER_HUB_USERNAME/alpine):
Please touch the attached Yubikey to perform signing.
Finished initializing "docker.io/DOCKER_HUB_USERNAME/alpine"

Congrats! you have signed and pushed a new image using the Yubikey. Docker users with enabled Docker Content Trust can pull the image that you just pushed.

For Linux Users:

Before you start, ensure there is a Docker engine running on your Linux machine. You will need to run the experimental version of Docker Engine inside a container on your machine. You will mount the Yubikey into the container and go through signing and pushing images within the container itself.

Step 1: Run Docker Experimental inside a Container

$ docker run -it --rm --privileged -v /dev/bus/usb:/dev/bus/usb dockersecurity/dct_lab:latest

Step 2: Insert the Yubikey

Step 3: In the container, run Smart Card Daemon and Docker Daemon

# pcscd
# docker daemon > /dev/null 2>&1 &

Step 4: Enable Docker Content Trust

# export DOCKER_CONTENT_TRUST=1

Step 5: Login to Docker Hub and pull a dummy image

# docker login
Username: <DOCKER_HUB_USERNAME>
Password:<YOUR_PASSWORD>
Email:<YOUR_EMAIL>
WARNING: login credentials saved in /Users/<YOUR_USERNAME>/.docker/config.json
Login Succeeded


# docker pull alpine
$Using default tag: latest
Pull (1 of 1): alpine:latest@sha256:074de05bbd8554cf454a19094df34985c8674f54e14474731427a2a31d1970ec
sha256:074de05bbd8554cf454a19094df34985c8674f54e14474731427a2a31d1970ec: Pulling from library/alpine
3b4d28ce80e4: Pull complete 
Digest: sha256:074de05bbd8554cf454a19094df34985c8674f54e14474731427a2a31d1970ec
Status: Downloaded newer image for alpine@sha256:074de05bbd8554cf454a19094df34985c8674f54e14474731427a2a31d1970ec
Tagging alpine@sha256:074de05bbd8554cf454a19094df34985c8674f54e14474731427a2a31d1970ec as alpine:latest

Step 6: Check Available Root Keys on Yubikey. You should see no keys.

# notary key list

No signing keys found.

Step 7: Tag , Sign, and Push an Image

In this step, you will tag the image and push it to Docker Hub. Since there are no available root keys on Yubikey, Docker will automatically generate one upon the first push. Please follow the instructions below:

# docker tag alpine:latest <DOCKER_HUB_USERNAME>/<REPO_NAME>:signed
# docker push <DOCKER_HUB_USERNAME>/<REPO_NAME>:signed

The push refers to a repository [docker.io/<DOCKER_HUB_USERNAME>/dct_demo] (len: 1)
3b4d28ce80e4: Pushed 
latest: digest: sha256:61b63b333e5f6132c70e3258701b75d787ac37536bc457873c23886627e64f86 size: 1611
Signing and pushing trust metadata
You are about to create a new root signing key passphrase. This passphrase
will be used to protect the most sensitive key in your signing system. Please
choose a long, complex passphrase and be careful to keep the password and the
key file itself secure and backed up. It is highly recommended that you use a
password manager to generate the passphrase and keep it safe. There will be no
way to recover this key. You can find the key in your config directory.
Enter passphrase for new root key with ID dbe580a: 
Repeat passphrase for new root key with ID dbe580a: 
Please touch the attached Yubikey to perform signing.
Enter passphrase for new repository key with ID fbe7380 (docker.io/<DOCKER_HUB_USERNAME>/<REPO_NAME>):  <ENTER A PASSWORD>
Repeat passphrase for new repository key with ID fbe7380 (docker.io/<DOCKER_HUB_USERNAME>/<REPO_NAME>):<ENTER A PASSWORD> 
Please touch the attached Yubikey to perform signing.
Finished initializing "docker.io/<DOCKER_HUB_USERNAME>/<REPO_NAME>"

Step 8: Check the new key

You will notice that a new root key was created. It is stored both in the Yubikey as well as on disk for backup.

# notary key list

    ROLE                GUN                                           KEY ID                                             LOCATION               
------------------------------------------------------------------------------------------------------------------------------------------------
  root                                  ***************   file (/root/.docker/trust/private)  
  root                                  ***************   yubikey               

Congrats! you have signed and pushed a new image using the Yubikey. Docker users with enabled Docker Content Trust can pull the image that you just pushed.

Conclusion

At this point you have successfully enabled Docker Content Trust on your Docker client, signed an image, and pushed the image to Docker Hub.

Share on Twitter!

Clean up

If you plan to do another lab, you need to cleanup your EC2 instances. Cleanup removes any environment variables, configuration changes, Docker images, and running containers. To do a clean up, log into each EC2 instance and run the following:

$ source /home/ubuntu/cleanup.sh

Related information

For more in-depth examples and advanced concepts refer to the Docker documentation: