Use a BuildKit SSH mount. It forwards your SSH agent socket into one build step, so the build can clone a private repository without the private key ever being copied into an image layer. Avoid copying key files or passing tokens through build arguments.
What Docker documents
Docker's secrets guide says build arguments and environment variables persist in the final image, so secrets passed that way can leak, and recommends secret mounts or SSH mounts instead. SSH mounts expose an SSH agent socket or key to the build, which suits cloning private repositories. You pass your socket when you run the build, with the ssh option set to default.
The Dockerfile reference adds details. The SSH mount type forwards the agent socket, the default ID is default, and the default target is a socket path under the BuildKit run directory. Setting required to true fails the build if no key is available, which is better than a silent fallback.
Steps
- Start an SSH agent on the build machine and add the key that can read the repository.
- In the Dockerfile, use a RUN instruction with an SSH mount of type ssh for the clone step.
- Add the host's key to known hosts in that step, rather than disabling host checking.
- Run the build with the ssh option forwarding your default agent.
- Check the result with history and an image scan to confirm nothing sensitive stayed behind.
# RUN with an ssh mount, then clone
RUN git clone git@example.com:org/private-lib.git /src/private-lib
The comment shows the shape. The real instruction carries the mount type as an option on RUN, as in the reference.
What not to do
| Practice | Problem |
|---|---|
| Copy a private key into the image | Key stays in a layer |
| Pass a token as a build argument | Visible in image history |
| Delete the key in a later step | Earlier layer still holds it |
| Turn off host key checking | Opens the build to impersonation |
Deleting a file later does not remove it from earlier layers. See a deleted secret in a later layer is still there.
Use a narrow credential
Even with a safe mount, the build can use whatever the agent holds. Use a deploy key that is read only and limited to the repositories the build needs, and rotate it. In CI, prefer short lived credentials from your platform over a long lived personal key.
Better still, avoid the clone
Fetching private code at image build time makes the build depend on a live network and a moving branch. Where you can, vendor the dependency, publish it to a private package registry, or pin the clone to a commit hash. A pinned commit makes the build repeatable.
Quick check
Is a multi-stage build enough to hide a key?
It helps only if the key never lands in the final stage, but a mount is cleaner because the key is never written to a layer at all.
How do I confirm no secret leaked?
Run docker history with the no truncate option, inspect environment settings, and scan the image for secrets.
Safeguard
Safeguard does SBOM and dependency scanning, and its policies and gates can run in CI so a bad image does not reach production. You can try a free scan before deciding anything.
Sources
Last reviewed: 19 October 2026.