如何在 cloud-init 中设置 ssh 密钥?

如何在 cloud-init 中设置 ssh 密钥?

我正在使用 cloud-init 设置装有 Ubuntu Server 22.04.1 的 Raspberry Pi。我想设置设备的 SSH 密钥,这样我就可以进行连接而不会受到中间人攻击。

我当前的用户数据是:

#cloud-config
users:
- name: 'foo'
  groups: users,adm,dialout,audio,netdev,video,plugdev,cdrom,games,input,gpio,spi,i2c,render,sudo
  shell: /bin/bash
  lock_passwd: true
  ssh_authorized_keys:
    - 'ssh-ed25519 ...'
  ssh_keys:
    ed25519_private: |
      -----BEGIN OPENSSH PRIVATE KEY-----
      ...
      -----END OPENSSH PRIVATE KEY-----
    ed25519_public: ...

当我通过 ssh 进入设备时,它的 ECDSA 指纹每次都会改变。(即,如果我重新映像驱动器并让 cloud-init 再次运行,然后通过 SSH 进入,指纹会有所不同。它永远不会与用户数据中的密钥的指纹匹配ed25519_private/public。)所以我认为它在启动时会生成新密钥,但我不知道如何阻止这种情况。

如何设置设备的 SSH 密钥?

更新(来自@muru):

cloud-init 的主机密钥部分文档包括一些相关条目:

  • 理论上,如果您指定ssh_keys,则不会生成新密钥。我不确定我做错了什么,导致情况并非如此。
  • 我尝试过将其放在用户对象ssh_deletekeys: falsessh_keys,并放在全局级别。每次使用 SSH 仍会产生新的密钥指纹。
  • 我尝试过将其放在用户对象ssh_genkeytypes: []ssh_keys,并将其放在全局级别。有时(我没有记录是哪一次)这会导致我根本无法 ssh 连接,大概是因为没有密钥。在任何情况下我都没有看到正确的密钥指纹(源自 ed25519_private)。
  • 有些条目允许我将公钥导入到我的授权密钥中、发布密钥、抑制密钥生成器输出或启用/禁用 root 登录。我对这些都不感兴趣。
  • ssh_keys是唯一声称允许我设置主机私钥的部分
  • 本节中的其他条目似乎都不能让我控制是否生成密钥,或指定要使用的私有主机密钥。也许我读错了什么?

最后,我刚刚做了一个ssh-keyscan <host> | ssh-keygen -lf -并且发现,显然我的设备除了 ed25519 密钥之外还生成了一个 ECDSA 密钥:

$ ssh-keyscan <host> | ssh-keygen -lf -
# <host>:22 SSH-2.0-OpenSSH_8.9p1 Ubuntu-3
# <host>:22 SSH-2.0-OpenSSH_8.9p1 Ubuntu-3
# <host>:22 SSH-2.0-OpenSSH_8.9p1 Ubuntu-3
256 SHA256:T50YAWwIgIOsQNuIXGBpoz1xPFXJkzffafibruuABtQ <host> (ECDSA)
256 SHA256:DB00DS6xzx5v7ZdVBe+z4nLZhOGVrKuSdhwdenhAm4s <host> (ED25519)

(两个签名均与 的签名不匹配ed25519_private

答案1

最终答案分为三部分:

  1. ssh_keys:需要位于顶层,而不是用户之下
  2. ssh_deletekeys: false需要处于最高层,而不是之下ssh_keys:
  3. YAML 多行字符串语法非常微妙。我仍然不确定我到底做错了什么,但我改用带尾注的双引号语法\n,它开始起作用了。

最终的用户数据定义如下:

#cloud-config
users:
- name: 'foo'
  groups: users,adm,dialout,audio,netdev,video,plugdev,cdrom,games,input,gpio,spi,i2c,render,sudo
  shell: /bin/bash
  lock_passwd: true
  ssh_authorized_keys:
    - 'ssh-ed25519 ...'

ssh_keys:
  ed25519_private: "-----BEGIN OPENSSH PRIVATE KEY-----\n...\n-----END OPENSSH PRIVATE KEY-----\n"
  ed25519_public: ...

ssh_deletekeys: false

答案2

我假设您指的是此场景中的主机密钥。

要修复主机密钥被覆盖的问题,请设置

ssh_deletekeys: false

默认情况下,cloud-init 每次检测到它在新的实例上运行时都会覆盖现有的主机密钥。这是出于安全目的的默认行为。在云环境中,一个常见的用例是从现有实例创建新映像。在这种情况下,启动新实例但保留上一个实例的现有主机密钥将是一个安全漏洞。

对于像 Raspberry Pi 这样的物理设备,这种用例不应该相关,因此您可以设置ssh_deletekeysfalse

相关内容