0

I am using cloud-init to set up a Raspberry Pi with Ubuntu Server 22.04.1. I would like to set the device's SSH keys so I can connect without being vulnerable to a man-in-the-middle attack.

My current user-data is:

#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: ...

When I go to ssh into the device, its ECDSA fingerprint changes every time. (i.e. if I re-image the drive and let cloud-init run again, then go SSH in, the fingerprint is different. It never matches the fingerprint of the keys in ed25519_private/public from the user-data.) So I think it's generating new keys on boot, and I'm at a loss for how to stop that.

How can I set the device's SSH keys?

Update (per @muru):

The host key section of the cloud-init docs includes a few relevant entries:

  • Theoretically if you specify ssh_keys then no new keys will be generated. I'm not sure what I'm doing wrong that this is not the case.
  • I've tried putting ssh_deletekeys: false under ssh_keys, the user object, and at the global level. SSH'ing in still produces new key fingerprints each time.
  • I've tried putting ssh_genkeytypes: [] under ssh_keys, the user object, and at the global level. Sometimes (I didn't record which) this results in me being unable to ssh in at all, presumably because no keys are present. In no case did I see the correct key fingerprint (as derived from ed25519_private).
  • Some entries let me import public keys to my authorized keys, publish keys, suppress keygen output or enable/disable root login. I'm not interested in any of those things.
  • ssh_keys is the only section that claims to let me set the private keys of the host
  • No other entry in this section seems to let me control whether keys are generated, or specify private host keys to use. Maybe I'm misreading something?

Lastly, I just did an ssh-keyscan <host> | ssh-keygen -lf - and saw that, apparently, my device is generating an ECDSA key in addition to an ed25519 key:

$ 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)

(neither signature matches the signature of ed25519_private)

5
  • You need to set the host keys: cloudinit.readthedocs.io/en/latest/topics/…
    – muru
    Nov 19, 2022 at 8:08
  • @muru Don't worry, I looked at the docs before asking =) Issue is, I can't figure out how to make it work - I've tried every vaguely-relevant option in that section in every way I can think of, but none of them make this work. Since re-reading the docs a few times didn't help, I asked here.
    – Dragon
    Nov 19, 2022 at 17:07
  • Can you show how exactly you tried that section?
    – muru
    Nov 19, 2022 at 18:34
  • @muru does that help?
    – Dragon
    Nov 19, 2022 at 19:32
  • No, you need to show the cloud-init config
    – muru
    Nov 20, 2022 at 2:07

2 Answers 2

3

Ultimately the answer had three parts:

  1. ssh_keys: needed to be at the top level, not under a user
  2. ssh_deletekeys: false needed to be at the top level, not under ssh_keys:
  3. YAML multiline string syntax is very delicate. I'm still not sure what exactly I was doing wrong there, but I switched to using double-quote syntax with a trailing \n and it started working.

The final user-data definition is as follows:

#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
0

I'm assuming you're referring to the host keys in this scenario.

To fix host keys getting overwritten, set

ssh_deletekeys: false

By default, cloud-init will overwrite existing host keys every time it detects that it is running on a new instance. This is the default behavior for security purposes. In a cloud environment, a common use case is to create new images from existing instances. In that scenario, launching new instances but keeping existing host keys from the previous instance would be a security vulnerability.

For a physical device like a Raspberry Pi, this use case shouldn't be relevant, so you can set ssh_deletekeys to false.

1
  • I've tried putting ssh_deletekeys: false under ssh_keys (and also tried it separately under the user object), but the keys are still getting regenerated. Is there something additional required to make this work?
    – Dragon
    Nov 19, 2022 at 16:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .