Which is cool, but is it also possible to specify existing keys?
For example I’d like to add ed25519 private key into my configuration (which is reasonable short key) and create /etc/ssh/ssh_host_ed25519_key from it and generate /etc/ssh/ssh_host_ed25519_key.pub from that private key (ssh-keygen -f x -y > x.pub).
You would want to use something like sops-nix. Ironically, sops-nix usually uses the host ssh key to decrypt secrets.
The problem is that for safe secret deployment, you always need to at least deploy one secret by some actual secure transfer mechanism (to decrypt all your other secrets). nix-build (and by extension nixos-rebuild and all other NixOS deployment tools) is definitely not such a secure mechanism, since it copies all your sources to the nix store in plain text. Hence, you need to copy over at least one secret by some other mechanism.
Typically the ssh host key is used for this one secret, because practically all servers run an ssh server for access, so it’s conveniently available. It often also needs to be present on the system for you to have access anyway, so by the time you run nixos-rebuild it should already be there.
So your safest options are to copy over that ssh key manually, or to copy a gpg key over manually and deploy the ssh key with sops-nix. Either way, some manual step is involved.
If you plan to deploy more services that work with secrets than just an ssh server I’d recommend figuring out sops-nix, though. It’s very useful for avoiding manual secret management in NixOS deployments.
I understand the need and value of secret management. But in case of a host keys… I think of them as an additional check for SSH so I’m not asked Are you sure you want to continue connecting (yes/no/[fingerprint])? Obviously I wouldn’t put my client personal SSH key into Nix configuration…
Would you consider using environment.etc."/etc/ssh/ssh_host_xxx_key for the host keys?
No! ssh uses public key encryption, aka asymmetric key encryption. By making the server side private key publicly known, an attacker can decrypt all messages your computer sends to the server, as well as pretend to be the server side.
It’s not just used for fingerprinting, that’s just to make sure the domain name matches the server you think you’re connecting to, since SSH has no better way to verify that.
Feel free to put the public key in your client configuration in plain text, but publishing your server’s private host key is at least as bad as publishing your root password (as it probably results in that, and likely worse…).
As a sops-nix user, who sometimes deploys partially prepared configuration, I usually do the manual installation with a bare minimal config, mostly as generated by the nixos-generate tool.
After installation but prior to rebooting, I place the intended hostkeys where they need to be.
Then I reboot.
After the reboot I finalize my setup by fetching and applying the intended configuration for the host.
This workflow has been succesfully applied in VMs about 2 or 3 times so far.
And I do not know why, but I have the feeling you are asking to reuse a single hostkey across machines… If this is true, simply don’t, unless you manage a fleet of cattle that really are all the same anyway.
I do exactly the same + I add the most simple flake.nix that just loads configuration.nix.
The additional benefit is that the simple configuration (basically just to boot) reveals any possible hardware (or virtualization configuration) issues and makes it much easier to debug than debugging my full config.
Maybe slightly less bad since the keys allow “only” to read the ongoing communication while a root password can be a way to SSH-in but yeah… It is bad. Thank you for the explanation.
and it didn’t work even after I deleted the existing host key and nixos-rebuild switch --flake .#mycomp
Maybe a problem how NixOS deals with existing files, maybe a protection against a security issue… not sure since environment.etc."ssh-todo/..." worked.
I struggled with the same problem. Except for @NobbZ solution or the usage of nixos anywhere there is no way to exchange the ssh host keys via configuration. But what works is to “smuggle” in an extra host key and point to it via the openssh.extraConfig option.
So nixos still generates it own keys but you configure sshd to point to your own created key.
Something like:
You can also use sops-nix to write to services.openssh.hostKeys.*.path. The service checks if the file already exists, and skips generating anything if it does; since sops-nix (or virtually any other method of deploying files outside of the nix store, including nixos-anywhere’s file smuggling) triggers well before that check, this is sufficient to deploy.
@NobbZ only needs that workaround since their deployments don’t always start from a complete configuration. This happens when you manually install a server without a full configuration and then want to switch to a different host key - sops-nix will complain if you try to overwrite an existing file. Since that deployment is already manual, I agree that just manually overwriting that file is probably best.
So this can be how you deploy your servers if you don’t know the hardware or whether your config will work ahead of time, or if you’re not sufficiently set up to do proper deployments yet. But it does not have to be.
If you can use extraConfig to set your key without touching the nix store you can also just use services.openssh.hostkeys.*.path and do whatever you did to get /run/secrets/ssh/ssh_host_ed25519_key deployed. I wouldn’t recommend what you’re doing, though without knowing your full deployment workflow it’s hard to give complete instructions as to what you should be doing.
I didn’t knew that. Thanks for explaining! I always just look at the available module options, not realising that nix lets you do so much more.
My main reason was to play around with sops-nix and trying to achieve a manual installation with a hostkey that I specify in the configuration. In my scenario I just let nixos generate the host keys copy my own generated hostkey on to the system and then deploy my config which points to this new hostkey. In the end I realised I could just overwrite the generated hostkey…
I long abandoned this approach and setteld with nixos-anywhere wherever possible. Much more convenient if a disko config is possible.