[SOLVED] Container Template: automatisch neue SSH Host-Keys generieren beim 1. Start des Containers

anderl1969

Member
Jul 10, 2022
70
10
8
Ich bastele mir gerade ein Container-Template auf Debian 11 Basis, aus dem ich mir bei Bedarf schnell neue LXC-Container klonen kann.
Bevor ich den Basis-Container in ein Template konvertiert habe, hatte ich /etc/machine-id und die Host-Keys unter /etc/ssh/ssh_host_* gelöscht.

In den geklonten Containern wird /etc/machine-id automatisch neu generiert. Die Host-Keys aber nicht, die müssen mittels dpkg-reconfigure openssh-server manuell neu generiert werden.

Jetzt hatte ich die Idee, das mittels Script automatisch machen zu lassen. Das Script muss natürlich schon im Template angelegt werden.
Das Prinzip ist einfach: Das Script prüft, ob unter /etc/ssh Dateien mit dem Muster ssh_host_* existieren. Falls ja, tut es nichts. Falls nein, ruft es dpkg-reconfigure openssh-server auf.

Die Frage ist: Wo und wie wird das Script am Besten in den System-Start des Containers eingepflanzt?

Wo ich mich zuletzt mit solchen Themen beschäftigt hatte, gab's noch kein systemd.

Hier das Script:
Code:
#! /bin/bash
# name: initsshkeys.sh

KEY_FOLDER=/etc/ssh/
FILE_PATTERN=ssh_host_*

if ! (find $KEY_FOLDER -type f -name $FILE_PATTERN -printf 1 -quit | grep -q 1); then
        dpkg-reconfigure openssh-server
fi
 
Edit: war abgelenkt und daher hab ich einfach Englisch drauflos geschrieben, argh.. Ist aber nicht viel Inhalt also lasse ichs mal so, einfach fragen wenn was unklar ist.

You could also try to handle this via a systemd unit. E.g., in the base template create a new unit file file at
/etc/systemd/system/ssh-keygen-firstboot.service, containing something like (not really tested):

Code:
[Unit]
Description=Regenerate SSH host keys on first boot
ConditionFirstBoot=yes
Before=first-boot-complete.target sshd.service
Wants=first-boot-complete.target

[Service]
Type=oneshot
ExecStartPre=-/bin/rm -f /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_ecdsa_key /etc/ssh/ssh_host_ed25519_key
ExecStart=/bin/ssh-keygen -q -N "" -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key
ExecStart=/bin/ssh-keygen -q -N "" -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key
ExecStart=/bin/ssh-keygen -q -N "" -t ed25519 -f /etc/ssh/ssh_host_ed25519_key
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

And enable it using systemctl enable ssh-keygen-firstboot.service

The ConditionFirstBoot matches with machine-id being removed, and thus this should only get executed on first boot after clone.

The dpkg-reconfigure step basically calls ssh-keygen the same way.
 
Last edited:
Funktioniert leider nicht.

Ich hab ein neues Template generiert, in dem sowohl /etc/machine-id gelöscht (truncate -s 0 /etc/machine-id) als auch die ssh-host-key gelöscht sind und obiges ssh-keygen-firstboot.service installiert und enabled ist.

In den geklonten Containern wird zwar eine neue /etc/machine-id generiert, aber leider keine neuen ssh-host-keys generiert.

systemctl status ssh-keygen-firstboot liefert folgendes:
Code:
● ssh-keygen-firstboot.service - Regenerate SSH host keys on first boot
     Loaded: loaded (/etc/systemd/system/ssh-keygen-firstboot.service; enabled; vendor preset: enabled)
     Active: inactive (dead)
  Condition: start condition failed at Tue 2023-04-25 20:30:30 CEST; 1min 5s ago
             └─ ConditionFirstBoot=yes was not met

Apr 25 20:30:30 deb11ct200 systemd[1]: Condition check resulted in Regenerate SSH host keys on first boot being skipped.

Die machine-id ist aber gelöscht! Ich krieg auch in jedem geklonten Container eine andere machine-id generiert.

Nur zur Sicherheit:
Ich hab die Datei /etc/machine-id nicht gelöscht, sondern mit truncate -s 0 /etc/machine-id nur den Inhalt gelöscht.
 
