Runtime Enforcement with Docker Content Trust¶
Note
Runtime enforcement is a feature that is exclusive to MCR. It is not available in Moby or Docker CE.
The implementation is separate from the
only run signed images
feature of Mirantis Kubernetes Engine.
Docker Content Trust within the Mirantis Container Runtime prevents a user from using a container image from an untrusted source. It will also prevent a user from building a container image from a base layer from an untrusted source. Trusted sources can include Official Docker Images, found on the Docker Hub or User trusted sources, with repositories and tags signed with the commands detailed in Signing Images with Docker Content Trust.
Engine Signature Verification prevents the following:
$ docker container run of an unsigned or altered image.
$ docker pull of an unsigned or altered image.
$ docker build where the FROM image is not signed or is not scratch.
Note
The implicit pulls and runs performed by worker nodes for a Swarm service on $ docker service create and $ docker service update are also verified. Tag resolution of services requires that all nodes in the Swarm including managers have content trust enabled and similarly configured.
DCT does not verify that the filesystem of a running container has not been altered from what was in the image. For example, it does not prevent a container from writing to the filesystem, once the container is running. Moreover, it does not prevent the image filesystem from being altered on the disk of a Docker host. DCT will also not prevent unsigned images from being imported, loaded, or created.
Enabling DCT within the Mirantis Container Runtime¶
DCT is controlled by the Docker Engine configuration file, which by default is
located at /etc/docker/daemon.json
. For more information on the
configuration file, refer to the official docker documentation, Daemon
configuration file.
Note
The configuration can be set only on Linux machines.
The content-trust section is based around a mode
option that
instructs the engine on whether to enforce signed images, and a
trust-pinning
section that instructs the engine on which sources to trust.
Mode
can take one of three values: disabled
, permissive
, or
enforced
.
disabled
Verification is not active and the remainder of the content-trust related configuration is ignored. This is the default value if
mode
is not specified.permissive
Verification will be performed, while failures are only logged. Images that cannot be verified successfully can still be pulled and run. This configuration is intended for testing of changes related to
content-trust
. The results of the signature verification are displayed in the MCR daemon logs.enforced
Content trust is enforced, thus an image that cannot be verified successfully is not pulled or run.
{
"content-trust": {
"mode": "<variable-type>"
}
}
Official Docker images¶
Note
The IDs of all Notary root keys that are used to verify Docker Official Images are embedded in MCR.
If you want to configure MCR so that only Docker Official Images can be used, you can configure your daemon to do so using the embedded key IDs:
{
"content-trust": {
"trust-pinning": {
"official-library-images": true
},
"mode": "enforced"
}
}
User-signed images¶
There are two options for trust pinning user-signed images: Notary Canonical Root Key ID and Notary Root key ID.
Notary canonical root key ID¶
The Notary Canonical Root Key ID, or DCT Root Key, describes only the root key
used to sign a repository, or rather its respective keys. This is the root key
on the host that originally signed the repository, such as your workstation. It
can be retrieved from the workstation that signed the repository through
$ grep -r "root" ~/.docker/trust/private/ (assuming your trust data
is at ~/.docker/trust/*
). It is expected that this canonical ID has
initiated multiple image repositories (mymsr/user1/image1 and
mymsr/user1/image2
).
Retrieve root ID:
$ grep -r "root" ~/.docker/trust/private /home/ubuntu/.docker/trust/private/0b6101527b2ac766702e4b40aa2391805b70e5031c04714c748f914e89014403.key:role: root
Use a canonical ID. In the example that follows, the canonical ID has signed two repos,
mymsr/user1/repo1
andmymsr/user1/repo2
. Note that wildcards are allowed.{ "content-trust": { "trust-pinning": { "root-keys": { "mymsr/user1/*": [ "0b6101527b2ac766702e4b40aa2391805b70e5031c04714c748f914e89014403" ] } }, "mode": "enforced" } }
Notary root key ID¶
The Notary Root key ID, or DCT Certificate ID, describes the same as the Notary
Canonical Root Key ID; the ID is unique per repository. For example,
mymsr/user1/image1
and mymsr/usr1/image2
will each have a unique
certificate ID. A certificate ID can be retrieved through a $ docker
trust inspect command, labeled as a root-key, referring back to the
Notary key name. This is designed for when different users are signing their
own repositories, such as when there is no central signing server. As a
cert-id
is more granular, it would take priority if a conflict occurs over
a root ID.
Retrieve root ID:
$ docker trust inspect mymsr/user1/repo1 | jq -r '.[].AdministrativeKeys[] | select(.Name=="Root") | .Keys[].ID' 9430d6e31e3b3e240957a1b62bbc2d436aafa33726d0fcb50addbf7e2dfa2168
Use cert IDs by specifying two repositories with their DCT root ID.
{ "content-trust": { "trust-pinning": { "cert-ids": { "mymsr/user1/repo1": [ "9430d6e31e3b3e240957a1b62bbc2d436aafa33726d0fcb50addbf7e2dfa2168" ], "mymsr/user2/repo1": [ "544cf09f294860f9d5bc953ad80b386063357fd206b37b541bb2c54166f38d08" ] } }, "mode": "enforced" } }
Using DCT in an offline environment¶
If your engine is unable to communicate to the registry, DCT can be enabled to
trust cached signature data. This is configured through the
allow-expired-cached-trust-data
option.
{
"content-trust": {
"trust-pinning": {
"official-library-images": true,
"root-keys": {
"mymsr/user1/*": [
"0b6101527b2ac766702e4b40aa2391805b70e5031c04714c748f914e89014403"
]
},
"cert-ids": {
"mymsr/user2/repo1": [
"9430d6e31e3b3e240957a1b62bbc2d436aafa33726d0fcb50addbf7e2dfa2168"
],
}
},
"mode": "enforced",
"allow-expired-cached-trust-data": true
}
}