How to Forward SSH Agent Sockets to Containers with the Apple Container Tool
Use the --ssh flag when running container commands to automatically mount the host's SSH authentication socket at /var/host-services/ssh-auth.sock inside the container.
The apple/container repository provides a first-class mechanism to forward SSH agent sockets from your host macOS system into Linux containers. This allows tools like ssh, git, and ssh-add running inside containers to authenticate using your host's SSH keys without ever copying private key material into the container filesystem.
How SSH Agent Forwarding Works Internally
The implementation spans multiple Swift source files and follows a clear pipeline from environment detection to guest mount. When you append --ssh to any container command, the runtime executes three distinct phases.
Step 1: Detecting the Host SSH_AUTH_SOCK
When a container starts, the command layer interrogates the host environment for the SSH_AUTH_SOCK variable. In Sources/ContainerCommands/Container/ContainerStart.swift (lines 91‑93) and Sources/ContainerCommands/Container/ContainerRun.swift (lines 131‑132), the code queries ProcessInfo.processInfo.environment["SSH_AUTH_SOCK"]. If the variable exists, its path is added to the dynamic environment dictionary that will be passed to the runtime service.
Step 2: Propagating the Socket to the Guest Runtime
The runtime service receives the dynamic environment and validates the request. In Sources/Services/RuntimeLinux/Server/RuntimeService.swift, the sshAuthSocketHostUrl method (lines 55‑94) checks that config.ssh is enabled and extracts the socket path from the incoming environment. If present, it creates a URL pointing to the host socket file.
Step 3: Mounting the Socket in the Container
When constructing the container configuration, the runtime fixes the guest path to /var/host-services/ssh-auth.sock. The service then adds a volume mount from the host socket URL to this guest path (lines 1028‑1035 in RuntimeService.swift). Simultaneously, it injects the SSH_AUTH_SOCK environment variable into the container’s environment (lines 1074‑1075), ensuring processes inside the container reference the correct socket location.
Using the --ssh Flag in Practice
The --ssh flag is defined in Sources/ContainerAPIService/Client/Flags.swift (lines 191‑220) and toggles the ContainerConfiguration.ssh Boolean to true. You can append this flag to any container sub-command that accepts a configuration, including run, exec, and build.
Start an interactive container with SSH forwarding:
container run -it --rm --ssh alpine:latest sh
Inside the container, verify the forwarding works:
# env | grep SSH_AUTH_SOCK
SSH_AUTH_SOCK=/var/host-services/ssh-auth.sock
# apk add --no-cache openssh-client git
# ssh-add -l
# git clone git@github.com:myorg/private-repo.git
For container builds that require SSH authentication (for example, cloning private Git repositories during the build), use:
container build --ssh myimage:latest .
Dynamic Updates and Security
Because the socket path is resolved at container start time rather than cached, logging out and back in on the host—or changing the agent socket—does not require manual updates. The runtime always re-reads SSH_AUTH_SOCK when --ssh is present, ensuring the mount points to the current socket. Your private keys remain on the host; only the authentication socket is forwarded, minimizing exposure of sensitive material.
Summary
- Detection: The tool checks
ProcessInfo.processInfo.environment["SSH_AUTH_SOCK"]inContainerStart.swiftandContainerRun.swiftwhen--sshis used. - Propagation:
RuntimeService.swift::sshAuthSocketHostUrlvalidates the configuration and extracts the socket path from the dynamic environment. - Mounting: The runtime mounts the host socket to
/var/host-services/ssh-auth.sockand sets theSSH_AUTH_SOCKenvironment variable inside the container. - Usage: Append
--sshto anycontainercommand (run, exec, build) to enable seamless SSH agent forwarding.
Frequently Asked Questions
Is the forwarded SSH agent socket updated dynamically if I log out and back in?
Yes. The socket path is resolved fresh each time a container starts with the --ssh flag. Because ContainerStart.swift and ContainerRun.swift read ProcessInfo.processInfo.environment["SSH_AUTH_SOCK"] at runtime, changes to the host agent (such as logging out and creating a new agent) are automatically reflected in new containers without manual intervention.
Can I use SSH forwarding with container builds?
Yes. The --ssh flag works with the container build command as well as run and exec. This allows build steps that clone private Git repositories or connect to remote servers via SSH to authenticate using your host's keys, as implemented in Flags.swift where the flag populates the shared ContainerConfiguration.
What happens if SSH_AUTH_SOCK is not set on the host?
If the SSH_AUTH_SOCK environment variable is absent on the host, the detection logic in ContainerStart.swift and ContainerRun.swift will not add a socket path to the dynamic environment. Consequently, RuntimeService.swift will not create a mount, and the container will start without SSH forwarding capabilities. No error is thrown; the container simply runs without access to the host's SSH agent.
Is the private key ever copied into the container?
No. The implementation only forwards the socket (ssh-auth.sock), not the private key files. The socket mount is created at /var/host-services/ssh-auth.sock, and the SSH_AUTH_SOCK environment variable points to this mount. Your private keys remain securely stored in the host's SSH agent, and the container only communicates with the agent through this forwarded socket.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →