docs/ee/dtr/user/manage-images/sign-images/trust-with-remote-ucp.md

10 KiB

title description keywords
Using Docker Content Trust with a Remote UCP Cluster Learn how to use a single DTR's trust data with remote UCPs. registry, sign, trust, notary

For more advanced deployments, you may want to share one Docker Trusted Registry across multiple Universal Control Planes. However, customers wanting to adopt this model, alongside the Only Run Signed Images feature of UCP, run into problems as each Universal Control Plane operates an independent set of users.

Docker Content Trust with a Remote UCP gets around this problem, as User's from a remote UCP are able to sign images in the central DTR, and still apply runtime enforcement.

In the following example we will connect DTR to 1 remote UCP cluster, however this process can be repeated over and over with more remote UCPs.

Before attempting this guide, please familiarize yourself with Docker Content Trust and Only Run Signed Images on a single UCP. A lot of the concepts within this guide may be new without that background.

Prerequisites

  • Cluster 1, running UCP 3.0.x or higher, with a DTR 2.5.x or higher deployed within the cluster.
  • Cluster 2, running UCP 3.0.x or higher, it is expected that there is no DTR installed on this environment.
  • Nodes on Cluster 2 need to trust the Certificate Authority that signed DTR's TLS Certificate. This can be tested by logging on to a Cluster 2 virtual machine and running curl https://dtr.example.com.
  • The DTR TLS Certificate needs be properly configured, ensuring that the Loadbalancer/Public Address field has been configured, with this address included within the certificate.
  • A workstation with the Docker Client (CE 17.12 / EE 1803 or newer) installed, as this contains the relevant $ docker trust commands.

Registering DTR with a remote Universal Control Plane

As there is no registry running within Cluster 2, by default UCP will not know where to check for trust data. Therefore, the first thing we need to do is register DTR within the Universal Control Plane of Cluster 2. When you normally install Docker Trusted Registry, this registration process happens by default to a local UCP.

The registration process allows the remote UCP to get signature data from DTR, however this will not provide Single Sign On, Users on Cluster 2 will not be synced with Cluster 1's Universal Control Plane or Docker Trusted Registry. Therefore when pulling images, if the repository is private, registry authentication will still need to be passed as part of the service definition.

To add a new registry, the first thing we need to retrieve is the Certificate Authority used to sign the DTR TLS Certificate. This can be done through DTR's /ca endpoint.

$ curl -ks https://dtr.example.com/ca > dtr.crt

Next we need to convert this DTR certificate into a JSON configuration file, this can then be used to register DTR within the 2nd Clusters Universal Control Plane.

A template of the json file called dtr-bundle.json is found below. Please replace the host address with the relevant URL, and enter the contents of the DTR CA certificate between the new line commands \n and \n.

Note within the json file, ensure there are no line breaks between each line of the DTR CA certificate.

$ cat dtr-bundle.json
{
  "hostAddress": "dtr.example.com",
  "caBundle": "-----BEGIN CERTIFICATE-----\n<contents of cert>\n-----END CERTIFICATE-----"
}

Now we will upload this configuration file to Cluster 2's Universal Control Plane using the UCP API endpoint /api/config/trustedregistry_. To authenticate against the API of Cluster 2's UCP, we have downloaded a UCP client bundle, extracted it in the current directory, and will reference the keys for authentication.

$ curl --cacert ca.pem --cert cert.pem --key key.pem \
    -X POST \
    -H "Accept: application/json" \
    -H "Content-Type: application/json" \
    -d @dtr-bundle.json \
    https://cluster2.example.com/api/config/trustedregistry_

To check this has been imported successfully, as the UCP endpoint will not output anything, we can check within Cluster 2's UCP UI. Select Admin in the top left hand corner, select Admin Settings and the finally select Docker Trusted Registry. If the registry has been added successfully we should see the DTR listed.

{: .with-border}

You could also check the full configuration file within Cluster 2's UCP. Once downloaded the ucp-config.toml file should now contain a section called [registries]

$ curl --cacert ca.pem --cert cert.pem --key key.pem https://cluster2.example.com/api/ucp/config-toml > ucp-config.toml

If the new registry isn't shown in the list, please check the logs of the ucp-controller container running on Cluster 2.

Signing an image in DTR