Update:
wenn ich im Template wirklich die Datei /etc/machine-id lösche, dann klappt's. Also wirklich die Datei komplett löschen, nicht nur den Inhalt.

Das hatte ich mich ursprünglich nicht getraut, weil ich dachte, dass der symbolic-link /var/lib/dbus/machine-id, der ja auf /etc/machine-id verweist, dann vielliecht durcheinander kommt. Aber der scheint damit kein Problem zu haben.

Ist es also unkritisch, die Datei /etc/machine-id im Template komplett zu löschen?

Edit:
Funktioniert doch noch nicht.
Auch wenn im Template /etc/machine-id gelöscht ist, wird der ssh-keygen-firstboot.service beim 1. Start des geklonten Containers nicht getriggert (ConditionFirstBoot=yes was not met). Erst wenn ich im CT /etc/machine-id nochmal lösche und den CT reboote, dann triggert der Service.

Noch eine Idee, wie man das hinkriegt?
 
Last edited:
/etc/machine-id gelöscht (truncate -s 0 /etc/machine-id)
Wenn das File danach noch existiert, würde ich das jetzt nicht unbedingt als löschen bezeichnen, sieht systemd wohl auch so,
siehe die machine-id man page
3. If /etc/machine-id exists and is empty, a boot is not considered the first boot. systemd will still
bind-mount a file containing the actual machine-id over it and later try to commit it to disk (if /etc/ is
writable).
Du musst eine dieser beiden Varianten probieren:
1. If /etc/machine-id does not exist, this is a first boot. During early boot, systemd will write
"uninitialized\n" to this file and overmount a temporary file which contains the actual machine ID. Later
(after first-boot-complete.target has been reached), the real machine ID will be written to disk.

2. If /etc/machine-id contains the string "uninitialized", a boot is also considered the first boot. The same
mechanism as above applies.
Dann sagt systemd nämlich auch:
If by any of the above rules, a first boot is detected, units with ConditionFirstBoot=yes will be run.
Auch wenn im Template /etc/machine-id gelöscht ist, wird der ssh-keygen-firstboot.service beim 1. Start des geklonten Containers nicht getriggert (ConditionFirstBoot=yes was not met). Erst wenn ich im CT /etc/machine-id nochmal lösche und den CT reboote, dann triggert der Service.
Und du erstellst das Template direkt nach löschen von /etc/machine-id gefolgt von poweroff?

Das hatte ich mich ursprünglich nicht getraut, weil ich dachte, dass der symbolic-link /var/lib/dbus/machine-id, der ja auf /etc/machine-id verweist, dann vielliecht durcheinander kommt.
Bei symlinks ist das egal, wenn das File wieder existiert zeigt der symlink auch wieder darauf, hardlinks wären da anders.

Potenziell mal das filesystem des Templates am Host mounten und schauen, ob da /etc/machine-id wirklich weg ist.
 
Danke für Deine ausführlichen Informationen zu /etc/machine-id und systemd/firstboot.
Und du erstellst das Template direkt nach löschen von /etc/machine-id gefolgt von poweroff?
Ja. Definitiv.
Potenziell mal das filesystem des Templates am Host mounten und schauen, ob da /etc/machine-id wirklich weg ist.
Hab ich getan:
Bash:
> ls /ZFS-Pool-SSD/basevol-8102-disk-0/etc/machine-id
ls: cannot access '/ZFS-Pool-SSD/basevol-8102-disk-0/etc/machine-id': No such file or directory

> ls /ZFS-Pool-SSD/basevol-8102-disk-0/etc/ssh
moduli  ssh_config  ssh_config.d  sshd_config  sshd_config.d
keine machine-id und keine ssh_host-keys im Template.
 
keine machine-id und keine ssh_host-keys im Template.
Oje, das Verhalten stammt wohl von Proxmox VE's Container Management selber. Zurzeit truncaten (sprich File existiert, aber empty) wir beim Clonen das machine-id file immer, um explizit die firstboot Condition zu vermeiden.

Das werden wir wohl ändern müssen, sodass es beim clonen nur truncated wenn das File im template auch wirklich da ist und der Admin hier eine gewisse Kontrolle noch hat um das first-boot verhalten zu erzwingen.

