mirror of https://github.com/docker/docs.git
Merge pull request #15396 from moxiegirl/my-trust-changes
Docker content trust documentation
This commit is contained in:
commit
1eb1083066
|
@ -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:
|
||||||
|
|
||||||
|

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

|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
>**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)
|
||||||
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 73 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 121 KiB |
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 70 KiB |
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
|
@ -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 New Issue