在为 Docker 设置 SSH 时如何排查“无法加载主机密钥”错误

DockerBeginner
立即练习

简介

Docker 是用于将应用程序容器化的强大工具,但设置 SSH 有时可能是一项挑战。在本教程中,我们将探讨如何在为 Docker 容器配置 SSH 时排查“无法加载主机密钥”错误,以确保开发过程顺利且安全。

理解 SSH 和主机密钥

安全外壳协议(Secure Shell,SSH)是一种广泛使用的协议,用于在不安全的网络上进行安全通信和远程访问计算机。它提供加密和认证机制,以确保客户端和服务器之间交换的数据的机密性和完整性。

SSH 的一个关键方面是主机密钥的使用,主机密钥是在 SSH 连接建立过程中用于标识服务器的加密密钥。这些主机密钥通过验证服务器的身份来帮助防止中间人攻击。

当 SSH 客户端首次连接到服务器时,它会将服务器的主机密钥存储在 known_hosts 文件中。此文件用于在后续连接中验证服务器的身份。如果主机密钥发生更改,SSH 客户端将引发“无法加载主机密钥”错误,这表明存在潜在的安全风险。

sequenceDiagram participant Client participant Server Client->>Server: SSH 连接请求 Server->>Client: 服务器的主机密钥 Client->>Client: 根据 known_hosts 文件验证主机密钥 alt 主机密钥匹配 Client->>Server: 建立安全连接 else 主机密钥不匹配 Client->>Client: “无法加载主机密钥” 错误 end

known_hosts 文件通常位于用户的主目录中(例如,Linux/macOS 上的 ~/.ssh/known_hosts,Windows 上的 %USERPROFILE%\.ssh\known_hosts)。它存储了用户过去连接过的所有服务器的主机密钥。

表 1:常见的 SSH 主机密钥算法

算法 描述
RSA 里弗斯特 - 沙米尔 - 阿德尔曼(Rivest-Shamir-Adleman,RSA)是一种广泛使用的公钥加密算法。RSA 主机密钥的长度通常为 2048 位或 4096 位。
ECDSA 椭圆曲线数字签名算法(Elliptic Curve Digital Signature Algorithm,ECDSA)是 RSA 的一种更高效的替代算法,它使用椭圆曲线密码学。ECDSA 主机密钥的长度通常为 256 位、384 位或 521 位。
ED25519 Ed25519 是一种基于椭圆曲线密码学的现代高性能公钥签名系统。Ed25519 主机密钥的长度为 256 位。

理解 SSH 主机密钥的作用以及“无法加载主机密钥”错误对于安全地设置和排查依赖 SSH 连接的 Docker 环境至关重要。

诊断“无法加载主机密钥”错误

确定原因

“无法加载主机密钥”错误通常在 SSH 客户端无法根据 known_hosts 文件验证服务器的主机密钥时出现。这可能由于以下几个原因发生:

  1. 首次连接:首次连接到新服务器时,SSH 客户端在 known_hosts 文件中没有存储服务器的主机密钥,从而导致错误。
  2. 主机密钥更改:如果自上次连接以来服务器的主机密钥发生了更改,SSH 客户端将引发“无法加载主机密钥”错误,因为它无法根据存储的密钥验证新密钥。
  3. known_hosts 文件损坏:如果 known_hosts 文件已损坏或被手动修改,SSH 客户端可能无法正确验证服务器的主机密钥。

故障排除步骤

  1. 验证 known_hosts 文件:检查 known_hosts 文件的内容,查看服务器的主机密钥是否存在且正确。你可以使用 ssh-keygen 命令查看文件内容:

    ssh-keygen -F <服务器主机名>

    此命令将在 known_hosts 文件中搜索指定的服务器主机名,并显示相关联的主机密钥。

  2. 清除 known_hosts 文件:如果服务器的主机密钥已更改,你可以从 known_hosts 文件中删除旧条目。这将允许 SSH 客户端在下一次连接时接受新的主机密钥:

    ssh-keygen -R <服务器主机名>

    此命令将从 known_hosts 文件中删除指定服务器主机名的所有条目。

  3. 手动添加主机密钥:如果 known_hosts 文件中不存在服务器的主机密钥,你可以手动添加它。首先,获取服务器的主机密钥,然后将其追加到 known_hosts 文件:

    ssh-keyscan -H <服务器主机名> >> ~/.ssh/known_hosts

    此命令将检索服务器的主机密钥并将其添加到 known_hosts 文件。

  4. 禁用主机密钥验证:作为最后的手段,你可以禁用主机密钥验证,但出于安全考虑不建议这样做。你可以通过在 SSH 配置文件(例如 ~/.ssh/config)中将 StrictHostKeyChecking 选项设置为 no 来实现:

    Host <服务器主机名>
        StrictHostKeyChecking no

通过遵循这些故障排除步骤,你应该能够解决“无法加载主机密钥”错误,并建立到你的 Docker 环境的安全 SSH 连接。

为 Docker 容器配置 SSH

在 Docker 容器中启用 SSH

要启用对 Docker 容器的 SSH 访问,你需要确保在容器内安装并配置了 SSH 服务器。以下是使用 Dockerfile 实现此目的的示例:

FROM ubuntu:22.04

## 安装 SSH 服务器
RUN apt-get update && apt-get install -y openssh-server
RUN mkdir /var/run/sshd

## 配置 SSH
RUN sed -i's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN echo 'root:password' | chpasswd

## 暴露 SSH 端口
EXPOSE 22

## 启动 SSH 服务器
CMD ["/usr/sbin/sshd", "-D"]

此 Dockerfile 安装 OpenSSH 服务器,为 SSH 守护进程创建必要的目录,配置 SSH 服务器以允许 root 登录,设置 root 密码,并暴露 SSH 端口(22)。最后,在容器运行时启动 SSH 服务器。

通过 SSH 连接到 Docker 容器

一旦你有了启用了 SSH 的 Docker 容器,就可以使用 ssh 命令连接到它:

ssh root@<容器 IP 地址>

<容器 IP 地址> 替换为你的 Docker 容器的实际 IP 地址或主机名。

如果你遇到“无法加载主机密钥”错误,请按照上一节中的故障排除步骤解决该问题。

使用 Docker Compose 自动化 SSH 配置

如果你使用 Docker Compose 来管理你的应用程序,可以通过在 Compose 文件中添加必要的步骤来自动化 SSH 配置过程。以下是一个示例:

version: "3"
services:
  my-app:
    build:
      context:.
      dockerfile: Dockerfile
    ports:
      - "22:22"
    environment:
      - SSH_ROOT_PASSWORD=password

在此示例中,Dockerfile 用于构建配置了 SSH 服务器的容器镜像,ports 部分将容器的 SSH 端口(22)映射到主机的端口 22。environment 部分设置 SSH 服务器的 root 密码。

通过使用此方法,你可以轻松启动启用了 SSH 访问的 Docker 容器,从而更轻松地排查和管理基于 Docker 的应用程序。

总结

在本教程结束时,你将对如何为 Docker 容器配置 SSH、诊断和解决“无法加载主机密钥”错误以及为基于 Docker 的应用程序维护安全的 SSH 连接有深入的了解。这些知识将使你能够简化 Docker 开发工作流程,并增强容器化环境的整体安全性。