diff --git a/diskless.pkr.hcl b/diskless.pkr.hcl index caa24a1..821968c 100644 --- a/diskless.pkr.hcl +++ b/diskless.pkr.hcl @@ -278,6 +278,11 @@ build { "printf 'PermitRootLogin no\\nPasswordAuthentication no\\nKbdInteractiveAuthentication no\\n' > /etc/ssh/sshd_config.d/50-fleet-hardening.conf", "chmod 0644 /etc/ssh/sshd_config.d/50-fleet-hardening.conf", "restorecon /etc/ssh/sshd_config.d/50-fleet-hardening.conf", + # Guarantee sshd is enabled (it's our ONLY way in once root is locked and + # the admin user is key-only). Don't rely on the distro preset. Validate + # the full sshd config so a bad drop-in fails the BUILD, not the boot. + "systemctl enable sshd.service", + "sshd -t", # Lock root in the image. Done last; admin access is via the key user. "passwd -l root", "echo \"root locked; admin user $ADMIN_USER created (wheel + NOPASSWD sudo, key-only).\"", diff --git a/docs/TODO.md b/docs/TODO.md index 9ccc58d..39066b8 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -64,6 +64,14 @@ and cleanup. but document/deviate), and the admin key/user are **fleet-wide baked** — for per-host/rotatable access without rebuilds, layer the signed HTTP/SMBIOS config-agent or an SSH CA (`TrustedUserCAKeys`) discussed in session. +- **SSH host keys (done):** `extract-artifacts.sh` strips `/etc/ssh/ssh_host_*` + so they're not baked (baked keys = shared fleet identity + the build's + perms/group don't survive the tar→erofs round-trip, so sshd rejected them + "Permissions 640 too open" and refused to start). RHEL's `sshd-keygen@.service` + regenerates them into the overlay before sshd starts. **⚠ Caveat:** the + ephemeral overlay means they regenerate **every boot** → the host key changes + per reboot (clients warn). Follow-up for a stable host identity: persist the + host keys or derive them from the TPM (ties to the hostnqn/identity model). ## [ ] 3. Roll the errata into design doc v3 diff --git a/scripts/extract-artifacts.sh b/scripts/extract-artifacts.sh index 45df610..dfc411d 100755 --- a/scripts/extract-artifacts.sh +++ b/scripts/extract-artifacts.sh @@ -68,6 +68,17 @@ tar -C "$WORK/root" --numeric-owner --xattrs --xattrs-include='*' --acls --selin -xpf "$WORK/rootfs.tar" rm -rf "$WORK/root/boot/"* "$WORK/rootfs.tar" # diskless hosts don't need /boot +# Strip SSH host keys. They are PER-HOST identity (invariant #1) and must not be +# baked: a baked key means every host shares one SSH identity (MITM risk), and +# the build VM's key perms/group don't survive the tar->erofs round-trip, so +# sshd rejects them ("Permissions 640 ... too open") and refuses to start. +# RHEL's sshd-keygen@.service regenerates them with correct perms before sshd +# starts, into the writable volatile overlay. NOTE: with the ephemeral overlay +# they regenerate EVERY boot, so the host key changes each reboot (SSH clients +# will warn) — for a stable identity, persist them or derive from the TPM +# (future; ties to the hostnqn/identity model). +rm -f "$WORK/root/etc/ssh/"ssh_host_* + # Fail loudly if labels didn't make it — shipping an unlabeled enforcing image # boots but denies all logins (the symptom we just chased down). if ! getfattr -h -n security.selinux "$WORK/root/usr/bin/bash" >/dev/null 2>&1; then