Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

copy over ssh host keys #229

Merged
merged 7 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions docs/howtos/secrets.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,16 @@ In the above example, replace `"my-super-safe-password"` with your actual
encryption password, and `my-disk-encryption-password` with the relevant entry
in your pass password store. Also, ensure to replace `'.#your-host'` and
`root@yourip` with your actual flake and IP address, respectively.

## Example: Using existing SSH host keys

If the system contains existing trusted `/etc/ssh/ssh_host_*` SSH host keys and
certificates, `nixos-anywhere` can copy them in case they are necessary during
installation and system activation.

```
nixos-anywhere --copy-host-keys --flake '.#your-host' root@yourip
```

This would copy `/etc/ssh/ssh_host_*` to `/mnt` after kexec but before
installation, ignoring files that already exist in destination.
17 changes: 15 additions & 2 deletions docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,28 @@ Options:
set the flake to install the system from.
* -i <identity_file>
selects which SSH private key file to use.
* -p, --ssh-port <ssh_port>
set the ssh port to connect with
* --ssh-option <ssh_option>
set an ssh option
* -L, --print-build-logs
print full build logs
* -s, --store-paths <disko-script> <nixos-system>
set the store paths to the disko-script and nixos-system directly
if this is give, flake is not needed
* -t --tty
Force pseudo-terminal allocation in SSH sessions. Use this when you expect e.g.
to be asked for password entry during LUKS configuration.
* --no-reboot
do not reboot after installation, allowing further customization of the target installation.
* --kexec <url>
* --kexec <path>
use another kexec tarball to bootstrap NixOS
* --post-kexec-ssh-port <ssh_port>
after kexec is executed, use a custom ssh port to connect. Defaults to 22
* --copy-host-keys
copy over existing /etc/ssh/ssh_host_* host keys to the installation
* --stop-after-disko
exit after disko formating, you can then proceed to install manually or some other way
exit after disko formatting, you can then proceed to install manually or some other way
* --extra-files <file...>
files to copy into the new nixos installation
* --disk-encryption-keys <remote_path> <local_path>
Expand All @@ -53,6 +64,8 @@ Options:
URL of the source Nix store to copy the nixos and disko closure from
* --build-on-remote
build the closure on the remote machine instead of locally and copy-closuring it
* --vm-test
build the system and test the disk configuration inside a VM without installing it to the target.
```

## Explanation of known error messages
Expand Down
21 changes: 19 additions & 2 deletions src/nixos-anywhere.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ Options:
use another kexec tarball to bootstrap NixOS
* --post-kexec-ssh-port <ssh_port>
after kexec is executed, use a custom ssh port to connect. Defaults to 22
* --copy-host-keys
copy over existing /etc/ssh/ssh_host_* host keys to the installation
* --stop-after-disko
exit after disko formatting, you can then proceed to install manually or some other way
* --extra-files <file...>
Expand Down Expand Up @@ -119,6 +121,9 @@ while [[ $# -gt 0 ]]; do
post_kexec_ssh_port=$2
shift
;;
--copy-host-keys)
copy_host_keys=y
;;
--debug)
enable_debug="-x"
print_build_logs=y
Expand Down Expand Up @@ -450,13 +455,25 @@ fi

step Installing NixOS
ssh_ bash <<SSH
set -efu ${enable_debug}
set -eu ${enable_debug}
# when running not in nixos we might miss this directory, but it's needed in the nixos chroot during installation
export PATH=\$PATH:/run/current-system/sw/bin
export PATH="\$PATH:/run/current-system/sw/bin"

# needed for installation if initrd-secrets are used
mkdir -p /mnt/tmp
chmod 777 /mnt/tmp
if [[ ${copy_host_keys-n} == "y" ]]; then
# NB we copy host keys that are in turn copied by kexec installer.
mkdir -m 755 -p /mnt/etc/ssh
for p in /etc/ssh/ssh_host_*; do
# Skip if the source file does not exist (i.e. glob did not match any files)
# or the destination already exists (e.g. copied with --extra-files).
if [ ! -e "\$p" -o -e "/mnt/\$p" ]; then
continue
fi
cp -a "\$p" "/mnt/\$p"
done
fi
nixos-install --no-root-passwd --no-channel-copy --system "$nixos_system"
if command -v zpool >/dev/null; then
zpool export -a || : # we always want to export the zfs pools so people can boot from it without force import
Expand Down
8 changes: 8 additions & 0 deletions tests/from-nixos.nix
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,19 @@
start_all()
installer.succeed("mkdir -p /tmp/extra-files/var/lib/secrets")
installer.succeed("echo value > /tmp/extra-files/var/lib/secrets/key")
ssh_key_path = "/etc/ssh/ssh_host_ed25519_key.pub"
ssh_key_output = installer.wait_until_succeeds(f"""
ssh -i /root/.ssh/install_key -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \
root@installed cat {ssh_key_path}
""")
installer.succeed("""
nixos-anywhere \
-i /root/.ssh/install_key \
--debug \
--kexec /etc/nixos-anywhere/kexec-installer \
--extra-files /tmp/extra-files \
--store-paths /etc/nixos-anywhere/disko /etc/nixos-anywhere/system-to-install \
--copy-host-keys \
root@installed >&2
""")
try:
Expand All @@ -42,5 +48,7 @@
assert "nixos-anywhere" == hostname, f"'nixos-anywhere' != '{hostname}'"
content = new_machine.succeed("cat /var/lib/secrets/key").strip()
assert "value" == content, f"secret does not have expected value: {content}"
ssh_key_content = new_machine.succeed(f"cat {ssh_key_path}").strip()
assert ssh_key_content in ssh_key_output, "SSH host identity changed"
'';
}