如何在 Docker 容器内使用 SSH 密钥?

容器内用 SSH 密钥:仅挂载所需密钥与已核验 known_hosts,只读不防止密钥泄露;构建期可用 BuildKit 的 --mount=type=ssh;切忌 COPY 私钥进镜像。本文给出各方案与安全对比。

最佳实践
如何在 Docker 容器内使用 SSH 密钥?封面

核心原则:私钥绝不 COPY 进镜像(镜像层会永久留存,推到仓库就泄露)。运行时用法:仅把所需密钥与已核验known_hosts分别只读挂载;构建期用法(如构建时拉私有 git 仓库):用 BuildKit 的 SSH 挂载 RUN --mount=type=ssh,密钥不落镜像层。

方案一:运行时挂载(最常见)

docker run -it --mount "type=bind,src=$HOME/.ssh/id_ed25519_work,dst=/root/.ssh/id_ed25519,readonly" --mount "type=bind,src=$HOME/.ssh/known_hosts,dst=/root/.ssh/known_hosts,readonly" my-image
  • :ro 只限制写入,容器仍能读取并窃取私钥,不能把只读视为保密保证
  • 仅挂载任务所需文件;路径属于Docker daemon主机,远端context/Desktop路径行为需单独核对
  • 权限要求: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
COPY verified_known_hosts /root/.ssh/known_hosts
# verified_known_hosts须通过可信渠道核对主机密钥,不能盲信ssh-keyscan结果
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,私钥文件不直接进入容器,但容器可利用agent提供的认证权限,仍只对可信任务开放并限制密钥。

反面清单

做法 问题
COPY id_rsa /root/.ssh/ 私钥永久留在镜像层,推仓库=泄露
ENV SSH_KEY=... docker inspect/history 可见
密钥放共享卷长期挂着 权限管理困难,用完即挂更好

常见问题(FAQ)

Q:挂载后 ssh 报 "permissions are too open"?
A:Windows 挂载目录权限模拟问题;只读挂载不能在容器内chmod;应在宿主侧修复权限/ACL并核对UID映射,或按平台文档使用agent转发。

Q:容器内访问 Git 还要配什么?
A:配置可信known_hosts与有权限的SSH公钥/Deploy Key;user.name/email只决定提交元数据,不决定SSH登录身份。

Q:K8s 里怎么用?
A:私钥放 Secret,volume 挂载(defaultMode 0600);构建期可用BuildKit SSH挂载,不应假定Kaniko提供等价机制。Secret的编码不是加密,还需RBAC和密钥生命周期管理。

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台