Bis dahin könntest du als workaround einfach eine andere Condition verwenden, etwa ob ein file (nicht) existiert, bspw. /etc/ssh/ssh_host_rsa_key (das soll ja sowieso erzeugt werden):

Die Unit würd dann wie folgt ausschauen:
Code:
[Unit]
Description=Regenerate SSH host keys after clone
ConditionPathExists=!/etc/ssh/ssh_host_rsa_key
Before=sshd.service

[Service]
Type=oneshot
ExecStartPre=-/bin/rm -f /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_ecdsa_key /etc/ssh/ssh_host_ed25519_key
ExecStart=/bin/ssh-keygen -q -N "" -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key
ExecStart=/bin/ssh-keygen -q -N "" -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key
ExecStart=/bin/ssh-keygen -q -N "" -t ed25519 -f /etc/ssh/ssh_host_ed25519_key
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
 
  • Like
Reactions: anderl1969
Danke für Deine Erläuterungen. Dass beim Klonen /etc/machine-id getrunkt (truncated?) wird, ist aufschlußreich. Aus Neugier hab ich das natürlich gleich mal nachvollzogen:

Hier das Volume des Template mit gelöschtem /etc/machine-id File:
Code:
> ls -l /ZFS-Pool-SSD/basevol-8103-disk-0/etc/machine-id
ls: cannot access '/ZFS-Pool-SSD/basevol-8103-disk-0/etc/machine-id': No such file or directory

Und hier das Volume eines geklonten CT noch vor seinem 1. Start:
Code:
> ls -l /ZFS-Pool-SSD/subvol-402-disk-0/etc/machine-id
-rw-r--r-- 1 100000 100000 1 Apr 26 14:07 /ZFS-Pool-SSD/subvol-402-disk-0/etc/machine-id

> cat /ZFS-Pool-SSD/subvol-402-disk-0/etc/machine-id
Wie Du schreibst, existiert /etc/machine-id bereits unmittelbar nach dem Klonen. Wieder was gelernt. Danke dafür.

Und das neue Service-File funktioniert jetzt auch wie gewünscht!!! Besten Dank!
 
Dass beim Klonen /etc/machine-id getrunkt (truncated?) wird, ist aufschlußreich
Hab jetzt angepasst, dass das machine-id File nur dann "gestutzt" (truncated) wird, wenn es vorher auch existierte. Bzw. wird es auch nicht mehr angefasst, falls "uninitialized" explizit drin steht

Änderung ist zurzeit nur im git, aber mit dem nächsten Versionsbump vom pve-container Paket sollte das Verhalten etwas weniger verwirrend sein.

https://git.proxmox.com/?p=pve-container.git;a=commitdiff;h=a72424ba7296d846b8893d3c070138eb280c51cd
Und das neue Service-File funktioniert jetzt auch wie gewünscht!!!
Freut mich zu hören!
 
Auch wenn es bereits wie gewünscht funktioniert, mein Spieltrieb ist geweckt. pve-container ist aktuell 4.4-3 - wenn das nächste Update kommt, gebe ich der 1. Variante mit ConditionFirstBoot=yes nochmal eine Chance :)
 
Wie versprochen: nachdem ich heute pve-container auf 4.4-4 aktualisiert hatte, habe ich die Variante mit
Code:
[Unit]
Description=Regenerate SSH host keys on first boot
ConditionFirstBoot=yes
Before=first-boot-complete.target sshd.service
Wants=first-boot-complete.target
nochmal getestet.

Ich kann bestätigen, dass mit der aktuellen Version 4.4-4 die /etc/machine-id beim Klonen nicht mehr "gestutzt" wird, wenn im Template /etc/machine-id gar nicht exisitiert hat.
Somit funktioniert auch die ConditionFirstBoot.
 
  • Like
Reactions: t.lamprecht

About

The Proxmox community has been around for many years and offers help and support for Proxmox VE, Proxmox Backup Server, and Proxmox Mail Gateway.
We think our community is one of the best thanks to people like you!

Get your subscription!

The Proxmox team works very hard to make sure you are running the best software and getting stable updates and security enhancements, as well as quick enterprise support. Tens of thousands of happy customers have a Proxmox subscription. Get yours easily in our online shop.

Buy now!