我正在使用 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: false
下ssh_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
最终答案分为三部分:
ssh_keys:
需要位于顶层,而不是用户之下ssh_deletekeys: false
需要处于最高层,而不是之下ssh_keys:
- 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_deletekeys
为false
。