v0.5.15: inject cloud-init seed pubkey as admin sshkey at install time
v0.5.14 ships a working install but auto-install harness can't SSH- validate post-reboot — admin user has no authorized_keys, hardened sshd rejects all auth. SSH up + listening but no path to log in. Fix: detect_seed_pubkey() searches /dev/sr* for a NoCloud cidata volume (label "cidata"), parses ssh_authorized_keys: list from user-data, returns first key. generate_ks() then embeds as sshkey --username=admin "ssh-ed25519 AAAA... user@host" right after the user= directive. Anaconda creates /home/admin/.ssh/authorized_keys with right perms (700/600). Real users: drop a NoCloud seed iso next to install media (or via USB), pubkey lands automatically. auto-install.sh: existing run-vm.sh seed logic already builds the cidata iso with host pubkey. If no seed → directive line empty → anaconda treats as no-op → SSH validation blocked but install otherwise unaffected.
This commit is contained in:
parent
8861e12485
commit
d07adf3b14
1 changed files with 42 additions and 0 deletions
|
|
@ -309,6 +309,34 @@ sed_escape() {
|
||||||
printf '%s' "$1" | sed -e 's/[\\&|/]/\\&/g'
|
printf '%s' "$1" | sed -e 's/[\\&|/]/\\&/g'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# detect_seed_pubkey — search attached cdroms for a NoCloud cidata seed
|
||||||
|
# with an ssh_authorized_keys entry. Returns the first key on stdout, or
|
||||||
|
# empty string if none found. Used by both auto-install.sh (cloud-init
|
||||||
|
# seed pre-built with host pubkey) and humans (drop a seed iso next to
|
||||||
|
# the install media).
|
||||||
|
detect_seed_pubkey() {
|
||||||
|
local dev label tmpmnt key=""
|
||||||
|
for dev in /dev/sr0 /dev/sr1 /dev/sr2 /dev/sr3; do
|
||||||
|
[ -b "$dev" ] || continue
|
||||||
|
label=$(blkid -o value -s LABEL "$dev" 2>/dev/null)
|
||||||
|
if [[ $label == "cidata" || $label == "CIDATA" ]]; then
|
||||||
|
tmpmnt=$(mktemp -d)
|
||||||
|
if mount -o ro "$dev" "$tmpmnt" 2>/dev/null; then
|
||||||
|
# NoCloud user-data format:
|
||||||
|
# ssh_authorized_keys:
|
||||||
|
# - ssh-ed25519 AAAA... user@host
|
||||||
|
# Extract first ssh-* line, strip leading '- '.
|
||||||
|
key=$(grep -E '^\s*-\s+ssh-' "$tmpmnt/user-data" 2>/dev/null \
|
||||||
|
| head -1 | sed -e 's/^\s*-\s*//' -e 's/[[:space:]]*$//')
|
||||||
|
umount "$tmpmnt" 2>/dev/null
|
||||||
|
fi
|
||||||
|
rmdir "$tmpmnt" 2>/dev/null
|
||||||
|
[[ -n $key ]] && { printf '%s' "$key"; return 0; }
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
generate_ks() {
|
generate_ks() {
|
||||||
# Build kickstart for actual disk install.
|
# Build kickstart for actual disk install.
|
||||||
# NOTE: passwords go in via --plaintext to avoid storing crypted hash
|
# NOTE: passwords go in via --plaintext to avoid storing crypted hash
|
||||||
|
|
@ -345,6 +373,7 @@ firewall --enabled --service=ssh
|
||||||
|
|
||||||
rootpw --lock
|
rootpw --lock
|
||||||
user --name=admin --groups=wheel --gecos="veilor admin" --password=__ADMIN_PW__ --plaintext
|
user --name=admin --groups=wheel --gecos="veilor admin" --password=__ADMIN_PW__ --plaintext
|
||||||
|
__SSHKEY_DIRECTIVE__
|
||||||
|
|
||||||
# Full hardening cmdline (installed system, not live):
|
# Full hardening cmdline (installed system, not live):
|
||||||
# --location=none: anaconda auto-places bootloader (UEFI grub2-efi or BIOS).
|
# --location=none: anaconda auto-places bootloader (UEFI grub2-efi or BIOS).
|
||||||
|
|
@ -594,12 +623,25 @@ KSEOF
|
||||||
# already rejects "$\`&|/\n at input — sed_escape() is defence in
|
# already rejects "$\`&|/\n at input — sed_escape() is defence in
|
||||||
# depth in case future code paths feed unsanitised values (e.g.
|
# depth in case future code paths feed unsanitised values (e.g.
|
||||||
# locale/hostname from a file, or a relaxed validator).
|
# locale/hostname from a file, or a relaxed validator).
|
||||||
|
# Detect cloud-init seed pubkey (if attached) → embed as anaconda
|
||||||
|
# `sshkey --username=admin` directive. Adds key to admin's
|
||||||
|
# authorized_keys at install time so SSH validation works first boot.
|
||||||
|
# No seed = empty directive line (anaconda treats blank line as no-op).
|
||||||
|
local seed_pubkey sshkey_directive=""
|
||||||
|
seed_pubkey=$(detect_seed_pubkey 2>/dev/null) || true
|
||||||
|
if [[ -n $seed_pubkey ]]; then
|
||||||
|
echo "[INFO] using cloud-init seed pubkey for admin authorized_keys"
|
||||||
|
# sshkey directive — quote pubkey, no shell meta in pubkeys.
|
||||||
|
sshkey_directive="sshkey --username=admin \"${seed_pubkey}\""
|
||||||
|
fi
|
||||||
|
|
||||||
sed -i \
|
sed -i \
|
||||||
-e "s|__LOCALE__|$(sed_escape "$SEL_LOCALE")|" \
|
-e "s|__LOCALE__|$(sed_escape "$SEL_LOCALE")|" \
|
||||||
-e "s|__HOSTNAME__|$(sed_escape "$SEL_HOSTNAME")|" \
|
-e "s|__HOSTNAME__|$(sed_escape "$SEL_HOSTNAME")|" \
|
||||||
-e "s|__DISK_BASENAME__|$(sed_escape "$disk_basename")|" \
|
-e "s|__DISK_BASENAME__|$(sed_escape "$disk_basename")|" \
|
||||||
-e "s|__LUKS_PW__|$(sed_escape "$SEL_LUKS_PW")|" \
|
-e "s|__LUKS_PW__|$(sed_escape "$SEL_LUKS_PW")|" \
|
||||||
-e "s|__ADMIN_PW__|$(sed_escape "$SEL_ADMIN_PW")|" \
|
-e "s|__ADMIN_PW__|$(sed_escape "$SEL_ADMIN_PW")|" \
|
||||||
|
-e "s|__SSHKEY_DIRECTIVE__|$(sed_escape "$sshkey_directive")|" \
|
||||||
"$out"
|
"$out"
|
||||||
echo "[INFO] generated kickstart at $out"
|
echo "[INFO] generated kickstart at $out"
|
||||||
return 0
|
return 0
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue