Docker
Git
Repository
DevOps
VersionControl

Clone private git repo with dockerfile

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Cloning a private Git repository during a Docker build is possible, but it is easy to do insecurely. The main concern is not whether git clone works inside a Dockerfile; it is whether your credentials end up leaked into image layers, build logs, or the repository's own remote configuration.

Prefer Cloning Outside the Dockerfile When You Can

The safest pattern is often to clone the private repository before the build and then COPY the checked-out files into the image. That keeps Git credentials entirely outside the image build.

If your CI system can already access the repository, this is usually cleaner than teaching the Docker build how to authenticate.

When you truly must clone during build, avoid hard-coded tokens and avoid copying private SSH keys into normal image layers.

Use BuildKit SSH Forwarding

Modern Docker BuildKit supports SSH forwarding, which is the cleanest in-Docker approach for private Git access over SSH.

dockerfile
1# syntax=docker/dockerfile:1.4
2FROM alpine:3.20
3
4RUN apk add --no-cache git openssh-client
5RUN mkdir -p -m 0700 /root/.ssh \
6    && ssh-keyscan github.com >> /root/.ssh/known_hosts
7
8RUN --mount=type=ssh git clone [email protected]:your-org/private-repo.git /app

Build it like this:

bash
DOCKER_BUILDKIT=1 docker build --ssh default -t my-image .

This forwards the SSH agent into the build step without baking the private key into the resulting image layer.

Multi-Stage Builds Reduce Risk Further

Even with secure secret handling, keep the clone step in an intermediate stage and copy only the final source or artifacts into the release image.

dockerfile
1# syntax=docker/dockerfile:1.4
2FROM alpine:3.20 AS source
3RUN apk add --no-cache git openssh-client
4RUN mkdir -p -m 0700 /root/.ssh \
5    && ssh-keyscan github.com >> /root/.ssh/known_hosts
6RUN --mount=type=ssh git clone [email protected]:your-org/private-repo.git /src
7
8FROM alpine:3.20
9COPY --from=source /src /app
10WORKDIR /app

This reduces the chance that build-time tooling or temporary files survive into the final image.

It also keeps the final runtime image smaller and easier to audit, because Git, SSH tooling, and build-time metadata do not need to ship with the production container.

Avoid Token-in-URL Shortcuts

A common shortcut is:

dockerfile
RUN git clone https://[email protected]/your-org/private-repo.git

That is risky for several reasons:

  • the token may appear in image history
  • the token may appear in build logs
  • the cloned repository may keep the token in its configured remote URL

If you must use HTTPS authentication, use build secrets rather than literal tokens in the Dockerfile, and scrub the remote configuration afterward. Even then, SSH forwarding is usually the better option.

Another operational detail matters here: if the repository contains private submodules, make sure your build authentication method also covers those nested clone steps. A build that authenticates only the top-level repository can still fail deeper in the checkout.

Common Pitfalls

  • Copying a private SSH key into the image and assuming rm removes the risk from earlier layers.
  • Using a personal access token directly in the clone URL.
  • Forgetting known_hosts, which leads to interactive host verification failures during build.
  • Solving a CI checkout problem inside the Dockerfile when the repository could have been cloned before the build.
  • Authenticating the main repository successfully but forgetting that private submodules need the same secret-handling strategy.

Summary

  • Cloning a private repo in a Dockerfile is possible, but secret handling is the real problem.
  • The safest pattern is usually to clone outside the Docker build and COPY the files in.
  • If build-time cloning is required, prefer BuildKit SSH forwarding.
  • Use multi-stage builds so build-time Git steps do not pollute the final image.
  • Avoid token-in-URL patterns because they can leak secrets into layers, logs, and repo config.

Course illustration
Course illustration

All Rights Reserved.