如何在 Docker 容器内使用 SSH 密钥?
容器内用 SSH 密钥的安全做法:挂载密钥目录为只读卷(-v ~/.ssh:/root/.ssh:ro)或构建期用 BuildKit 的 --mount=type=ssh;切忌 COPY 私钥进镜像。本文给出各方案与安全对比。
核心原则:私钥绝不 COPY 进镜像(镜像层会永久留存,推到仓库就泄露)。运行时用法:把宿主机 .ssh 目录只读挂载进容器 -v ~/.ssh:/root/.ssh:ro;构建期用法(如构建时拉私有 git 仓库):用 BuildKit 的 SSH 挂载 RUN --mount=type=ssh,密钥不落镜像层。
方案一:运行时挂载(最常见)
docker run -it -v ~/.ssh:/root/.ssh:ro my-image
:ro只读,容器改不了也泄露面小- 挂载的是目录,容器内 ssh 会找到 id_rsa/id_ed25519
- 权限要求:ssh 要求私钥 600,挂载保持宿主权限一般没问题
容器内验证:
ssh -T git@github.com
方案二:构建期 SSH 挂载(拉私有依赖)
Dockerfile:
# syntax=docker/dockerfile:1
FROM python:3.12-slim
RUN apt-get update && apt-get install -y git openssh-client
RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
RUN --mount=type=ssh pip install git+ssh://git@github.com/org/private-repo.git
构建命令:
eval $(ssh-agent) && ssh-add
DOCKER_BUILDKIT=1 docker build --ssh default .
密钥通过 ssh-agent 转发进构建过程,不会留在任何镜像层——这是与 COPY 私钥的本质区别。
方案三:ssh-agent 套接字转发(docker run)
docker run -it \
-v $SSH_AUTH_SOCK:/ssh-agent \
-e SSH_AUTH_SOCK=/ssh-agent \
my-image
容器内 ssh 直接使用宿主机的 agent,私钥文件根本不进容器。
反面清单
| 做法 | 问题 |
|---|---|
COPY id_rsa /root/.ssh/ |
私钥永久留在镜像层,推仓库=泄露 |
ENV SSH_KEY=... |
docker inspect/history 可见 |
| 密钥放共享卷长期挂着 | 权限管理困难,用完即挂更好 |
观测云对照
密钥使用行为纳入审计视野。 容器对外 SSH 连接的日志(known_hosts 变化、连接记录)属安全敏感操作,统一采集后可追溯。
常见问题(FAQ)
Q:挂载后 ssh 报 "permissions are too open"?
A:Windows 挂载目录权限模拟问题;在容器内 chmod 600 /root/.ssh/id_* 或改用 agent 转发方案。
Q:容器内访问 Git 还要配什么?
A:git config --global user.email/name,以及把主机公钥加过 Git 平台的 deploy key。
Q:K8s 里怎么用?
A:私钥放 Secret,volume 挂载(defaultMode 0600);构建期用 Kaniko/BuildKit 的 ssh 机制。