We will now sign an image and push this to DTR, to sign images we need a User's key pair from Cluster 2. Key pairs can be found in a client bundle, with the key.pem being a private key, and cert.pem being the public key within a x509 certificate.

First we load the Private key into the local Docker trust store (~/.docker/trust). The name used here is purely metadata to help keep track of which keys you have imported.

$ docker trust key load --name cluster2admin key.pem
Loading key from "key.pem"...
Enter passphrase for new cluster2admin key with ID a453196:
Repeat passphrase for new cluster2admin key with ID a453196:
Successfully imported key from key.pem

Next we will initiate the repository, and add the public key of Cluster 2's User as a signer. You will be asked for a number of passphrases to protect the keys. Please keep note of these passphrases, and to learn more about managing Keys head to the Docker Content Trust documentation here.

$ docker trust signer add --key cert.pem cluster2admin dtr.example.com/admin/trustdemo
Adding signer "cluster2admin" to dtr.example.com/admin/trustdemo...
Initializing signed repository for dtr.example.com/admin/trustdemo...
Enter passphrase for root key with ID 4a72d81:
Enter passphrase for new repository key with ID dd4460f:
Repeat passphrase for new repository key with ID dd4460f:
Successfully initialized "dtr.example.com/admin/trustdemo"
Successfully added signer: cluster2admin to dtr.example.com/admin/trustdemo

Finally we will sign an image tag. This pushes the image up to DTR, as well as signing the tag with the User from Cluster 2's keys.

$ docker trust sign dtr.example.com/admin/trustdemo:1
Signing and pushing trust data for local image dtr.example.com/admin/trustdemo:1, may overwrite remote trust data
The push refers to repository [dtr.olly.dtcntr.net/admin/trustdemo]
27c0b07c1b33: Layer already exists
aa84c03b5202: Layer already exists
5f6acae4a5eb: Layer already exists
df64d3292fd6: Layer already exists
1: digest: sha256:37062e8984d3b8fde253eba1832bfb4367c51d9f05da8e581bd1296fc3fbf65f size: 1153
Signing and pushing trust metadata
Enter passphrase for cluster2admin key with ID a453196:
Successfully signed dtr.example.com/admin/trustdemo:1

Within the DTR UI, you should now be able to see a new tag has been pushed, as well as the Signed icon next to the size.

{: .with-border}

We could sign this image multiple times if required, whether there were multiple teams from the same Cluster that wanted to sign the image, or you wanted to integrate DTR with more remote UCP's, and therefore a User from Cluster 1, Cluster 2, Cluster 3...etc can all to sign the same image.

Enforce Signed Image Tags on the Remote UCP

We can now enable Only Run Signed Images on the Remote UCP. To do this, login to Cluster 2's UCP UI as an Admin user, select Admin in the top left hand corner, select Admin Settings and then go down to Docker Content Trust.

For more information on Only Run Signed Images in UCP, refer to the UCP Documentation.

{: .with-border}

Finally we are in a position to deploy a workload on Cluster 2, using a signed image from a DTR running Cluster 1. This workload could be a simple $ docker run, a Swarm Service or a Kubernetes workload. As a simple test, source a client bundle, and try and run one of your signed images.

$ source env.sh

$ docker service create dtr.example.com/admin/trustdemo:1
nqsph0n6lv9uzod4lapx0gwok
overall progress: 1 out of 1 tasks
1/1: running   [==================================================>]
verify: Service converged

$ docker service ls
ID                  NAME                    MODE                REPLICAS            IMAGE                                   PORTS
nqsph0n6lv9u        laughing_lamarr         replicated          1/1                 dtr.example.com/admin/trustdemo:1

Troubleshooting

  1. If the image is stored in a Private Repository within DTR, as there is no Single Sign On between Cluster 2 and DTR, you need to pass credentials to the Orchestrator. This is either via --with-registry-auth for swarm, or as a Kubernetes Secret.

  2. If you see:

image or trust data does not exist for dtr.example.com/admin/trustdemo:1

This means something went wrong when initiating the repository or signing the image, as the tag contains no signing data.

  1. If you see:
Error response from daemon: image did not meet required signing policy

dtr.example.com/admin/trustdemo:1: image did not meet required signing policy 

This means that the image was signed correctly, however the User that signed the image does not mean the signing policy in Cluster 2. This could be because you signed the Image with the wrong Users Keys.

Where to go next