Using the correct identity when SSH forwarding in Docker

16 Jan 2024 14:16 docker

Back in October, I wrote a post explaining how to do SSH forwarding with docker build. In November, I wrote about how to use multiple SSH identities with git. Unfortunately, these don’t always mix: using SSH in the docker build uses the first SSH identity held by ssh-agent, which might not be the one you wanted. Here’s how I got around this problem.

The answer is to tell SSH, running in docker build, which identity we want to use.

The first thing we need to do is make the private key available to docker build. We can use a secret for this:

docker build \
    --ssh default \
    --secret id=ssh_id,src=$(HOME)/.ssh/id_other \
    --build-arg GIT_SSH_COMMAND="ssh -i /run/secrets/ssh_id -o IdentitiesOnly=yes" \
    .

Then we need to edit the Dockerfile to tell SSH that we want to use that identity:

# Set the GIT_SSH_COMMAND environment variable.
ARG GIT_SSH_COMMAND

# mount the ssh-agent *and* the private key secret, then run 'npm install' (or whatever)
RUN --mount=type=ssh \
    --mount=type=secret,id=ssh_id \
    npm install

To make this transparent for people (or CI pipelines) who aren’t using multiple identities, you can omit the --secret and --build-arg options from the docker build command:

docker build \
    --ssh default \
    .

In my Makefile, that looks like this:

# If you're using more than one SSH identity, set DOCKER_SSH_ID_SECRET to point to the ~/.ssh/id_whatever file.
ifdef DOCKER_SSH_ID_SECRET
_DOCKER_BUILD_SECRET_ARG = --secret id=ssh_id,src=$(DOCKER_SSH_ID_SECRET)
_DOCKER_BUILD_GIT_CONFIG_ARG = --build-arg GIT_SSH_COMMAND="ssh -i /run/secrets/ssh_id -o IdentitiesOnly=yes"
endif

docker-image:
	docker build \
		$(_DOCKER_BUILD_SECRET_ARG) \
		$(_DOCKER_BUILD_GIT_CONFIG_ARG) \
		--ssh default \
		.