@@ -124,6 +124,11 @@ repository to mirror.
124124
125125## Mirror from Docker Hub to another registry
126126
127+ > [ !IMPORTANT]
128+ >
129+ > To continue receiving image updates and preserve access to Docker Hardened
130+ > Images, ensure that any copies pushed to other registries remain private.
131+
127132After you've mirrored a Docker Hardened Image repository to your organization's
128133namespace on Docker Hub, you can optionally mirror it to another container
129134registry, such as Amazon ECR, Google Artifact Registry, GitHub Container
@@ -134,40 +139,145 @@ You can use any standard workflow to mirror the image, such as the
134139API] ( /reference/api/registry/latest/ ) , third-party registry tools, or CI/CD
135140automation.
136141
137- However, to preserve the full security context, including signatures and
138- attestations, you must also copy its associated OCI artifacts. Docker
139- Hardened Images store the image layers on Docker Hub (` docker.io ` ) and the
140- signed attestations in a separate registry (` registry.scout.docker.com ` ).
142+ However, to preserve the full security context, including attestations, you must
143+ also mirror its associated OCI artifacts. Docker Hardened Images store the image
144+ layers on Docker Hub (` docker.io ` ) and the signed attestations in a separate
145+ registry (` registry.scout.docker.com ` ).
141146
142147To copy both, you can use [ regctl] ( https://regclient.org/cli/regctl/ ) , an
143148OCI-aware CLI that supports mirroring images along with attached artifacts such
144- as SBOMs, vulnerability reports, and SLSA provenance.
149+ as SBOMs, vulnerability reports, and SLSA provenance. For ongoing synchronization,
150+ you can use [ regsync] ( https://regclient.org/cli/regsync/ ) .
151+
152+ ### Example mirroring with regctl
153+
154+ The following example shows how to mirror a specific tag of a Docker Hardened
155+ Image from Docker Hub to another registry, along with its associated
156+ attestations using ` regctl ` . You must [ install
157+ ` regctl ` ] ( https://github.com/regclient/regclient ) first.
158+
159+ 1 . Set environment variables for your specific environment. Replace the
160+ placeholders with your actual values.
161+
162+ ``` console
163+ $ export DOCKER_USERNAME="YOUR_DOCKER_USERNAME"
164+ $ export DOCKER_PAT="YOUR_DOCKER_PAT"
165+ $ export DEST_REG="registry.example.com"
166+ $ export DEST_REPO="mirror/dhi-python"
167+ $ export SRC_REPO="docker.io/<your-org>/dhi-python"
168+ $ export SRC_TAG="3.13-alpine3.21"
169+ ```
170+
171+ 2 . Sign in via regctl to Docker Hub, the Scout registry that contains
172+ the attestations, and your destination registry.
173+
174+ ``` console
175+ $ regctl registry login -u "$DOCKER_USERNAME" --pass-stdin docker.io
176+ $ regctl registry login -u "$DOCKER_USERNAME" --pass-stdin registry.scout.docker.com
177+ $ regctl registry login "$DEST_REG
178+ ```
179+
180+ 3 . Mirror the image by digest from Docker Hub to your destination registry.
181+
182+ First, get a digest for a specific tag and platform. For example, ` linux/amd64 ` .
183+
184+ ``` console
185+ DIGEST="$(regctl manifest head "${SRC_REPO}:${SRC_TAG}" --platform linux/amd64)"
186+ ```
187+
188+ Then, copy the image by digest to ensure you get the exact same image.
189+
190+ ``` console
191+ regctl image copy \
192+ "${SRC_REPO}@${DIGEST}" \
193+ "${DEST_REG}/${DEST_REPO}@${DIGEST}"
194+ ```
195+
196+ 4 . Mirror the attestations from the Scout registry to your target registry using
197+ ` --referrers ` and referrer endpoints:
198+
199+ ``` console
200+ $ regctl image copy \
201+ --referrers \
202+ --referrers-src "registry.scout.docker.com/<your-org>/dhi-python" \
203+ --referrers-tgt "${DEST_REG}/${DEST_REPO}" \
204+ "registry.scout.docker.com/<your-org>/dhi-python@${DIGEST}" \
205+ "${DEST_REG}/${DEST_REPO}@${DIGEST}"
206+ ```
207+
208+ 5 . Verify that artifacts were preserved.
209+
210+ List attached artifacts (SBOM, provenance, VEX, vuln reports).
211+
212+ ``` console
213+ $ regctl artifact list "${DEST_REG}/${DEST_REPO}@${DIGEST}"
214+ ```
215+
216+ If you use Docker Scout:
217+
218+ ``` console
219+ $ docker scout attest list "registry://${DEST_REG}/${DEST_REPO}@${DIGEST}"
220+ ```
221+
222+ ### Example ongoing mirroring with regsync
223+
224+ regsync automates pulling from your organizations mirrored DHI repositories on
225+ Docker Hub and pushing to your external registry including attestations. It
226+ reads a YAML configuration file and can filter tags.
227+
228+ The following example uses a ` regsync.yaml ` file that syncs Node 24.* and Python
229+ 3.12.* Debian 13 variants, excluding Alpine and Debian 12.
230+
231+ ``` yaml{title="regsync.yaml"}
232+ version: 1
233+ # Optional: inline creds if not relying on prior CLI logins
234+ # creds:
235+ # - registry: docker.io
236+ # user: <your-docker-username>
237+ # pass: "{{file \"/run/secrets/docker_token\"}}"
238+ # - registry: registry.scout.docker.com
239+ # user: <your-docker-username>
240+ # pass: "{{file \"/run/secrets/docker_token\"}}"
241+ # - registry: registry.example.com
242+ # user: <service-user>
243+ # pass: "{{file \"/run/secrets/dest_token\"}}"
244+
245+ sync:
246+ - source: docker.io/<your-org>/dhi-node
247+ target: registry.example.com/mirror/dhi-node
248+ type: repository
249+ fastCopy: true
250+ referrers: true
251+ referrerSource: registry.scout.docker.com/<your-org>/dhi-node
252+ referrerTarget: registry.example.com/mirror/dhi-node
253+ tags:
254+ allow: [ "24.*" ]
255+ deny: [ ".*alpine.*", ".*debian12.*" ]
256+
257+ - source: docker.io/<your-org>/dhi-python
258+ target: registry.example.com/mirror/dhi-python
259+ type: repository
260+ fastCopy: true
261+ referrers: true
262+ referrerSource: registry.scout.docker.com/<your-org>/dhi-python
263+ referrerTarget: registry.example.com/mirror/dhi-python
264+ tags:
265+ allow: [ "3.12.*" ]
266+ deny: [ ".*alpine.*", ".*debian12.*" ]
267+ ```
145268
146- The following example uses ` regctl ` to mirror a DHI and then its attestations to a
147- private registry:
269+ To do a dry run with the configuration file, you can run the following command.
270+ You must [ install ` regsync ` ] ( https://github.com/regclient/regclient ) first.
148271
149272``` console
150- $ regctl \
151- --host "reg=docker.io,user=$DOCKER_USERNAME,pass=$DOCKER_PASSWORD_OR_PAT" \
152- --host "reg=registry.example.com" \
153- image copy \
154- docker.io/docs/dhi-python@sha256:25c9... \
155- my-registry.example.com/mirror/dhi-python@sha256:25c9...
156-
157- $ regctl \
158- --host "reg=registry.scout.docker.com,user=$DOCKER_USERNAME,pass=$DOCKER_PASSWORD_OR_PAT" \
159- --host "reg=registry.example.com" \
160- image copy --referrers \
161- registry.scout.docker.com/docs/dhi-python@sha256:25c9... \
162- my-registry.example.com/mirror/dhi-python@sha256:25c9...
273+ $ regsync check -c regsync.yaml
163274```
164275
165- This mirrors both the image and its associated attestations to a private OCI-compatible registry.
276+ To run the sync with the configuration file:
166277
167- > [ !IMPORTANT]
168- >
169- > To continue receiving image updates and preserve access to Docker Hardened
170- > Images, ensure that any copies pushed to other registries remain private.
278+ ``` console
279+ $ regsync once -c regsync.yaml
280+ ```
171281
172282## What's next
173283
0 commit comments