Answers: <h2>tl;dr</h2>
  <p>You can execute the following to pin the public root key for <code>debian</code>:</p>
  <pre><code>sudo su -
  mkdir -p /root/.docker/trust/tuf/docker.io/library/debian/metadata
  chown -R root:root /root/.docker
  chmod -R 0700 /root/.docker
  echo '{&quot;signed&quot;:{&quot;_type&quot;:&quot;Root&quot;,&quot;consistent_snapshot&quot;:false,&quot;expires&quot;:&quot;2025-08-07T20:55:22.677722315-07:00&quot;,&quot;keys&quot;:{&quot;5717dcd81d9fb5b73aa15f2d887a6a0de543829ab9b2d411acce9219c2f8ba3a&quot;:{&quot;keytype&quot;:&quot;ecdsa&quot;,&quot;keyval&quot;:{&quot;private&quot;:null,&quot;public&quot;:&quot;MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEsslGF2xHOYztrocb2OsRF2zth16v170QiLAyKdce1nQgOJ34FOk679ClPL9/RNnJukf2JfQXSlVV/qcsvxV2dQ==&quot;}},&quot;575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84&quot;:{&quot;keytype&quot;:&quot;ecdsa-x509&quot;,&quot;keyval&quot;:{&quot;private&quot;:null,&quot;public&quot;:&quot;LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJlVENDQVIrZ0F3SUJBZ0lRWExkUFFHTGJaOE84UXFlTzVuZlBRekFLQmdncWhrak9QUVFEQWpBak1TRXcKSHdZRFZRUURFeGhrYjJOclpYSXVhVzh2YkdsaWNtRnllUzlrWldKcFlXNHdIaGNOTVRVd09ERXhNRE0xTlRJeQpXaGNOTWpVd09EQTRNRE0xTlRJeVdqQWpNU0V3SHdZRFZRUURFeGhrYjJOclpYSXVhVzh2YkdsaWNtRnllUzlrClpXSnBZVzR3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVE1ZGkxcmxPQjBMQmRNS2N0VFQxYmwKUGd6aXYxOUJDdW9tNEFNL3BUdURtdjBnS0E5S1ptNUVjLy9VQmhSODVCYmR0cTk0cXhQM3IwUjhRc3FQV1Y4SQpvelV3TXpBT0JnTlZIUThCQWY4RUJBTUNBS0F3RXdZRFZSMGxCQXd3Q2dZSUt3WUJCUVVIQXdNd0RBWURWUjBUCkFRSC9CQUl3QURBS0JnZ3Foa2pPUFFRREFnTklBREJGQWlBOUFOZ3dPN2tBdUVIK3U2N25XNlFLWmlMdWd5UVcKaEQ3Vys5WjIza01mTndJaEFJa3RTaW1TdFdRQkFoOG9WOXhjaWNVWWVUN0pyUG82a0RqeHU1YitGZ3MxCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K&quot;}},&quot;728c96ff5e9f48d4e66d5a0c3ecabfdd90bee2b5f9f80b950ed9c668db264a70&quot;:{&quot;keytype&quot;:&quot;ecdsa&quot;,&quot;keyval&quot;:{&quot;private&quot;:null,&quot;public&quot;:&quot;MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENtpBkDJ2oYaAAVdOkP0A6J0XwUkYGuFRk+q8N4WCPu2VnNIuBJkatPCWdEtHfQ9nNYLeanWgG62/UmJnx3E2Yg==&quot;}},&quot;d48327d85f0490827db7c931eedb58d293e1da5fc425ea0cde3e6c13b397ad69&quot;:{&quot;keytype&quot;:&quot;ecdsa&quot;,&quot;keyval&quot;:{&quot;private&quot;:null,&quot;public&quot;:&quot;MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwfs26T/cpjvNTXVJpK7Wv8oDOnNKL78AT3Y1QD356OIAggwPupX2LQjZU6CVzCjm+pkJIO4clu9Q2n540gKuzQ==&quot;}}},&quot;roles&quot;:{&quot;root&quot;:{&quot;keyids&quot;:[&quot;575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84&quot;],&quot;threshold&quot;:1},&quot;snapshot&quot;:{&quot;keyids&quot;:[&quot;d48327d85f0490827db7c931eedb58d293e1da5fc425ea0cde3e6c13b397ad69&quot;],&quot;threshold&quot;:1},&quot;targets&quot;:{&quot;keyids&quot;:[&quot;5717dcd81d9fb5b73aa15f2d887a6a0de543829ab9b2d411acce9219c2f8ba3a&quot;],&quot;threshold&quot;:1},&quot;timestamp&quot;:{&quot;keyids&quot;:[&quot;728c96ff5e9f48d4e66d5a0c3ecabfdd90bee2b5f9f80b950ed9c668db264a70&quot;],&quot;threshold&quot;:1}},&quot;version&quot;:1},&quot;signatures&quot;:[{&quot;keyid&quot;:&quot;575d013f89e3cbbb19e0fb06aa33566c22718318e0c9f
  fb1ab5cc4291e07bf84&quot;,&quot;method&quot;:&quot;ecdsa&quot;,&quot;sig&quot;:&quot;3WbX1VXN9E8LRmSG+E4SQlBUNqBNchhwAStWnRWLLyAOoFNBq5xmIgSO3UYYuKyJvL7kbMoONRbn5Vk2p2Wqrg==&quot;}]}' &gt; /root/.docker/trust/tuf/docker.io/library/debian/metadata/root.json
  
  export DOCKER_CONTENT_TRUST=1
  docker pull debian:stable-slim
  </code></pre>
  <h2>Long Answer</h2>
  <blockquote>
  <p>⚠ Disclaimer: I am not a docker developer. As of 2021, it appears that DCT is broken out-of-the-box and is far from being useful. My answer here is a best-guess, but I have not confirmed with the docker team if this is the &quot;correct&quot; way to pre-load and pin a given publisher's root key into the DCT keyring.</p>
  <p>Be advised, proceed with caution, and your comments are very welcome.</p>
  </blockquote>
  <p>It doesn't appear to be documented anywhere, but per <a href="https://security.stackexchange.com/questions/238916/how-to-pin-public-root-key-when-downloading-an-image-with-docker-pull-docker-co?noredirect=1&amp;lq=1">this question</a> it's clear that docker puts its DCT metadata (including root public keys) in the following location:</p>
  <pre><code>$HOME/.docker/trust/tuf/docker.io/library
  </code></pre>
  <p>Inside this <code>library</code> dir exists one dir per publisher. For the purposes of this answer, I'll use <code>debian</code> as our example publisher.</p>
  <p>You can see the list of the <code>debian</code> docker images published to Docker Hub here:</p>
  <ul>
  <li><a href="https://hub.docker.com/_/debian/" rel="nofollow noreferrer">https://hub.docker.com/_/debian/</a></li>
  </ul>
  <h3>Solution</h3>
  <p>Let's say we want to download the <code>stable-slim</code> image from the <code>debian</code> publisher on Docker Hub. In this example, we'll also use a fresh install of Debian 10 as the docker host.</p>
  <pre><code>##
  # first, install docker
  ## 
  root@disp2716:~# apt-get install docker.io
  ...
  root@disp2716:~#
  
  ##
  # confirm that there is no docker config dir yet
  ##
  
  root@disp2716:~# ls -lah /root/.docker
  ls: cannot access '/root/.docker': No such file or directory
  root@disp2716:~# 
  
  ##
  # add the debian publisher's root DCT key
  ##
  
  root@disp2716:~# mkdir -p /root/.docker/trust/tuf/docker.io/library/debian/metadata
  root@disp2716:~# chown -R root:root /root/.docker
  root@disp2716:~# chmod -R 0700 /root/.docker
  root@disp2716:~# echo '{&quot;signed&quot;:{&quot;_type&quot;:&quot;Root&quot;,&quot;consistent_snapshot&quot;:false,&quot;expires&quot;:&quot;2025-08-07T20:55:22.677722315-07:00&quot;,&quot;keys&quot;:{&quot;5717dcd81d9fb5b73aa15f2d887a6a0de543829ab9b2d411acce9219c2f8ba3a&quot;:{&quot;keytype&quot;:&quot;ecdsa&quot;,&quot;keyval&quot;:{&quot;private&quot;:null,&quot;public&quot;:&quot;MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEsslGF2xHOYztrocb2OsRF2zth16v170QiLAyKdce1nQgOJ34FOk679ClPL9/RNnJukf2JfQXSlVV/qcsvxV2dQ==&quot;}},&quot;575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84&quot;:{&quot;keytype&quot;:&quot;ecdsa-x509&quot;,&quot;keyval&quot;:{&quot;private&quot;:null,&quot;public&quot;:&quot;LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJlVENDQVIrZ0F3SUJBZ0lRWExkUFFHTGJaOE84UXFlTzVuZlBRekFLQmdncWhrak9QUVFEQWpBak1TRXcKSHdZRFZRUURFeGhrYjJOclpYSXVhVzh2YkdsaWNtRnllUzlrWldKcFlXNHdIaGNOTVRVd09ERXhNRE0xTlRJeQpXaGNOTWpVd09EQTRNRE0xTlRJeVdqQWpNU0V3SHdZRFZRUURFeGhrYjJOclpYSXVhVzh2YkdsaWNtRnllUzlrClpXSnBZVzR3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVE1ZGkxcmxPQjBMQmRNS2N0VFQxYmwKUGd6aXYxOUJDdW9tNEFNL3BUdURtdjBnS0E5S1ptNUVjLy9VQmhSODVCYmR0cTk0cXhQM3IwUjhRc3FQV1Y4SQpvelV3TXpBT0JnTlZIUThCQWY4RUJBTUNBS0F3RXdZRFZSMGxCQXd3Q2dZSUt3WUJCUVVIQXdNd0RBWURWUjBUCkFRSC9CQUl3QURBS0JnZ3Foa2pPUFFRREFnTklBREJGQWlBOUFOZ3dPN2tBdUVIK3U2N25XNlFLWmlMdWd5UVcKaEQ3Vys5WjIza01mTndJaEFJa3RTaW1TdFdRQkFoOG9WOXhjaWNVWWVUN0pyUG82a0RqeHU1YitGZ3MxCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K&quot;}},&quot;728c96ff5e9f48d4e66d5a0c3ecabfdd90bee2b5f9f80b950ed9c668db264a70&quot;:{&quot;keytype&quot;:&quot;ecdsa&quot;,&quot;keyval&quot;:{&quot;private&quot;:null,&quot;public&quot;:&quot;MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENtpBkDJ2oYaAAVdOkP0A6J0XwUkYGuFRk+q8N4WCPu2VnNIuBJkatPCWdEtHfQ9nNYLeanWgG62/UmJnx3E2Yg==&quot;}},&quot;d48327d85f0490827db7c931eedb58d293e1da5fc425ea0cde3e6c13b397ad69&quot;:{&quot;keytype&quot;:&quot;ecdsa&quot;,&quot;keyval&quot;:{&quot;private&quot;:null,&quot;public&quot;:&quot;MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwfs26T/cpjvNTXVJpK7Wv8oDOnNKL78AT3Y1QD356OIAggwPupX2LQjZU6CVzCjm+pkJIO4clu9Q2n540gKuzQ==&quot;}}},&quot;roles&quot;:{&quot;root&quot;:{&quot;keyids&quot;:[&quot;575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84&quot;],&quot;threshold&quot;:1},&quot;snapshot&quot;:{&quot;keyids&quot;:[&quot;d48327d85f0490827db7c931eedb58d293e1da5fc425ea0cde3e6c13b397ad69&quot;],&quot;threshold&quot;:1},&quot;targets&quot;:{&quot;keyids&quot;:[&quot;5717dcd81d9fb5b73aa15f2d887a6a0de543829ab9b2d411acce9219c2f8ba3a&quot;],&quot;threshold&quot;:1},&quot;timestamp&quot;:{&quot;keyids&quot;:[&quot;728c96ff5e9f48d4e66d5a0c3ecabfdd90bee2b5f9f80b950ed9c668db264a70&quot;],&quot;threshold&quot;:1}},&quot;version&quot;:1},&quot;signatures&quot;:[{&quot;keyid&quot;:&quot;575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84&quot;,&quot;method&quot;:&quot;ecdsa&quot;,&quot;sig&quot;:&quot;3WbX1VXN9E8LRmSG+E4SQlBUNqBNchhwAStWnRWLLyAOoFNBq5xmIgSO3UYYuKyJvL7kbMoONRbn5Vk2p2Wqrg==&quot;}]}' &gt; /root/.docker/trust/tuf/docker.io/library/debian/metadata/root.json
  root@disp2716:~# 
  root@disp2716:~# chown root:root /root/.docker/trust/tuf/docker.io/library/debian/metadata/root.json
  root@disp2716:~# chmod 0600 /root/.docker/trust/tuf/docker.io/library/debian/metadata/root.json
  root@disp2716:~# 
  
  ##
  # pull the docker image with DCT verification
  ##
  
  root@disp2716:~# export DOCKER_CONTENT_TRUST=1
  root@disp2716:~# docker pull debian:stable-slim
  Pull (1 of 1): debian:stable-slim@sha256:850a7ee21c49c99b0e5e06df21f898a0e64335ae84eb37d6f71abc1bf28f5632
  sha256:850a7ee21c49c99b0e5e06df21f898a0e64335ae84eb37d6f71abc1bf28f5632: Pulling from library/debian
  6e640006d1cd: Pull complete 
  Digest: sha256:850a7ee21c49c99b0e5e06df21f898a0e64335ae84eb37d6f71abc1bf28f5632
  Status: Downloaded newer image for debian@sha256:850a7ee21c49c99b0e5e06df21f898a0e64335ae84eb37d6f71abc1bf28f5632
  Tagging debian@sha256:850a7ee21c49c99b0e5e06df21f898a0e64335ae84eb37d6f71abc1bf28f5632 as debian:stable-slim
  root@disp2716:~# 
  </code></pre>
  <h3>Proof</h3>
  <p>While there's <a href="https://github.com/docker/cli/issues/2752" rel="nofollow noreferrer">no way to tell <code>docker</code> to fail on TOFU</a>, we can confirm that the above key pinning works by making the public key something else</p>
  <pre><code>##
  # first, move the docker config dir out of the way
  ## 
  
  mv /root/.docker /root/.docker.bak
  
  ##
  # add the debian publisher's root DCT key (note I just overwrote the first 8
  # characters of the actual key with &quot;INVALID/&quot;)
  ##
  
  root@disp2716:~# mkdir -p /root/.docker/trust/tuf/docker.io/library/debian/metadata
  root@disp2716:~# chown -R root:root /root/.docker
  root@disp2716:~# chmod -R 0700 /root/.docker
  root@disp2716:~# echo '{&quot;signed&quot;:{&quot;_type&quot;:&quot;Root&quot;,&quot;consistent_snapshot&quot;:false,&quot;expires&quot;:&quot;2025-08-07T20:55:22.677722315-07:00&quot;,&quot;keys&quot;:{&quot;5717dcd81d9fb5b73aa15f2d887a6a0de543829ab9b2d411acce9219c2f8ba3a&quot;:{&quot;keytype&quot;:&quot;ecdsa&quot;,&quot;keyval&quot;:{&quot;private&quot;:null,&quot;public&quot;:&quot;INVALID/KoZIzj0CAQYIKoZIzj0DAQcDQgAEsslGF2xHOYztrocb2OsRF2zth16v170QiLAyKdce1nQgOJ34FOk679ClPL9/RNnJukf2JfQXSlVV/qcsvxV2dQ==&quot;}},&quot;575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84&quot;:{&quot;keytype&quot;:&quot;ecdsa-x509&quot;,&quot;keyval&quot;:{&quot;private&quot;:null,&quot;public&quot;:&quot;INVALID/RUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJlVENDQVIrZ0F3SUJBZ0lRWExkUFFHTGJaOE84UXFlTzVuZlBRekFLQmdncWhrak9QUVFEQWpBak1TRXcKSHdZRFZRUURFeGhrYjJOclpYSXVhVzh2YkdsaWNtRnllUzlrWldKcFlXNHdIaGNOTVRVd09ERXhNRE0xTlRJeQpXaGNOTWpVd09EQTRNRE0xTlRJeVdqQWpNU0V3SHdZRFZRUURFeGhrYjJOclpYSXVhVzh2YkdsaWNtRnllUzlrClpXSnBZVzR3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVE1ZGkxcmxPQjBMQmRNS2N0VFQxYmwKUGd6aXYxOUJDdW9tNEFNL3BUdURtdjBnS0E5S1ptNUVjLy9VQmhSODVCYmR0cTk0cXhQM3IwUjhRc3FQV1Y4SQpvelV3TXpBT0JnTlZIUThCQWY4RUJBTUNBS0F3RXdZRFZSMGxCQXd3Q2dZSUt3WUJCUVVIQXdNd0RBWURWUjBUCkFRSC9CQUl3QURBS0JnZ3Foa2pPUFFRREFnTklBREJGQWlBOUFOZ3dPN2tBdUVIK3U2N25XNlFLWmlMdWd5UVcKaEQ3Vys5WjIza01mTndJaEFJa3RTaW1TdFdRQkFoOG9WOXhjaWNVWWVUN0pyUG82a0RqeHU1YitGZ3MxCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K&quot;}},&quot;728c96ff5e9f48d4e66d5a0c3ecabfdd90bee2b5f9f80b950ed9c668db264a70&quot;:{&quot;keytype&quot;:&quot;ecdsa&quot;,&quot;keyval&quot;:{&quot;private&quot;:null,&quot;public&quot;:&quot;INVALID/KoZIzj0CAQYIKoZIzj0DAQcDQgAENtpBkDJ2oYaAAVdOkP0A6J0XwUkYGuFRk+q8N4WCPu2VnNIuBJkatPCWdEtHfQ9nNYLeanWgG62/UmJnx3E2Yg==&quot;}},&quot;d48327d85f0490827db7c931eedb58d293e1da5fc425ea0cde3e6c13b397ad69&quot;:{&quot;keytype&quot;:&quot;ecdsa&quot;,&quot;keyval&quot;:{&quot;private&quot;:null,&quot;public&quot;:&quot;INVALID/KoZIzj0CAQYIKoZIzj0DAQcDQgAEwfs26T/cpjvNTXVJpK7Wv8oDOnNKL78AT3Y1QD356OIAggwPupX2LQjZU6CVzCjm+pkJIO4clu9Q2n540gKuzQ==&quot;}}},&quot;roles&quot;:{&quot;root&quot;:{&quot;keyids&quot;:[&quot;575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84&quot;],&quot;threshold&quot;:1},&quot;snapshot&quot;:{&quot;keyids&quot;:[&quot;d48327d85f0490827db7c931eedb58d293e1da5fc425ea0cde3e6c13b397ad69&quot;],&quot;threshold&quot;:1},&quot;targets&quot;:{&quot;keyids&quot;:[&quot;5717dcd81d9fb5b73aa15f2d887a6a0de543829ab9b2d411acce9219c2f8ba3a&quot;],&quot;threshold&quot;:1},&quot;timestamp&quot;:{&quot;keyids&quot;:[&quot;728c96ff5e9f48d4e66d5a0c3ecabfdd90bee2b5f9f80b950ed9c668db264a70&quot;],&quot;threshold&quot;:1}},&quot;version&quot;:1},&quot;signatures&quot;:[{&quot;keyid&quot;:&quot;575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84&quot;,&quot;method&quot;:&quot;ecdsa&quot;,&quot;sig&quot;:&quot;3WbX1VXN9E8LRmSG+E4SQlBUNqBNchhwAStWnRWLLyAOoFNBq5xmIgSO3UYYuKyJvL7kbMoONRbn5Vk2p2Wqrg==&quot;}]}' &gt; /root/.docker/trust/tuf/docker.io/library/debian/metadata/root.json
  root@disp2716:~# 
  root@disp2716:~# chown root:root /root/.docker/trust/tuf/docker.io/library/debian/metadata/root.json
  root@disp2716:~# chmod 0600 /root/.docker/trust/tuf/docker.io/library/debian/metadata/root.json
  root@disp2716:~# 
  
  ##
  # pull the docker image with DCT verification
  ##
  
  root@disp2716:~# export DOCKER_CONTENT_TRUST=1
  root@disp2716:~# docker pull debian:stable-slim
  could not validate the path to a trusted root: unable to retrieve valid leaf certificates
  root@disp2716:~# 
  root@disp2716:~# echo $?
  1
  root@disp2716:~# 
  </code></pre>
  <p>Note that docker exits 1 with an error refusing to pull the <code>debian:stable-slim</code> docker image from Docker Hub because it cannot trust its signature</p>
  
Answers: CC BY-SA 4.0
Answers: 2021-05-25T15:34:49.273Z
Answers: This doesn't answer how to actually obtain the `root.json` file. For that, see https://devops.stackexchange.com/questions/13990/docker-how-to-download-verify-a-publishers-root-key-out-of-band-distinct-d
Answers: Michael Altfield
Answers: CC BY-SA 4.0
Answers: 2021-05-25T14:36:48.930Z
Answers: 2021-05-25T15:20:46.387Z
Answers: 2021-05-25T15:20:46.387Z
Answers: Michael Altfield
Body: <p>How can I execute <code>docker pull</code> (with Docker Content Trust enabled) such that it fails if the image doesn't have a valid signature using the private key corresponding to (or subordinate to) the public key that I provide?</p>
  <p>I just discovered that, in fact, <a href="https://security.stackexchange.com/questions/238529/how-to-list-all-of-the-known-root-keys-in-docker-docker-content-trust">DCT silently and dumbly downloads and trusts (TOFU) the root key when downloading an image for the first time.</a></p>
  <p>My application for docker is a CI process that will use the <code>debian:stable-latest</code> docker image to build my application's releases in ephemeral cloud instances. Because the server used to build my application is ephemeral, DCT literally provides me zero security and it will be vulnerable to a MITM of the docker image payload on <em>every</em> execution of my build process.</p>
  <p>Therefore, it's critical that I pin the public root key used by Debian to sign their docker images. So the questions are:</p>
  <ol>
  <li>How do I download the public root key used by Debian to sign their docker images and</li>
  <li>How do I tell <code>docker pull</code> to use the above key and fail if the image doesn't contain a valid signature from that key or a key that's downchain from the supplied root key?</li>
  </ol>
  
