mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Docker content trust documentation
- started from Diogo's work - updated after discussions with team - Updating with new key names - fixing weight - adding in sandbox - adding in gliffy for images - backing out to old names for now - Copy edit pass - Entering comments from the content trust team - Update name of branch and image name - Removing the last diogo reference - Updating with Seb's comments Signed-off-by: Mary Anthony <mary@docker.com>
This commit is contained in:
parent
4bfbeb80a6
commit
753bf40f15
13 changed files with 800 additions and 0 deletions
291
docs/security/trust/content_trust.md
Normal file
291
docs/security/trust/content_trust.md
Normal file
|
@ -0,0 +1,291 @@
|
|||
<!--[metadata]>
|
||||
+++
|
||||
title = "Content trust in Docker"
|
||||
description = "Enabling content trust in Docker"
|
||||
keywords = ["content, trust, security, docker, documentation"]
|
||||
[menu.main]
|
||||
parent= "smn_content_trust"
|
||||
weight=-1
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Content trust in Docker
|
||||
|
||||
When transferring data among networked systems, *trust* is a central concern. In
|
||||
particular, when communicating over an untrusted medium such as the internet, it
|
||||
is critical to ensure the integrity and publisher of all the data a system
|
||||
operates on. You use Docker to push and pull images (data) to a registry. Content trust
|
||||
gives you the ability to both verify the integrity and the publisher of all the
|
||||
data received from a registry over any channel.
|
||||
|
||||
Content trust is currently only available for users of the public Docker Hub. It
|
||||
is currently not available for the Docker Trusted Registry or for private
|
||||
registries.
|
||||
|
||||
## Understand trust in Docker
|
||||
|
||||
Content trust allows operations with a remote Docker registry to enforce
|
||||
client-side signing and verification of image tags. Content trust provides the
|
||||
ability to use digital signatures for data sent to and received from remote
|
||||
Docker registries. These signatures allow client-side verification of the
|
||||
integrity and publisher of specific image tags.
|
||||
|
||||
Currently, content trust is disabled by default. You must enabled it by setting
|
||||
the `DOCKER_CONTENT_TRUST` environment variable.
|
||||
|
||||
Once content trust is enabled, image publishers can sign their images. Image consumers can
|
||||
ensure that the images they use are signed. publishers and consumers can be
|
||||
individuals alone or in organizations. Docker's content trust supports users and
|
||||
automated processes such as builds.
|
||||
|
||||
### Image tags and content trust
|
||||
|
||||
An individual image record has the following identifier:
|
||||
|
||||
```
|
||||
[REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG]
|
||||
```
|
||||
|
||||
A particular image `REPOSITORY` can have multiple tags. For example, `latest` and
|
||||
`3.1.2` are both tags on the `mongo` image. An image publisher can build an image
|
||||
and tag combination many times changing the image with each build.
|
||||
|
||||
Content trust is associated with the `TAG` portion of an image. Each image
|
||||
repository has a set of keys that image publishers use to sign an image tag.
|
||||
Image publishers have discretion on which tags they sign.
|
||||
|
||||
An image repository can contain an image with one tag that is signed and another
|
||||
tag that is not. For example, consider [the Mongo image
|
||||
repository](https://hub.docker.com/r/library/mongo/tags/). The `latest`
|
||||
tag could be unsigned while the `3.1.6` tag could be signed. It is the
|
||||
responsibility of the image publisher to decide if an image tag is signed or
|
||||
not. In this representation, some image tags are signed, others are not:
|
||||
|
||||
![Signed tags](../images/tag_signing.png)
|
||||
|
||||
Publishers can choose to sign a specific tag or not. As a result, the content of
|
||||
an unsigned tag and that of a signed tag with the same name may not match. For
|
||||
example, a publisher can push a tagged image `someimage:latest` and sign it.
|
||||
Later, the same publisher can push an unsigned `someimage:latest` image. This second
|
||||
push replaces the last unsigned tag `latest` but does not affect the signed `latest` version.
|
||||
The ability to choose which tags they can sign, allows publishers to iterate over
|
||||
the unsigned version of an image before officially signing it.
|
||||
|
||||
Image consumers can enable content trust to ensure that images they use were
|
||||
signed. If a consumer enables content trust, they can only pull, run, or build
|
||||
with trusted images. Enabling content trust is like wearing a pair of
|
||||
rose-colored glasses. Consumers "see" only signed images tags and the less
|
||||
desirable, unsigned image tags are "invisible" to them.
|
||||
|
||||
![Trust view](../images/trust_view.png)
|
||||
|
||||
To the consumer who does not enabled content trust, nothing about how they
|
||||
work with Docker images changes. Every image is visible regardless of whether it
|
||||
is signed or not.
|
||||
|
||||
|
||||
### Content trust operations and keys
|
||||
|
||||
When content trust is enabled, `docker` CLI commands that operate on tagged images must
|
||||
either have content signatures or explicit content hashes. The commands that
|
||||
operate with content trust are:
|
||||
|
||||
* `push`
|
||||
* `build`
|
||||
* `create`
|
||||
* `pull`
|
||||
* `run`
|
||||
|
||||
For example, with content trust enabled a `docker pull someimage:latest` only
|
||||
succeeds if `someimage:latest` is signed. However, an operation with an explicit
|
||||
content hash always succeeds as long as the hash exists:
|
||||
|
||||
```bash
|
||||
$ docker pull someimage@sha256:d149ab53f8718e987c3a3024bb8aa0e2caadf6c0328f1d9d850b2a2a67f2819a
|
||||
```
|
||||
|
||||
Trust for an image tag is managed through the use of signing keys. Docker's content
|
||||
trust makes use four different keys:
|
||||
|
||||
| Key | Description |
|
||||
|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| offline key | Root of content trust for a image tag. When content trust is enabled, you create the offline key once. |
|
||||
| target and snapshot | These two keys are known together as the "tagging" key. When content trust is enabled, you create this key when you add a new image repository. If you have the offline key, you can export the tagging key and allow other publishers to sign the image tags. |
|
||||
| timestamp | This key applies to a repository. It allows Docker repositories to have freshness security guarantees without requiring periodic content refreshes on the client's side. |
|
||||
|
||||
With the exception of the timestamp, all the keys are generated and stored locally
|
||||
client-side. The timestamp is safely generated and stored in a signing server that
|
||||
is deployed alongside the Docker registry. All keys are generated in a backend
|
||||
service that isn't directly exposed to the internet and are encrypted at rest.
|
||||
|
||||
The following image depicts the various signing keys and their relationships:
|
||||
|
||||
![Content trust components](../images/trust_components.png)
|
||||
|
||||
>**WARNING**: Loss of the offline key is **very difficult** to recover from.
|
||||
>Correcting this loss requires intervention from [Docker
|
||||
>Support](https://support.docker.com) to reset the repository state. This loss
|
||||
>also requires **manual intervention** from every consumer that used a signed
|
||||
>tag from this repository prior to the loss.
|
||||
|
||||
You should backup the offline key somewhere safe. Given that it is only required
|
||||
to create new repositories, it is a good idea to store it offline. Make sure you
|
||||
read [Manage keys for content trust](/security/trust/trust_key_mng) information
|
||||
for details on creating, securing, and backing up your keys.
|
||||
|
||||
## Survey of typical content trust operations
|
||||
|
||||
This section surveys the typical trusted operations users perform with Docker
|
||||
images.
|
||||
|
||||
### Enable content trust
|
||||
|
||||
Enable content trust by setting the `DOCKER_CONTENT_TRUST` environment variable.
|
||||
Enabling per-shell is useful because you can have one shell configured for
|
||||
trusted operations and another terminal shell for untrusted operations. You can
|
||||
also add this declaration to your shell profile to have it turned on always by
|
||||
default.
|
||||
|
||||
To enable content trust in a `bash` shell enter the following command:
|
||||
|
||||
```bash
|
||||
export DOCKER_CONTENT_TRUST=1
|
||||
```
|
||||
|
||||
Once set, each of the "tag" operations require key for trusted tag. All of these
|
||||
commands also support the `--disable-content-trust` flag. This flag allows
|
||||
publishers to run individual operations on tagged images without content trust on an
|
||||
as-needed basis.
|
||||
|
||||
|
||||
### Push trusted content
|
||||
|
||||
To create signed content for a specific image tag, simply enable content trust and push
|
||||
a tagged image. If this is the first time you have pushed an image using content trust
|
||||
on your system, the session looks like this:
|
||||
|
||||
```bash
|
||||
$ docker push docker/trusttest:latest
|
||||
The push refers to a repository [docker.io/docker/trusttest] (len: 1)
|
||||
9a61b6b1315e: Image already exists
|
||||
902b87aaaec9: Image already exists
|
||||
latest: digest: sha256:d02adacee0ac7a5be140adb94fa1dae64f4e71a68696e7f8e7cbf9db8dd49418 size: 3220
|
||||
Signing and pushing trust metadata
|
||||
You are about to create a new offline 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 offline key with id a1d96fb:
|
||||
Repeat passphrase for new offline key with id a1d96fb:
|
||||
Enter passphrase for new tagging key with id docker.io/docker/trusttest (3a932f1):
|
||||
Repeat passphrase for new tagging key with id docker.io/docker/trusttest (3a932f1):
|
||||
Finished initializing "docker.io/docker/trusttest"
|
||||
```
|
||||
When you push your first tagged image with content trust enabled, the `docker` client
|
||||
recognizes this is your first push and:
|
||||
|
||||
- alerts you that it will create a new offline key
|
||||
- requests a passphrase for the key
|
||||
- generates an offline key in the `~/.docker/trust` directory
|
||||
- generates a tagging key for in the `~/.docker/trust` directory
|
||||
|
||||
The passphrase you chose for both the offline key and your content key-pair should
|
||||
be randomly generated and stored in a *password manager*.
|
||||
|
||||
It is important to note, if you had left off the `latest` tag, content trust is skipped.
|
||||
This is true even if content trust is enabled and even if this is your first push.
|
||||
|
||||
```bash
|
||||
$ docker push docker/trusttest
|
||||
The push refers to a repository [docker.io/docker/trusttest] (len: 1)
|
||||
9a61b6b1315e: Image successfully pushed
|
||||
902b87aaaec9: Image successfully pushed
|
||||
latest: digest: sha256:a9a9c4402604b703bed1c847f6d85faac97686e48c579bd9c3b0fa6694a398fc size: 3220
|
||||
No tag specified, skipping trust metadata push
|
||||
```
|
||||
|
||||
It is skipped because as the message states, you did not supply an image `TAG`
|
||||
value. In Docker content trust, signatures are associated with tags.
|
||||
|
||||
Once you have an offline key on your system, subsequent images repositories
|
||||
you create can use that same offline key:
|
||||
|
||||
```bash
|
||||
$ docker push docker.io/docker/seaside:latest
|
||||
The push refers to a repository [docker.io/docker/seaside] (len: 1)
|
||||
a9539b34a6ab: Image successfully pushed
|
||||
b3dbab3810fc: Image successfully pushed
|
||||
latest: digest: sha256:d2ba1e603661a59940bfad7072eba698b79a8b20ccbb4e3bfb6f9e367ea43939 size: 3346
|
||||
Signing and pushing trust metadata
|
||||
Enter key passphrase for offline key with id a1d96fb:
|
||||
Enter passphrase for new tagging key with id docker.io/docker/seaside (bb045e3):
|
||||
Repeat passphrase for new tagging key with id docker.io/docker/seaside (bb045e3):
|
||||
Finished initializing "docker.io/docker/seaside"
|
||||
```
|
||||
|
||||
The new image has its own tagging key and timestamp key. The `latest` tag is signed with both of
|
||||
these.
|
||||
|
||||
|
||||
### Pull image content
|
||||
|
||||
A common way to consume an image is to `pull` it. With content trust enabled, the Docker
|
||||
client only allows `docker pull` to retrieve signed images.
|
||||
|
||||
```
|
||||
$ docker pull docker/seaside
|
||||
Using default tag: latest
|
||||
Pull (1 of 1): docker/trusttest:latest@sha256:d149ab53f871
|
||||
...
|
||||
Tagging docker/trusttest@sha256:d149ab53f871 as docker/trusttest:latest
|
||||
```
|
||||
|
||||
The `seaside:latest` image is signed. In the following example, the command does not specify a tag, so the system uses
|
||||
the `latest` tag by default again and the `docker/cliffs:latest` tag is not signed.
|
||||
|
||||
```bash
|
||||
$ docker pull docker/cliffs
|
||||
Using default tag: latest
|
||||
no trust data available
|
||||
```
|
||||
|
||||
Because the tag `docker/cliffs:latest` is not trusted, the `pull` fails.
|
||||
|
||||
|
||||
### Disable content trust for specific operations
|
||||
|
||||
A user that wants to disable content trust for a particular operation can use the
|
||||
`--disable-content-trust` flag. **Warning: this flag disables content trust for
|
||||
this operation**. With this flag, Docker will ignore content-trust and allow all
|
||||
operations to be done without verifying any signatures. If we wanted the
|
||||
previous untrusted build to succeed we could do:
|
||||
|
||||
```
|
||||
$ cat Dockerfile
|
||||
FROM docker/trusttest:notrust
|
||||
RUN echo
|
||||
$ docker build --disable-content-trust -t docker/trusttest:testing .
|
||||
Sending build context to Docker daemon 42.84 MB
|
||||
...
|
||||
Successfully built f21b872447dc
|
||||
```
|
||||
|
||||
The same is true for all the other commands, such as `pull` and `push`:
|
||||
|
||||
```
|
||||
$ docker pull --disable-content-trust docker/trusttest:untrusted
|
||||
...
|
||||
$ docker push --disable-content-trust docker/trusttest:untrusted
|
||||
...
|
||||
```
|
||||
|
||||
## Related information
|
||||
|
||||
* [Manage keys for content trust](/security/trust/trust_key_mng)
|
||||
* [Automation with content trust](/security/trust/trust_automation)
|
||||
* [Play in a content trust sandbox](/security/trust/trust_sandbox)
|
||||
|
||||
|
||||
|
BIN
docs/security/trust/images/tag_signing.png
Normal file
BIN
docs/security/trust/images/tag_signing.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 73 KiB |
1
docs/security/trust/images/trust_.gliffy
Normal file
1
docs/security/trust/images/trust_.gliffy
Normal file
File diff suppressed because one or more lines are too long
1
docs/security/trust/images/trust_components.gliffy
Normal file
1
docs/security/trust/images/trust_components.gliffy
Normal file
File diff suppressed because one or more lines are too long
BIN
docs/security/trust/images/trust_components.png
Normal file
BIN
docs/security/trust/images/trust_components.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 121 KiB |
1
docs/security/trust/images/trust_signing.gliffy
Normal file
1
docs/security/trust/images/trust_signing.gliffy
Normal file
File diff suppressed because one or more lines are too long
BIN
docs/security/trust/images/trust_signing.png
Normal file
BIN
docs/security/trust/images/trust_signing.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 70 KiB |
1
docs/security/trust/images/trust_view.gliffy
Normal file
1
docs/security/trust/images/trust_view.gliffy
Normal file
File diff suppressed because one or more lines are too long
BIN
docs/security/trust/images/trust_view.png
Normal file
BIN
docs/security/trust/images/trust_view.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
21
docs/security/trust/index.md
Normal file
21
docs/security/trust/index.md
Normal file
|
@ -0,0 +1,21 @@
|
|||
<!--[metadata]>
|
||||
+++
|
||||
title = "Use trusted images"
|
||||
description = "Use trusted images"
|
||||
keywords = ["trust, security, docker, index"]
|
||||
[menu.main]
|
||||
identifier="smn_content_trust"
|
||||
parent= "mn_docker_hub"
|
||||
weight=4
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Use trusted images
|
||||
|
||||
The following topics are available:
|
||||
|
||||
* [Content trust in Docker](/security/trust/content_trust)
|
||||
* [Manage keys for content trust](/security/trust/trust_key_mng)
|
||||
* [Automation with content trust](/security/trust/trust_automation)
|
||||
* [Play in a content trust sandbox](/security/trust/trust_sandbox)
|
||||
|
79
docs/security/trust/trust_automation.md
Normal file
79
docs/security/trust/trust_automation.md
Normal file
|
@ -0,0 +1,79 @@
|
|||
<!--[metadata]>
|
||||
+++
|
||||
title = "Automation with content trust"
|
||||
description = "Automating content push pulls with trust"
|
||||
keywords = ["trust, security, docker, documentation, automation"]
|
||||
[menu.main]
|
||||
parent= "smn_content_trust"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Automation with content trust
|
||||
|
||||
Your automation systems that pull or build images can also work with trust. Any automation environment must set `DOCKER_TRUST_ENABLED` either manually or in in a scripted fashion before processing images.
|
||||
|
||||
## Bypass requests for passphrases
|
||||
|
||||
To allow tools to wrap docker and push trusted content, there are two
|
||||
environment variables that allow you to provide the passphrases without an
|
||||
expect script, or typing them in:
|
||||
|
||||
- `DOCKER_CONTENT_TRUST_OFFLINE_PASSPHRASE`
|
||||
- `DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE`
|
||||
|
||||
Docker attempts to use the contents of these environment variables as passphrase
|
||||
for the keys. For example, an image publisher can export the repository `target`
|
||||
and `snapshot` passphrases:
|
||||
|
||||
```bash
|
||||
$ export DOCKER_CONTENT_TRUST_OFFLINE_PASSPHRASE="u7pEQcGoebUHm6LHe6"
|
||||
$ export DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE="l7pEQcTKJjUHm6Lpe4"
|
||||
```
|
||||
|
||||
Then, when pushing a new tag the Docker client does not request these values but signs automatically:
|
||||
|
||||
``bash
|
||||
$ docker push docker/trusttest:latest
|
||||
The push refers to a repository [docker.io/docker/trusttest] (len: 1)
|
||||
a9539b34a6ab: Image already exists
|
||||
b3dbab3810fc: Image already exists
|
||||
latest: digest: sha256:d149ab53f871 size: 3355
|
||||
Signing and pushing trust metadata
|
||||
```
|
||||
|
||||
## Building with content trust
|
||||
|
||||
You can also build with content trust. Before running the `docker build` command, you should set the environment variable `DOCKER_CONTENT_TRUST` either manually or in in a scripted fashion. Consider the simple Dockerfile below.
|
||||
|
||||
```Dockerfilea
|
||||
FROM docker/trusttest:latest
|
||||
RUN echo
|
||||
```
|
||||
|
||||
The `FROM` tag is pulling a signed image. You cannot build an image that has a
|
||||
`FROM` that is not either present locally or signed. Given that content trust
|
||||
data exists for the tag `latest`, the following build should succeed:
|
||||
|
||||
```bash
|
||||
$ docker build -t docker/trusttest:testing .
|
||||
Using default tag: latest
|
||||
latest: Pulling from docker/trusttest
|
||||
|
||||
b3dbab3810fc: Pull complete
|
||||
a9539b34a6ab: Pull complete
|
||||
Digest: sha256:d149ab53f871
|
||||
```
|
||||
|
||||
If content trust is enabled, building from a Dockerfile that relies on tag without trust data, causes the build command to fail:
|
||||
|
||||
```bash
|
||||
$ docker build -t docker/trusttest:testing .
|
||||
unable to process Dockerfile: No trust data for notrust
|
||||
```
|
||||
|
||||
## Related information
|
||||
|
||||
* [Content trust in Docker](/security/trust/content_trust)
|
||||
* [Manage keys for content trust](/security/trust/trust_key_mng)
|
||||
* [Play in a content trust sandbox](/security/trust/trust_sandbox)
|
||||
|
74
docs/security/trust/trust_key_mng.md
Normal file
74
docs/security/trust/trust_key_mng.md
Normal file
|
@ -0,0 +1,74 @@
|
|||
<!--[metadata]>
|
||||
+++
|
||||
title = "Manage keys for content trust"
|
||||
description = "Manage keys for content trust"
|
||||
keywords = ["trust, security, root, keys, repository"]
|
||||
[menu.main]
|
||||
parent= "smn_content_trust"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Manage keys for content trust
|
||||
|
||||
Trust for an image tag is managed through the use of keys. Docker's content
|
||||
trust makes use four different keys:
|
||||
|
||||
| Key | Description |
|
||||
|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| offline key | Root of content trust for a image tag. When content trust is enabled, you create the offline key once. |
|
||||
| target and snapshot | These two keys are known together as the "tagging" key. When content trust is enabled, you create this key when you add a new image repository. If you have the offline key, you can export the tagging key and allow other publishers to sign the image tags. |
|
||||
| timestamp | This key applies to a repository. It allows Docker repositories to have freshness security guarantees without requiring periodic content refreshes on the client's side. |
|
||||
|
||||
With the exception of the timestamp, all the keys are generated and stored locally
|
||||
client-side. The timestamp is safely generated and stored in a signing server that
|
||||
is deployed alongside the Docker registry. All keys are generated in a backend
|
||||
service that isn't directly exposed to the internet and are encrypted at rest.
|
||||
|
||||
## Choosing a passphrase
|
||||
|
||||
The passphrases you chose for both the offline key and your tagging key should
|
||||
be randomly generated and stored in a password manager. Having the tagging key
|
||||
allow users to sign image tags on a repository. Passphrases are used to encrypt
|
||||
your keys at rest and ensures that a lost laptop or an unintended backup doesn't
|
||||
put the private key material at risk.
|
||||
|
||||
## Back up your keys
|
||||
|
||||
All the Docker trust keys are stored encrypted using the passphrase you provide
|
||||
on creation. Even so, you should still take care of the location where you back them up.
|
||||
Good practice is to create two encrypted USB keys.
|
||||
|
||||
It is very important that you backup your keys to a safe, secure location. Loss
|
||||
of the tagging key is recoverable; loss of the offline key is not.
|
||||
|
||||
The Docker client stores the keys in the `~/.docker/trust/private` directory.
|
||||
Before backing them up, you should `tar` them into an archive:
|
||||
|
||||
```bash
|
||||
$ tar -zcvf private_keys_backup.tar.gz ~/.docker/trust/private
|
||||
$ chmod 600 private_keys_backup.tar.gz
|
||||
```
|
||||
|
||||
## Lost keys
|
||||
|
||||
If a publisher loses keys it means losing the ability to sign trusted content for
|
||||
your repositories. If you lose a key, contact [Docker
|
||||
Support](https://support.docker.com) (support@docker.com) to reset the repository
|
||||
state.
|
||||
|
||||
This loss also requires **manual intervention** from every consumer that pulled
|
||||
the tagged image prior to the loss. Image consumers would get an error for
|
||||
content that they already downloaded:
|
||||
|
||||
```
|
||||
could not validate the path to a trusted root: failed to validate data with current trusted certificates
|
||||
```
|
||||
|
||||
To correct this, they need to download a new image tag with that is signed with
|
||||
the new key.
|
||||
|
||||
## Related information
|
||||
|
||||
* [Content trust in Docker](/security/trust/content_trust)
|
||||
* [Automation with content trust](/security/trust/trust_automation)
|
||||
* [Play in a content trust sandbox](/security/trust/trust_sandbox)
|
331
docs/security/trust/trust_sandbox.md
Normal file
331
docs/security/trust/trust_sandbox.md
Normal file
|
@ -0,0 +1,331 @@
|
|||
<!--[metadata]>
|
||||
+++
|
||||
title = "Play in a content trust sandbox"
|
||||
description = "Play in a trust sandbox"
|
||||
keywords = ["trust, security, root, keys, repository, sandbox"]
|
||||
[menu.main]
|
||||
parent= "smn_content_trust"
|
||||
+++
|
||||
<![end-metadata]-->
|
||||
|
||||
# Play in a content trust sandbox
|
||||
|
||||
This page explains how to set up and use a sandbox for experimenting with trust.
|
||||
The sandbox allows you to configure and try trust operations locally without
|
||||
impacting your production images.
|
||||
|
||||
Before working through this sandbox, you should have read through the [trust
|
||||
overview](content_trust.md).
|
||||
|
||||
### Prerequisites
|
||||
|
||||
These instructions assume you are running in Linux or Mac OS X. You can run
|
||||
this sandbox on a local machine or on a virtual machine. You will need to
|
||||
have `sudo` privileges on your local machine or in the VM.
|
||||
|
||||
This sandbox requires you to install two Docker tools: Docker Engine and Docker
|
||||
Compose. To install the Docker Engine, choose from the [list of supported
|
||||
platforms]({{< relref "installation.md" >}}). To install Docker Compose, see the
|
||||
[detailed instructions here]({{< relref "compose/install" >}}).
|
||||
|
||||
Finally, you'll need to have `git` installed on your local system or VM.
|
||||
|
||||
## What is in the sandbox?
|
||||
|
||||
If you are just using trust out-of-the-box you only need your Docker Engine
|
||||
client and access to Docker's own public hub. The sandbox mimics a
|
||||
production trust environment, and requires these additional components:
|
||||
|
||||
| Container | Description |
|
||||
|-----------------|---------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| nostarysandbox | A container with the latest version of Docker Engine and with some preconfigured certifications. This is your sandbox where you can use the `docker` client to test trust operations. |
|
||||
| Registry server | A local registry service. |
|
||||
| Notary server | The service that does all the heavy-lifting of managing trust |
|
||||
| Notary signer | A service that ensures that your keys are secure. |
|
||||
| MySQL | The database where all of the trust information will be stored |
|
||||
|
||||
The sandbox uses the Docker daemon on your local system. Within the `nostarysandbox`
|
||||
you interact with a local registry rather than the public Docker Hub. This means
|
||||
your everyday image repositories are not used. They are protected while you play.
|
||||
|
||||
When you play in the sandbox, you'll also create root and tagging keys. The
|
||||
sandbox is configured to store all the keys and files inside the `notarysandbox`
|
||||
container. Since the keys you create in the sandbox are for play only,
|
||||
destroying the container destroys them as well.
|
||||
|
||||
|
||||
## Build the sandbox
|
||||
|
||||
In this section, you build the Docker components for your trust sandbox. If you
|
||||
work exclusively with the Docker Hub, you would not need with these components.
|
||||
They are built into the Docker Hub for you. For the sandbox, however, you must
|
||||
build your own entire, mock production environment and registry.
|
||||
|
||||
### Configure /etc/hosts
|
||||
|
||||
The sandbox' `notaryserver` and `sandboxregistry` run on your local server. The
|
||||
client inside the `notarysandbox` container connects to them over your network.
|
||||
So, you'll need an entry for both the servers in your local `/etc/hosts` file.
|
||||
|
||||
1. Add an entry for the `notaryserver` to `/etc/hosts`.
|
||||
|
||||
$ sudo sh -c 'echo "127.0.0.1 notaryserver" >> /etc/hosts'
|
||||
|
||||
2. Add an entry for the `sandboxregistry` to `/etc/hosts`.
|
||||
|
||||
$ sudo sh -c 'echo "127.0.0.1 sandboxregistry" >> /etc/hosts'
|
||||
|
||||
|
||||
### Build the notarytest image
|
||||
|
||||
1. Create a `notarytest` directory on your system.
|
||||
|
||||
$ mkdir notarysandbox
|
||||
|
||||
2. Change into your `notarysandbox` directory.
|
||||
|
||||
$ cd notarysandbox
|
||||
|
||||
3. Create a `notarytest` directory then change into that.
|
||||
|
||||
$ mkdir notarytest
|
||||
$ cd nostarytest
|
||||
|
||||
4. Create a filed called `Dockerfile` with your favorite editor.
|
||||
|
||||
5. Add the following to the new file.
|
||||
|
||||
FROM debian:jessie
|
||||
|
||||
ADD https://master.dockerproject.org/linux/amd64/docker /usr/bin/docker
|
||||
RUN chmod +x /usr/bin/docker \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y \
|
||||
tree \
|
||||
vim \
|
||||
git \
|
||||
ca-certificates \
|
||||
--no-install-recommends
|
||||
|
||||
WORKDIR /root
|
||||
RUN git clone -b trust-sandbox https://github.com/docker/notary.git
|
||||
RUN cp /root/notary/fixtures/root-ca.crt /usr/local/share/ca-certificates/root-ca.crt
|
||||
RUN update-ca-certificates
|
||||
|
||||
ENTRYPOINT ["bash"]
|
||||
|
||||
6. Save and close the file.
|
||||
|
||||
7. Build the testing container.
|
||||
|
||||
$ docker build -t nostarysandbox .
|
||||
Sending build context to Docker daemon 2.048 kB
|
||||
Step 0 : FROM debian:jessie
|
||||
...
|
||||
Successfully built 5683f17e9d72
|
||||
|
||||
|
||||
### Build and start up the trust servers
|
||||
|
||||
In this step, you get the source code for your notary and registry services.
|
||||
Then, you'll use Docker Compose to build and start them on your local system.
|
||||
|
||||
1. Change to back to the root of your `notarysandbox` directory.
|
||||
|
||||
$ cd notarysandbox
|
||||
|
||||
2. Clone the `notary` project.
|
||||
|
||||
$ git clone -b trust-sandbox https://github.com/docker/notary.git
|
||||
|
||||
3. Clone the `distribution` project.
|
||||
|
||||
$ git clone https://github.com/docker/distribution.git
|
||||
|
||||
4. Change to the `notary` project directory.
|
||||
|
||||
$ cd notary
|
||||
|
||||
The directory contains a `docker-compose` file that you'll use to run a
|
||||
notary server together with a notary signer and the corresponding MySQL
|
||||
databases. The databases store the trust information for an image.
|
||||
|
||||
5. Build the server images.
|
||||
|
||||
$ docker-compose build
|
||||
|
||||
The first time you run this, the build takes some time.
|
||||
|
||||
6. Run the server containers on your local system.
|
||||
|
||||
$ docker-compose up -d
|
||||
|
||||
Once the trust services are up, you'll setup a local version of the Docker
|
||||
Registry v2.
|
||||
|
||||
7. Change to the `nostarysandbox/distribution` directory.
|
||||
|
||||
8. Build the `sandboxregistry` server.
|
||||
|
||||
$ docker build -t sandboxregistry .
|
||||
|
||||
9. Start the `sandboxregistry` server running.
|
||||
|
||||
$ docker run -p 5000:5000 --name sandboxregistry sandboxregistry &
|
||||
|
||||
## Playing in the sandbox
|
||||
|
||||
Now that everything is setup, you can go into your `nostarysandbox` container and
|
||||
start testing Docker content trust.
|
||||
|
||||
|
||||
### Start the notarysandbox container
|
||||
|
||||
In this procedure, you start the `notarysandbox` and link it to the running
|
||||
`notary_notaryserver_1` and `sandboxregistry` containers. The links allow
|
||||
communication among the containers.
|
||||
|
||||
```
|
||||
$ docker run -it -v /var/run/docker.sock:/var/run/docker.sock --link notary_notaryserver_1:notaryserver --link sandboxregistry:sandboxregistry nostarysandbox
|
||||
root@0710762bb59a:/#
|
||||
```
|
||||
|
||||
Mounting the `docker.sock` gives the `nostarysandbox` access to the `docker`
|
||||
deamon on your host, while storing all the keys and files inside the sandbox
|
||||
container. When you destroy the container, you destroy the "play" keys.
|
||||
|
||||
### Test some trust operations
|
||||
|
||||
Now, you'll pull some images.
|
||||
|
||||
1. Download a `docker` image to test with.
|
||||
|
||||
# docker pull docker/trusttest
|
||||
docker pull docker/trusttest
|
||||
Using default tag: latest
|
||||
latest: Pulling from docker/trusttest
|
||||
|
||||
b3dbab3810fc: Pull complete
|
||||
a9539b34a6ab: Pull complete
|
||||
Digest: sha256:d149ab53f8718e987c3a3024bb8aa0e2caadf6c0328f1d9d850b2a2a67f2819a
|
||||
Status: Downloaded newer image for docker/trusttest:latest
|
||||
|
||||
2. Tag it to be pushed to our sandbox registry:
|
||||
|
||||
# docker tag docker/trusttest sandboxregistry:5000/test/trusttest:latest
|
||||
|
||||
3. Enable content trust.
|
||||
|
||||
# export DOCKER_CONTENT_TRUST=1
|
||||
|
||||
4. Identify the trust server.
|
||||
|
||||
# export DOCKER_CONTENT_TRUST_SERVER=https://notaryserver:4443
|
||||
|
||||
This step is only necessary because the sandbox is using its own server.
|
||||
Normally, if you are using the Docker Public Hub this step isn't necessary.
|
||||
|
||||
5. Pull the test image.
|
||||
|
||||
# docker pull sandboxregistry:5000/test/trusttest
|
||||
Using default tag: latest
|
||||
no trust data available
|
||||
|
||||
You see an error, because this content doesn't exist on the `sandboxregistry` yet.
|
||||
|
||||
6. Push the trusted image.
|
||||
|
||||
# docker push sandboxregistry:5000/test/trusttest:latest
|
||||
The push refers to a repository [sandboxregistry:5000/test/trusttest] (len: 1)
|
||||
a9539b34a6ab: Image successfully pushed
|
||||
b3dbab3810fc: Image successfully pushed
|
||||
latest: digest: sha256:1d871dcb16805f0604f10d31260e79c22070b35abc71a3d1e7ee54f1042c8c7c size: 3348
|
||||
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 offline key with id 8c69e04:
|
||||
Repeat passphrase for new offline key with id 8c69e04:
|
||||
Enter passphrase for new tagging key with id sandboxregistry:5000/test/trusttest (93c362a):
|
||||
Repeat passphrase for new tagging key with id sandboxregistry:5000/test/trusttest (93c362a):
|
||||
Finished initializing "sandboxregistry:5000/test/trusttest"
|
||||
latest: digest: sha256:d149ab53f8718e987c3a3024bb8aa0e2caadf6c0328f1d9d850b2a2a67f2819a size: 3355
|
||||
Signing and pushing trust metadata
|
||||
|
||||
7. Try pulling the image you just pushed:
|
||||
|
||||
# docker pull sandboxregistry:5000/test/trusttest
|
||||
Using default tag: latest
|
||||
Pull (1 of 1): sandboxregistry:5000/test/trusttest:latest@sha256:1d871dcb16805f0604f10d31260e79c22070b35abc71a3d1e7ee54f1042c8c7c
|
||||
sha256:1d871dcb16805f0604f10d31260e79c22070b35abc71a3d1e7ee54f1042c8c7c: Pulling from test/trusttest
|
||||
b3dbab3810fc: Already exists
|
||||
a9539b34a6ab: Already exists
|
||||
Digest: sha256:1d871dcb16805f0604f10d31260e79c22070b35abc71a3d1e7ee54f1042c8c7c
|
||||
Status: Downloaded newer image for sandboxregistry:5000/test/trusttest@sha256:1d871dcb16805f0604f10d31260e79c22070b35abc71a3d1e7ee54f1042c8c7c
|
||||
Tagging sandboxregistry:5000/test/trusttest@sha256:1d871dcb16805f0604f10d31260e79c22070b35abc71a3d1e7ee54f1042c8c7c as sandboxregistry:5000/test/trusttest:latest
|
||||
|
||||
|
||||
### Test with malicious images
|
||||
|
||||
What happens when data is corrupted and you try to pull it when trust is
|
||||
enabled? In this section, you go into the `sandboxregistry` and tamper with some
|
||||
data. Then, you try and pull it.
|
||||
|
||||
1. Leave the sandbox container running.
|
||||
|
||||
2. Open a new bash terminal from your host into the `sandboxregistry`.
|
||||
|
||||
$ docker exec -it sandboxregistry bash
|
||||
296db6068327#
|
||||
|
||||
3. Change into the registry storage.
|
||||
|
||||
You'll need to provide the `sha` you received when you pushed the image.
|
||||
|
||||
# cd /var/lib/registry/docker/registry/v2/blobs/sha256/aa/aac0c133338db2b18ff054943cee3267fe50c75cdee969aed88b1992539ed042
|
||||
|
||||
4. Add malicious data to one of the trusttest layers:
|
||||
|
||||
# echo "Malicious data" > data
|
||||
|
||||
5. Got back to your sandbox terminal.
|
||||
|
||||
6. List the trusttest image.
|
||||
|
||||
# docker images | grep trusttest
|
||||
docker/trusttest latest a9539b34a6ab 7 weeks ago 5.025 MB
|
||||
sandboxregistry:5000/test/trusttest latest a9539b34a6ab 7 weeks ago 5.025 MB
|
||||
sandboxregistry:5000/test/trusttest <none> a9539b34a6ab 7 weeks ago 5.025 MB
|
||||
|
||||
7. Remove the `trusttest:latest` image.
|
||||
|
||||
# docker rmi -f a9539b34a6ab
|
||||
Untagged: docker/trusttest:latest
|
||||
Untagged: sandboxregistry:5000/test/trusttest:latest
|
||||
Untagged: sandboxregistry:5000/test/trusttest@sha256:1d871dcb16805f0604f10d31260e79c22070b35abc71a3d1e7ee54f1042c8c7c
|
||||
Deleted: a9539b34a6aba01d3942605dfe09ab821cd66abf3cf07755b0681f25ad81f675
|
||||
Deleted: b3dbab3810fc299c21f0894d39a7952b363f14520c2f3d13443c669b63b6aa20
|
||||
|
||||
8. Pull the image again.
|
||||
|
||||
# docker pull sandboxregistry:5000/test/trusttest
|
||||
Using default tag: latest
|
||||
...
|
||||
b3dbab3810fc: Verifying Checksum
|
||||
a9539b34a6ab: Pulling fs layer
|
||||
filesystem layer verification failed for digest sha256:aac0c133338db2b18ff054943cee3267fe50c75cdee969aed88b1992539ed042
|
||||
|
||||
You'll see the the pull did not complete because the trust system was
|
||||
unable to verify the image.
|
||||
|
||||
## More play in the sandbox
|
||||
|
||||
Now, that you have a full Docker content trust sandbox on your local system,
|
||||
feel free to play with it and see how it behaves. If you find any security
|
||||
issues with Docker, feel free to send us an email at <security@docker.com>.
|
||||
|
||||
|
||||
|
Loading…
Reference in a new issue