Mounting SSH Keys in Docker Containers: Why and How to Use Volume Bind‑Mounts with the -i Flag
When you run security or compliance scans inside a Docker container, you often need to connect to remote hosts over SSH. A common pattern is to combine the -i option (to point to a private key) with one or more -v volume mounts that expose your local ~/.ssh directory and the current working directory to the container. This article explains why both are required, breaks down each part of the command, and provides practical guidance for using SSH keys safely and efficiently in Docker‑based DevSecOps workflows.
Table of Contents
- Understanding the
docker runcommand - Why mount
~/.sshas a volume? - The role of the
-iflag - Why two
-vflags? - Step‑by‑step example
- Best practices & security tips
- Common questions
Understanding the docker run command
A typical invocation for running the InSpec Docker image against a remote server looks like this:
docker run --rm \
-v ~/.ssh:/root/.ssh \
-v $(pwd):/share \
hysnsec/inspec exec https://github.com/dev-sec/linux-baseline.git \
-t ssh://root@$DEPLOYMENT_SERVER \
-i ~/.ssh/id_rsa \
--chef-license accept
| Segment | Purpose |
|---|---|
--rm |
Remove the container automatically when it exits. |
-v ~/.ssh:/root/.ssh |
Bind‑mount the host’s SSH directory into the container. |
-v $(pwd):/share |
Share the current host directory (e.g., test files, profiles) with the container. |
hysnsec/inspec |
Docker image that contains the InSpec scanner. |
exec … |
InSpec command to run a compliance profile from GitHub. |
-t ssh://root@$DEPLOYMENT_SERVER |
Target remote host via SSH. |
-i ~/.ssh/id_rsa |
Path to the private key inside the container. |
--chef-license accept |
Auto‑accept the Chef license required by InSpec. |
Why mount ~/.ssh as a volume?
1. Provides the full SSH configuration
The -i flag only points to a single private key file. Real‑world SSH setups often rely on additional files:
~/.ssh/config(host aliases, proxy commands, preferred algorithms)- Known hosts file
~/.ssh/known_hosts(pre‑trusted fingerprints) - Additional keys (
id_ecdsa,id_ed25519, etc.)
Mounting the entire ~/.ssh directory makes all of these files available to the container, ensuring the SSH client inside Docker behaves exactly like the one on your host.
2. Keeps the path consistent
Inside the container the default user is root, whose home directory is /root. By mapping ~/.ssh to /root/.ssh, the container’s SSH client automatically finds the keys without needing to adjust environment variables or copy files manually.
3. Avoids copy‑and‑paste errors
If you only passed -i ~/.ssh/id_rsa, you would still need to copy the key into the container’s filesystem or set SSH_AUTH_SOCK. A bind‑mount is a single, declarative step that guarantees the key is present where the SSH client expects it.
The role of the -i flag
- Scope: Tells InSpec (or any underlying SSH client) which private key to use for authentication inside the container.
- Syntax:
-i /path/to/key– the path is evaluated relative to the container’s filesystem. - Why it still matters: Even though the whole
.sshdirectory is mounted, InSpec does not automatically select a key. Explicitly specifying-iremoves ambiguity, especially when multiple keys exist.
Bottom line:
-v ~/.ssh:/root/.sshmakes the key available;-i ~/.ssh/id_rsatells the tool which key to use.
Why two -v flags?
Docker allows multiple volume bind‑mounts in a single docker run. Each -v maps a distinct host path to a distinct container path:
| Flag | Host path | Container path | Typical use case |
|---|---|---|---|
-v ~/.ssh:/root/.ssh |
Your local SSH configuration (~/.ssh) |
/root/.ssh (root’s home) |
Provide SSH keys & config |
-v $(pwd):/share |
The directory you are currently in ($(pwd)) |
/share |
Share InSpec profiles, scripts, or output files with the container |
Using both mounts lets you interact with remote hosts (via SSH) and work with local test assets without copying them into the image.
Step‑by‑step example
-
Prepare your environment
export DEPLOYMENT_SERVER=10.0.1.23 cd ~/my-inspec-profiles # Directory containing custom controls -
Run the scan
docker run --rm \ -v ~/.ssh:/root/.ssh \ -v $(pwd):/share \ hysnsec/inspec exec https://github.com/dev-sec/linux-baseline.git \ -t ssh://root@$DEPLOYMENT_SERVER \ -i ~/.ssh/id_rsa \ --chef-license accept -
Inspect results
The scan writes its report to standard output. If you want a file on the host, add a volume for areportsfolder:-v $(pwd)/reports:/reports \ ... \ --reporter json:/reports/report.json
Best practices & security tips
- Least‑privilege keys: Use a dedicated SSH key with limited permissions (e.g., read‑only sudo) for scanning.
- Read‑only mount: Prevent accidental modification of host keys by mounting read‑only:
-v ~/.ssh:/root/.ssh:ro - Avoid embedding secrets in images: Never
COPY ~/.sshinto a Dockerfile; always use bind‑mounts at runtime. - Clean up: The
--rmflag ensures the container disappears after the run, but the host’s key files remain untouched. - Use SSH agent forwarding (advanced): If you prefer not to expose private keys, start the container with
-v $SSH_AUTH_SOCK:/ssh-agent -e SSH_AUTH_SOCK=/ssh-agentand omit the-iflag.
Common Questions
| Question | Answer |
|---|---|
Do I still need -i if I mount the whole .ssh directory? |
Yes. The mount makes the key visible; -i tells InSpec which key to present to the remote host. |
| Can I mount only a single key file instead of the whole directory? | Technically, you could -v ~/.ssh/id_rsa:/root/.ssh/id_rsa. However, you would lose config and known_hosts, which may cause host‑key verification failures. |
| What if my host uses a non‑standard SSH config location? | Adjust the mount accordingly, e.g., -v /custom/ssh:/root/.ssh. |
| Is it safe to share the entire current directory with the container? | Generally yes, but avoid mounting sensitive files (password files, tokens) unless required. Use a dedicated sub‑directory if you need tighter control. |
Takeaway
Mounting ~/.ssh as a Docker volume supplies the container with all the SSH artefacts it needs, while the -i flag explicitly selects the private key for authentication. The second -v flag shares your local work directory, enabling seamless interaction between host and container. By following the best‑practice checklist above, you can run DevSecOps scans securely, reproducibly, and without exposing secret material inside Docker images.