Tags: <docker><linux><release-management><docker-registry>
Title: How to pin public root key when downloading an image with docker pull (Docker Content Trust)?
UserDisplayName: Michael Altfield
ThreadText: # How to pin public root key when downloading an image with docker pull (Docker Content Trust)?
  
  (Asked by: username_0 on 2021-05-25)
  
  How can I execute `docker pull` (with Docker Content Trust enabled) such that it fails if the image doesn't have a valid signature using the private key corresponding to (or subordinate to) the public key that I provide?
  
  I just discovered that, in fact, [DCT silently and dumbly downloads and trusts (TOFU) the root key when downloading an image for the first time.](https://security.stackexchange.com/questions/238529/how-to-list-all-of-the-known-root-keys-in-docker-docker-content-trust)
  
  My application for docker is a CI process that will use the `debian:stable-latest` docker image to build my application's releases in ephemeral cloud instances. Because the server used to build my application is ephemeral, DCT literally provides me zero security and it will be vulnerable to a MITM of the docker image payload on *every* execution of my build process.
  
  Therefore, it's critical that I pin the public root key used by Debian to sign their docker images. So the questions are:
  
  1. How do I download the public root key used by Debian to sign their docker images and
  2. How do I tell `docker pull` to use the above key and fail if the image doesn't contain a valid signature from that key or a key that's downchain from the supplied root key?
  
  **Tags:** docker, linux, release-management, docker-registry
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_0 on 2021-05-25. Score: 2 | Accepted answer
  
  ## tl;dr
  
  You can execute the following to pin the public root key for `debian`:
  
  ```
  sudo su -
  mkdir -p /root/.docker/trust/tuf/docker.io/library/debian/metadata
  chown -R root:root /root/.docker
  chmod -R 0700 /root/.docker
  echo '{"signed":{"_type":"Root","consistent_snapshot":false,"expires":"2025-08-07T20:55:22.677722315-07:00","keys":{"5717dcd81d9fb5b73aa15f2d887a6a0de543829ab9b2d411acce9219c2f8ba3a":{"keytype":"ecdsa","keyval":{"private":null,"public":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEsslGF2xHOYztrocb2OsRF2zth16v170QiLAyKdce1nQgOJ34FOk679ClPL9/RNnJukf2JfQXSlVV/qcsvxV2dQ=="}},"575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84":{"keytype":"ecdsa-x509","keyval":{"private":null,"public":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJlVENDQVIrZ0F3SUJBZ0lRWExkUFFHTGJaOE84UXFlTzVuZlBRekFLQmdncWhrak9QUVFEQWpBak1TRXcKSHdZRFZRUURFeGhrYjJOclpYSXVhVzh2YkdsaWNtRnllUzlrWldKcFlXNHdIaGNOTVRVd09ERXhNRE0xTlRJeQpXaGNOTWpVd09EQTRNRE0xTlRJeVdqQWpNU0V3SHdZRFZRUURFeGhrYjJOclpYSXVhVzh2YkdsaWNtRnllUzlrClpXSnBZVzR3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVE1ZGkxcmxPQjBMQmRNS2N0VFQxYmwKUGd6aXYxOUJDdW9tNEFNL3BUdURtdjBnS0E5S1ptNUVjLy9VQmhSODVCYmR0cTk0cXhQM3IwUjhRc3FQV1Y4SQpvelV3TXpBT0JnTlZIUThCQWY4RUJBTUNBS0F3RXdZRFZSMGxCQXd3Q2dZSUt3WUJCUVVIQXdNd0RBWURWUjBUCkFRSC9CQUl3QURBS0JnZ3Foa2pPUFFRREFnTklBREJGQWlBOUFOZ3dPN2tBdUVIK3U2N25XNlFLWmlMdWd5UVcKaEQ3Vys5WjIza01mTndJaEFJa3RTaW1TdFdRQkFoOG9WOXhjaWNVWWVUN0pyUG82a0RqeHU1YitGZ3MxCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"}},"728c96ff5e9f48d4e66d5a0c3ecabfdd90bee2b5f9f80b950ed9c668db264a70":{"keytype":"ecdsa","keyval":{"private":null,"public":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENtpBkDJ2oYaAAVdOkP0A6J0XwUkYGuFRk+q8N4WCPu2VnNIuBJkatPCWdEtHfQ9nNYLeanWgG62/UmJnx3E2Yg=="}},"d48327d85f0490827db7c931eedb58d293e1da5fc425ea0cde3e6c13b397ad69":{"keytype":"ecdsa","keyval":{"private":null,"public":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwfs26T/cpjvNTXVJpK7Wv8oDOnNKL78AT3Y1QD356OIAggwPupX2LQjZU6CVzCjm+pkJIO4clu9Q2n540gKuzQ=="}}},"roles":{"root":{"keyids":["575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84"],"threshold":1},"snapshot":{"keyids":["d48327d85f0490827db7c931eedb58d293e1da5fc425ea0cde3e6c13b397ad69"],"threshold":1},"targets":{"keyids":["5717dcd81d9fb5b73aa15f2d887a6a0de543829ab9b2d411acce9219c2f8ba3a"],"threshold":1},"timestamp":{"keyids":["728c96ff5e9f48d4e66d5a0c3ecabfdd90bee2b5f9f80b950ed9c668db264a70"],"threshold":1}},"version":1},"signatures":[{"keyid":"575d013f89e3cbbb19e0fb06aa33566c22718318e0c9f
  fb1ab5cc4291e07bf84","method":"ecdsa","sig":"3WbX1VXN9E8LRmSG+E4SQlBUNqBNchhwAStWnRWLLyAOoFNBq5xmIgSO3UYYuKyJvL7kbMoONRbn5Vk2p2Wqrg=="}]}' > /root/.docker/trust/tuf/docker.io/library/debian/metadata/root.json
  
  export DOCKER_CONTENT_TRUST=1
  docker pull debian:stable-slim
  
  ```
  
  ## Long Answer
  
  > ⚠ Disclaimer: I am not a docker developer. As of 2021, it appears that DCT is broken out-of-the-box and is far from being useful. My answer here is a best-guess, but I have not confirmed with the docker team if this is the "correct" way to pre-load and pin a given publisher's root key into the DCT keyring.
  >
  > Be advised, proceed with caution, and your comments are very welcome.
  
  It doesn't appear to be documented anywhere, but per [this question](https://security.stackexchange.com/questions/238916/how-to-pin-public-root-key-when-downloading-an-image-with-docker-pull-docker-co?noredirect=1&lq=1) it's clear that docker puts its DCT metadata (including root public keys) in the following location:
  
  ```
  $HOME/.docker/trust/tuf/docker.io/library
  
  ```
  
  Inside this `library` dir exists one dir per publisher. For the purposes of this answer, I'll use `debian` as our example publisher.
  
  You can see the list of the `debian` docker images published to Docker Hub here:
  
  * <https://hub.docker.com/_/debian/>
  
  ### Solution
  
  Let's say we want to download the `stable-slim` image from the `debian` publisher on Docker Hub. In this example, we'll also use a fresh install of Debian 10 as the docker host.
  
  ```
  ##
  # first, install docker
  ## 
  root@disp2716:~# apt-get install docker.io
  ...
  root@disp2716:~#
  
  ##
  # confirm that there is no docker config dir yet
  ##
  
  root@disp2716:~# ls -lah /root/.docker
  ls: cannot access '/root/.docker': No such file or directory
  root@disp2716:~# 
  
  ##
  # add the debian publisher's root DCT key
  ##
  
  root@disp2716:~# mkdir -p /root/.docker/trust/tuf/docker.io/library/debian/metadata
  root@disp2716:~# chown -R root:root /root/.docker
  root@disp2716:~# chmod -R 0700 /root/.docker
  root@disp2716:~# echo '{"signed":{"_type":"Root","consistent_snapshot":false,"expires":"2025-08-07T20:55:22.677722315-07:00","keys":{"5717dcd81d9fb5b73aa15f2d887a6a0de543829ab9b2d411acce9219c2f8ba3a":{"keytype":"ecdsa","keyval":{"private":null,"public":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEsslGF2xHOYztrocb2OsRF2zth16v170QiLAyKdce1nQgOJ34FOk679ClPL9/RNnJukf2JfQXSlVV/qcsvxV2dQ=="}},"575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84":{"keytype":"ecdsa-x509","keyval":{"private":null,"public":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJlVENDQVIrZ0F3SUJBZ0lRWExkUFFHTGJaOE84UXFlTzVuZlBRekFLQmdncWhrak9QUVFEQWpBak1TRXcKSHdZRFZRUURFeGhrYjJOclpYSXVhVzh2YkdsaWNtRnllUzlrWldKcFlXNHdIaGNOTVRVd09ERXhNRE0xTlRJeQpXaGNOTWpVd09EQTRNRE0xTlRJeVdqQWpNU0V3SHdZRFZRUURFeGhrYjJOclpYSXVhVzh2YkdsaWNtRnllUzlrClpXSnBZVzR3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVE1ZGkxcmxPQjBMQmRNS2N0VFQxYmwKUGd6aXYxOUJDdW9tNEFNL3BUdURtdjBnS0E5S1ptNUVjLy9VQmhSODVCYmR0cTk0cXhQM3IwUjhRc3FQV1Y4SQpvelV3TXpBT0JnTlZIUThCQWY4RUJBTUNBS0F3RXdZRFZSMGxCQXd3Q2dZSUt3WUJCUVVIQXdNd0RBWURWUjBUCkFRSC9CQUl3QURBS0JnZ3Foa2pPUFFRREFnTklBREJGQWlBOUFOZ3dPN2tBdUVIK3U2N25XNlFLWmlMdWd5UVcKaEQ3Vys5WjIza01mTndJaEFJa3RTaW1TdFdRQkFoOG9WOXhjaWNVWWVUN0pyUG82a0RqeHU1YitGZ3MxCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"}},"728c96ff5e9f48d4e66d5a0c3ecabfdd90bee2b5f9f80b950ed9c668db264a70":{"keytype":"ecdsa","keyval":{"private":null,"public":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENtpBkDJ2oYaAAVdOkP0A6J0XwUkYGuFRk+q8N4WCPu2VnNIuBJkatPCWdEtHfQ9nNYLeanWgG62/UmJnx3E2Yg=="}},"d48327d85f0490827db7c931eedb58d293e1da5fc425ea0cde3e6c13b397ad69":{"keytype":"ecdsa","keyval":{"private":null,"public":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwfs26T/cpjvNTXVJpK7Wv8oDOnNKL78AT3Y1QD356OIAggwPupX2LQjZU6CVzCjm+pkJIO4clu9Q2n540gKuzQ=="}}},"roles":{"root":{"keyids":["575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84"],"threshold":1},"snapshot":{"keyids":["d48327d85f0490827db7c931eedb58d293e1da5fc425ea0cde3e6c13b397ad69"],"threshold":1},"targets":{"keyids":["5717dcd81d9fb5b73aa15f2d887a6a0de543829ab9b2d411acce9219c2f8ba3a"],"threshold":1},"timestamp":{"keyids":["728c96ff5e9f48d4e66d5a0c3ecabfdd90bee2b5f9f80b950ed9c668db264a70"],"threshold":1}},"version":1},"signatures":[{"keyid":"575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84","method":"ecdsa","sig":"3WbX1VXN9E8LRmSG+E4SQlBUNqBNchhwAStWnRWLLyAOoFNBq5xmIgSO3UYYuKyJvL7kbMoONRbn5Vk2p2Wqrg=="}]}' > /root/.docker/trust/tuf/docker.io/library/debian/metadata/root.json
  root@disp2716:~# 
  root@disp2716:~# chown root:root /root/.docker/trust/tuf/docker.io/library/debian/metadata/root.json
  root@disp2716:~# chmod 0600 /root/.docker/trust/tuf/docker.io/library/debian/metadata/root.json
  root@disp2716:~# 
  
  ##
  # pull the docker image with DCT verification
  ##
  
  root@disp2716:~# export DOCKER_CONTENT_TRUST=1
  root@disp2716:~# docker pull debian:stable-slim
  Pull (1 of 1): debian:stable-slim@sha256:850a7ee21c49c99b0e5e06df21f898a0e64335ae84eb37d6f71abc1bf28f5632
  sha256:850a7ee21c49c99b0e5e06df21f898a0e64335ae84eb37d6f71abc1bf28f5632: Pulling from library/debian
  6e640006d1cd: Pull complete 
  Digest: sha256:850a7ee21c49c99b0e5e06df21f898a0e64335ae84eb37d6f71abc1bf28f5632
  Status: Downloaded newer image for debian@sha256:850a7ee21c49c99b0e5e06df21f898a0e64335ae84eb37d6f71abc1bf28f5632
  Tagging debian@sha256:850a7ee21c49c99b0e5e06df21f898a0e64335ae84eb37d6f71abc1bf28f5632 as debian:stable-slim
  root@disp2716:~# 
  
  ```
  
  ### Proof
  
  While there's [no way to tell `docker` to fail on TOFU](https://github.com/docker/cli/issues/2752), we can confirm that the above key pinning works by making the public key something else
  
  ```
  ##
  # first, move the docker config dir out of the way
  ## 
  
  mv /root/.docker /root/.docker.bak
  
  ##
  # add the debian publisher's root DCT key (note I just overwrote the first 8
  # characters of the actual key with "INVALID/")
  ##
  
  root@disp2716:~# mkdir -p /root/.docker/trust/tuf/docker.io/library/debian/metadata
  root@disp2716:~# chown -R root:root /root/.docker
  root@disp2716:~# chmod -R 0700 /root/.docker
  root@disp2716:~# echo '{"signed":{"_type":"Root","consistent_snapshot":false,"expires":"2025-08-07T20:55:22.677722315-07:00","keys":{"5717dcd81d9fb5b73aa15f2d887a6a0de543829ab9b2d411acce9219c2f8ba3a":{"keytype":"ecdsa","keyval":{"private":null,"public":"INVALID/KoZIzj0CAQYIKoZIzj0DAQcDQgAEsslGF2xHOYztrocb2OsRF2zth16v170QiLAyKdce1nQgOJ34FOk679ClPL9/RNnJukf2JfQXSlVV/qcsvxV2dQ=="}},"575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84":{"keytype":"ecdsa-x509","keyval":{"private":null,"public":"INVALID/RUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJlVENDQVIrZ0F3SUJBZ0lRWExkUFFHTGJaOE84UXFlTzVuZlBRekFLQmdncWhrak9QUVFEQWpBak1TRXcKSHdZRFZRUURFeGhrYjJOclpYSXVhVzh2YkdsaWNtRnllUzlrWldKcFlXNHdIaGNOTVRVd09ERXhNRE0xTlRJeQpXaGNOTWpVd09EQTRNRE0xTlRJeVdqQWpNU0V3SHdZRFZRUURFeGhrYjJOclpYSXVhVzh2YkdsaWNtRnllUzlrClpXSnBZVzR3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVE1ZGkxcmxPQjBMQmRNS2N0VFQxYmwKUGd6aXYxOUJDdW9tNEFNL3BUdURtdjBnS0E5S1ptNUVjLy9VQmhSODVCYmR0cTk0cXhQM3IwUjhRc3FQV1Y4SQpvelV3TXpBT0JnTlZIUThCQWY4RUJBTUNBS0F3RXdZRFZSMGxCQXd3Q2dZSUt3WUJCUVVIQXdNd0RBWURWUjBUCkFRSC9CQUl3QURBS0JnZ3Foa2pPUFFRREFnTklBREJGQWlBOUFOZ3dPN2tBdUVIK3U2N25XNlFLWmlMdWd5UVcKaEQ3Vys5WjIza01mTndJaEFJa3RTaW1TdFdRQkFoOG9WOXhjaWNVWWVUN0pyUG82a0RqeHU1YitGZ3MxCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"}},"728c96ff5e9f48d4e66d5a0c3ecabfdd90bee2b5f9f80b950ed9c668db264a70":{"keytype":"ecdsa","keyval":{"private":null,"public":"INVALID/KoZIzj0CAQYIKoZIzj0DAQcDQgAENtpBkDJ2oYaAAVdOkP0A6J0XwUkYGuFRk+q8N4WCPu2VnNIuBJkatPCWdEtHfQ9nNYLeanWgG62/UmJnx3E2Yg=="}},"d48327d85f0490827db7c931eedb58d293e1da5fc425ea0cde3e6c13b397ad69":{"keytype":"ecdsa","keyval":{"private":null,"public":"INVALID/KoZIzj0CAQYIKoZIzj0DAQcDQgAEwfs26T/cpjvNTXVJpK7Wv8oDOnNKL78AT3Y1QD356OIAggwPupX2LQjZU6CVzCjm+pkJIO4clu9Q2n540gKuzQ=="}}},"roles":{"root":{"keyids":["575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84"],"threshold":1},"snapshot":{"keyids":["d48327d85f0490827db7c931eedb58d293e1da5fc425ea0cde3e6c13b397ad69"],"threshold":1},"targets":{"keyids":["5717dcd81d9fb5b73aa15f2d887a6a0de543829ab9b2d411acce9219c2f8ba3a"],"threshold":1},"timestamp":{"keyids":["728c96ff5e9f48d4e66d5a0c3ecabfdd90bee2b5f9f80b950ed9c668db264a70"],"threshold":1}},"version":1},"signatures":[{"keyid":"575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84","method":"ecdsa","sig":"3WbX1VXN9E8LRmSG+E4SQlBUNqBNchhwAStWnRWLLyAOoFNBq5xmIgSO3UYYuKyJvL7kbMoONRbn5Vk2p2Wqrg=="}]}' > /root/.docker/trust/tuf/docker.io/library/debian/metadata/root.json
  root@disp2716:~# 
  root@disp2716:~# chown root:root /root/.docker/trust/tuf/docker.io/library/debian/metadata/root.json
  root@disp2716:~# chmod 0600 /root/.docker/trust/tuf/docker.io/library/debian/metadata/root.json
  root@disp2716:~# 
  
  ##
  # pull the docker image with DCT verification
  ##
  
  root@disp2716:~# export DOCKER_CONTENT_TRUST=1
  root@disp2716:~# docker pull debian:stable-slim
  could not validate the path to a trusted root: unable to retrieve valid leaf certificates
  root@disp2716:~# 
  root@disp2716:~# echo $?
  1
  root@disp2716:~# 
  
  ```
  
  Note that docker exits 1 with an error refusing to pull the `debian:stable-slim` docker image from Docker Hub because it cannot trust its signature
  
  > **Comments:**
  > **username_0**: This doesn't answer how to actually obtain the `root.json` file. For that, see https://devops.stackexchange.com/questions/13990/docker-how-to-download-verify-a-publishers-root-key-out-of-band-distinct-d  
  
  ---
  
  