Need to access private Git repositories during build? Here’s how to do it securely with SSH.

The setup

Enable SSH forwarding in your compose.yml:

services:
  app:
    build:
      context: .
      ssh:
        - default  # Uses your default SSH agent

Or use specific keys for different services:

services:
  app:
    build:
      context: .
      ssh:
        - github=/home/user/.ssh/github_key  # Custom key for GitHub
        - gitlab=/home/user/.ssh/gitlab_key  # Different key for GitLab

The Dockerfile

Use BuildKit’s SSH mount to clone private repos:

# syntax=docker/dockerfile:1
FROM node:20

# Using default SSH key
RUN --mount=type=ssh \
    git clone git@github.com:mycompany/private-lib.git /tmp/lib && \
    cd /tmp/lib && npm install && npm run build && \
    cp -r dist /app/vendor/

# Using a specific key ID
RUN --mount=type=ssh,id=github \
    git clone git@github.com:mycompany/private-package.git /tmp/package

# Different key for GitLab
RUN --mount=type=ssh,id=gitlab \
    git clone git@gitlab.com:mycompany/internal-tool.git /tmp/tool

Building with SSH

Make sure your SSH agent is running:

# Start SSH agent if needed
eval $(ssh-agent)
ssh-add ~/.ssh/id_rsa

# Build with SSH forwarding
docker compose build --ssh default

CI/CD setup

For GitHub Actions or similar:

services:
  app:
    build:
      context: .
      ssh:
        - default=${{ secrets.SSH_KEY }}

Security notes

  • SSH keys are never stored in the image
  • They’re only available during the RUN command with --mount=type=ssh
  • No secrets leak into your final container
  • BuildKit handles the SSH agent forwarding securely

Common issues

“Could not read from remote repository”

Make sure the host is in known_hosts:

RUN --mount=type=ssh \
    mkdir -p ~/.ssh && \
    ssh-keyscan github.com >> ~/.ssh/known_hosts && \
    git clone git@github.com:mycompany/repo.git

“SSH agent not available”

On macOS, the SSH agent should work automatically. On Linux:

docker compose build --ssh default=$SSH_AUTH_SOCK

Why this matters

No more:

  • Copying SSH keys into images (security risk!)
  • Building everything publicly
  • Complex workarounds with access tokens

Just secure, straightforward access to private dependencies during build.