From 5eee16d24b51e86bd7cf09f5592f1a57f8028e90 Mon Sep 17 00:00:00 2001 From: a-kenji Date: Wed, 27 Nov 2024 12:31:50 +0100 Subject: [PATCH] feat: Use `identity_file` as deployment key Will now use the provided `-i` (identity_file) as a stable deployment key - if specified - rather than always generating a random ephemeral SSH key. This is primarily useful for the following reasons: - error recovery - controlled phases *Error Recovery* If `nixos-anywhere` stops with an error, we might want to connect remotely to the deployed machine. With the ephemeral key this might not be possible, because we don't necessarily have access to it anymore. *Controlled Phases* It is already possible to control which phases should be run. With an ephemeral key outside our control we are not able to resume the phases with a second `nixos-anywhere` invocation, because a different deployment key will now be generated. --- docs/quickstart.md | 4 ++- src/nixos-anywhere.sh | 9 +++-- tests/flake-module.nix | 1 + tests/from-nixos-separated-phases.nix | 52 +++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 tests/from-nixos-separated-phases.nix diff --git a/docs/quickstart.md b/docs/quickstart.md index d9881cf0..29e20f0e 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -113,7 +113,9 @@ example uses a local directory on the source machine. If your SSH key is not found, you will be asked for your password. If you are using a non-root user, you must have access to sudo without a password. To avoid SSH password prompts, set the `SSHPASS` environment variable to your password -and add `--env-password` to the `nixos-anywhere` command. +and add `--env-password` to the `nixos-anywhere` command. If providing a +specific SSH key through `-i` (identity_file), this key will then be used for +the installation and no temporary SSH key will be created. ### 7. (Optional) Test your NixOS and Disko configuration diff --git a/src/nixos-anywhere.sh b/src/nixos-anywhere.sh index 426504f2..86280593 100755 --- a/src/nixos-anywhere.sh +++ b/src/nixos-anywhere.sh @@ -367,10 +367,15 @@ runVmTest() { } uploadSshKey() { - # we generate a temporary ssh keypair that we can use during nixos-anywhere # ssh-copy-id requires this directory mkdir -p "$HOME/.ssh/" - ssh-keygen -t ed25519 -f "$sshKeyDir"/nixos-anywhere -P "" -C "nixos-anywhere" >/dev/null + if [[ -n ${sshPrivateKeyFile} ]]; then + cp "$sshPrivateKeyFile" "$sshKeyDir/nixos-anywhere" + ssh-keygen -y -f "$sshKeyDir/nixos-anywhere" >"$sshKeyDir/nixos-anywhere.pub" + else + # we generate a temporary ssh keypair that we can use during nixos-anywhere + ssh-keygen -t ed25519 -f "$sshKeyDir"/nixos-anywhere -P "" -C "nixos-anywhere" >/dev/null + fi declare -a sshCopyIdArgs if [[ -n ${sshPrivateKeyFile} ]]; then diff --git a/tests/flake-module.nix b/tests/flake-module.nix index 4f647dc1..4350da95 100644 --- a/tests/flake-module.nix +++ b/tests/flake-module.nix @@ -20,5 +20,6 @@ from-nixos-with-sudo-stable = import ./from-nixos-with-sudo.nix testInputsStable; from-nixos-with-generated-config = import ./from-nixos-generate-config.nix testInputsUnstable; from-nixos-build-on-remote = import ./from-nixos-build-on-remote.nix testInputsUnstable; + from-nixos-separated-phases = import ./from-nixos-separated-phases.nix testInputsUnstable; }); } diff --git a/tests/from-nixos-separated-phases.nix b/tests/from-nixos-separated-phases.nix new file mode 100644 index 00000000..35a89f4b --- /dev/null +++ b/tests/from-nixos-separated-phases.nix @@ -0,0 +1,52 @@ +(import ./lib/test-base.nix) { + name = "from-nixos-separated-phases"; + nodes = { + installer = ./modules/installer.nix; + installed = { + services.openssh.enable = true; + virtualisation.memorySize = 1024; + + users.users.nixos = { + isNormalUser = true; + openssh.authorizedKeys.keyFiles = [ ./modules/ssh-keys/ssh.pub ]; + extraGroups = [ "wheel" ]; + }; + security.sudo.enable = true; + security.sudo.wheelNeedsPassword = false; + }; + }; + testScript = '' + start_all() + + with subtest("Kexec Phase"): + installer.succeed(""" + nixos-anywhere \ + -i /root/.ssh/install_key \ + --debug \ + --kexec /etc/nixos-anywhere/kexec-installer \ + --phases kexec \ + --store-paths /etc/nixos-anywhere/disko /etc/nixos-anywhere/system-to-install \ + nixos@installed >&2 + """) + + with subtest("Disko Phase"): + output = installer.succeed(""" + nixos-anywhere \ + -i /root/.ssh/install_key \ + --debug \ + --phases disko \ + --store-paths /etc/nixos-anywhere/disko /etc/nixos-anywhere/system-to-install \ + installed >&2 + """) + + with subtest("Install Phase"): + installer.succeed(""" + nixos-anywhere \ + -i /root/.ssh/install_key \ + --debug \ + --phases install \ + --store-paths /etc/nixos-anywhere/disko /etc/nixos-anywhere/system-to-install \ + root@installed >&2 + """) + ''; +}