This blog post recaps how to install NixOS with only a WiFi connection, how to manage the WiFi connection declaratively and how to encrypt the passphrase during deploy.
This is only really useful for a machine that will not move much. If you’re trying to configure WiFi
on a laptop, I would recommend using services.networkmanager and configure the connection
manually.
- Why Encrypt the Passphrase
- Enable WiFi Manually
- Initial Install WiFi Configuration
- Deploy with Encrypted Secret
Why Encrypt the Passphrase
Like for any non-encrypted secret in NixOS, two issues arise if you put the passphrase in clear in the configuration:
- the passphrase will be stored in the nix store of both the build machine and the target machine
- and the passphrase will be stored in the git repo you use to manage your deploy.
The solution to the first issue is to use something like the deployment.keys option that is
supported by most deployment tools.
The solution to the second issue is to encrypt the secret in the repo, and decrypt it on the target machine, after deploy. Multiple tools exist to handle this.
In this post, we will use sops-nix which provides a solution for both issues.
Enable WiFi Manually
A little aside before we start. If something goes wrong, you can always setup WiFi manually with the commands from the wpa_supplicant and dhcpcd Arch Linux wiki. The only difference with the wiki is you do not need to install the commands as they come with NixOS.
sudo wpa_supplicant -B \
-i wlan0 \
-c <(wpa_passphrase SSID PASSPHRASE)
touch dhcpcd.conf && \
sudo dhcpcd --config dhcpcd.confInitial Install WiFi Configuration
Assuming you just booted on NixOS for the first time on the target machine and you made some edits
to configuration.nix, your next step is to run nixos-rebuild switch. But first, you need a
working internet connection.
What is following looks like a convoluted way to set WiFi up but it sets us up nicely to be able to declaratively set the WiFi connection with an encrypted password later on.
In the machine’s configuration.nix, add:
networking.wireless = {
enable = true;
environmentFile = "/run/secrets/MY_SSID_PSK";
networks = {
"MY_SSID" = {
psk = "@MY_SSID_PSK@";
};
};
};Replace MY_SSID with the name of the SSID you will be connecting to.
Then create the file /run/secrets/MY_SSID_PSK with the following content:
MY_SSID_PSK=theactualpassphrase
Deploy with Encrypted Secret
Like we said earlier, we will use nix-sops to encrypt the secret at rest and during deploy.
A few prerequisites:
- You copied over the machine’s configuration.nix locally which includes the networking.wireless
section we added earlier.
- You created a public/private key pair that allows you to ssh into the target machine.
Now, to actually encrypt the secret, we will follow the nix-sops readme file. The gist is:
Install the necessary packages to run the commands:
nix shell nixpkgs#ssh-to-age nixpkgs#sopsYou need the latest
ssh-to-agebinary as the one provided in 21.11 does not have all the necessary arguments.Create an
agesecret from that public/private key pair used to connect to the target machine.ssh-to-age -private-key \ -i ~/.ssh/TARGET_HOSTNAME \ -o ~/.config/sops/age/TARGET_HOSTNAME.txt age-keygen -y ~/.config/sops/age/TARGET_HOSTNAME.txtUse the output of that last command for
admin_nixoslater on.Also, replace
TARGET_HOSTNAMEwith the actual hostname of the target machine.If the private key uses a passphrase, you’ll first need to export an environment variable with the passphrase:
read -s SSH_TO_AGE_PASSPHRASE export SSH_TO_AGE_PASSPHRASEGet the
agesecret from the target machinessh-keyscan -t ed25519 TARGET_MACHINE_IP | \ ssh-to-ageUse the output of that command for
server_TARGET_HOSTNAMElater on.Note here I am using the IP of the target machine as
ssh-keyscanwas failing to retrieve anything with the hostname. I do not know why.Then fill in
.sops.yamlwith:keys: - &admin_nixos age1... - &server_TARGET_HOSTNAME age1... creation_rules: - path_regex: secrets/[^/]+\.yaml$ key_groups: - age: - *admin_nixos - *server_TARGET_HOSTNAMEThat file should be living in your repository used for deploys.
A few replacements are needed in the file:
- Replace
age1...string foradmin_nixoswith the value we obtained at step 2. - Replace
age1...string forserver_TARGET_HOSTNAMEwith the value we obtained at step 3. - Replace
TARGET_HOSTNAMEwith the actual hostname of the target server.
- Replace
Create the encrypted secret file:
mkdir -p secrets
sops secrets/secrets.yamlThe content of the file should be the content of the file in /run/secrets we created earlier:
MY_SSID_PSK=theactualpassphrase
- Wire up SOPS in the
configuration.nix:
sops = {
defaultSopsFile = ./secrets/secrets.yaml;
age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
age.keyFile = "/home/ME/.config/sops/age/TARGET_HOSTNAME.txt";
secrets."MY_SSID_PSK" = {};
};Now, next time you will deploy, sops will use the secret file, send it over to the target machine
when deploying, decrypt the file and populate the content of /run/secrets/MY_SSID_PSK.