This commit is contained in:
Casper V. Kristensen 2024-02-24 02:11:59 +01:00
parent d16c7baa4a
commit 9241fe5e5c
8 changed files with 142 additions and 30 deletions

View file

@ -21,7 +21,7 @@ the unofficial NixOS wiki [Full Disk Encryption](https://nixos.wiki/wiki/Full_Di
gist](https://gist.github.com/martijnvermaat/76f2e24d0239470dd71050358b4d5134). gist](https://gist.github.com/martijnvermaat/76f2e24d0239470dd71050358b4d5134).
We create a 1GiB EFI boot partition (`/dev/sda1`) and the rest will be our LUKS-encrypted volume: We create a 1GiB EFI boot partition (`/dev/sda1`) and the rest will be our LUKS-encrypted volume:
```bash ```fish
# Create partition table # Create partition table
parted /dev/sda -- mklabel gpt parted /dev/sda -- mklabel gpt
@ -58,19 +58,35 @@ sda
└─vg-root ext4 1.0 nix └─vg-root ext4 1.0 nix
``` ```
### Installation
Whereas the [NixOS manual](https://nixos.org/manual/nixos/stable/index.html#sec-installation-manual-installing) mounts Whereas the [NixOS manual](https://nixos.org/manual/nixos/stable/index.html#sec-installation-manual-installing) mounts
the newly-created `nixos` partition to `/mnt`, we will follow the _tmpfs as root_ blogpost and mount `/mnt` as `tmpfs`: the newly-created `nixos` partition to `/mnt`, we will follow the _tmpfs as root_ blogpost and mount `/mnt` as `tmpfs`:
```bash ```fish
mount -t tmpfs none /mnt mount -t tmpfs none /mnt
mount --mkdir /dev/disk/by-label/BOOT /mnt/boot mount --mkdir /dev/disk/by-label/BOOT /mnt/boot
mount --mkdir /dev/disk/by-label/nix /mnt/nix mount --mkdir /dev/disk/by-label/nix /mnt/nix
mkdir -p /mnt/nix/persist/ mkdir -p /mnt/nix/persist/
``` ```
### Secrets
All files in the Nix store are world-readable, so it is not a suitable place for including cleartext secrets,
even if we had a scheme to securely transfer them to each system. [Agenix](https://github.com/ryantm/agenix)
solves this issue by encrypting the secrets using [age](https://github.com/FiloSottile/age), and then decrypting
and symlinking them using the system's SSH host key during system activation.
To bootstrap a new system, we must first generate a host key manually using `ssh-keygen -A -f /mnt/nix/persist`
during installation. Then, on an existing system, add the new host's public key to `secrets.nix` and rekey all
secrets using `agenix --rekey`. Commit and push the changes and proceed below.
When managing secrets, the Keepass recovery key is used like so:
```fish
set AGE_KEY_FILE (mktemp); read -s > $AGE_KEY_FILE
agenix -i $AGE_KEY_FILE -e foo.age
```
### Installation
The remaining installation can be done (more or less) according to the [NixOS The remaining installation can be done (more or less) according to the [NixOS
manual](https://nixos.org/manual/nixos/stable/index.html#sec-installation-manual-installing). manual](https://nixos.org/manual/nixos/stable/index.html#sec-installation-manual-installing).
```bash ```fish
cd /mnt/nix cd /mnt/nix
git clone https://git.caspervk.net/caspervk/nixos.git tmp git clone https://git.caspervk.net/caspervk/nixos.git tmp
cd tmp/ cd tmp/
@ -78,10 +94,6 @@ nixos-generate-config --root /mnt --show-hardware-config
vim hosts/omega/hardware.nix vim hosts/omega/hardware.nix
git add . # nix sometimes ignores files outside version control git add . # nix sometimes ignores files outside version control
nixos-install --no-root-passwd --flake .#omega nixos-install --no-root-passwd --flake .#omega
# Make sure to set a password
mkpasswd > /mnt/nix/persist/passwordfile
chmod 400 /mnt/nix/persist/passwordfile
``` ```
### Hardware Configuration ### Hardware Configuration
@ -94,7 +106,7 @@ enough](https://sourcegraph.com/search?q=context%3Aglobal+repo%3A%5Egithub%5C.co
## Useful Commands ## Useful Commands
```bash ```fish
# upgrade system # upgrade system
sudo nixos-rebuild switch --flake . sudo nixos-rebuild switch --flake .

View file

@ -1,5 +1,30 @@
{ {
"nodes": { "nodes": {
"agenix": {
"inputs": {
"darwin": [],
"home-manager": [
"home-manager"
],
"nixpkgs": [
"nixpkgs"
],
"systems": "systems"
},
"locked": {
"lastModified": 1707830867,
"narHash": "sha256-PAdwm5QqdlwIqGrfzzvzZubM+FXtilekQ/FA0cI49/o=",
"owner": "ryantm",
"repo": "agenix",
"rev": "8cb01a0e717311680e0cbca06a76cbceba6f3ed6",
"type": "github"
},
"original": {
"owner": "ryantm",
"repo": "agenix",
"type": "github"
}
},
"home-manager": { "home-manager": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@ -28,11 +53,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1708451036, "lastModified": 1708591310,
"narHash": "sha256-tgZ38NummEdnXvxj4D0StHBzXgceAw8CptytHljH790=", "narHash": "sha256-8mQGVs8JccWTnORgoLOTh9zvf6Np+x2JzhIc+LDcJ9s=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "517601b37c6d495274454f63c5a483c8e3ca6be1", "rev": "0e0e9669547e45ea6cca2de4044c1a384fd0fe55",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -79,11 +104,11 @@
}, },
"nixos-hardware": { "nixos-hardware": {
"locked": { "locked": {
"lastModified": 1708091350, "lastModified": 1708594753,
"narHash": "sha256-o28BJYi68qqvHipT7V2jkWxDiMS1LF9nxUsou+eFUPQ=", "narHash": "sha256-c/gH7iXS/IYH9NrFOT+aJqTq+iEBkvAkpWuUHGU3+f0=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixos-hardware", "repo": "nixos-hardware",
"rev": "106d3fec43bcea19cb2e061ca02531d54b542ce3", "rev": "3f7d0bca003eac1a1a7f4659bbab9c8f8c2a0958",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -95,11 +120,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1708294118, "lastModified": 1708566995,
"narHash": "sha256-evZzmLW7qoHXf76VCepvun1esZDxHfVRFUJtumD7L2M=", "narHash": "sha256-e/THimsoxxMAHSbwMKov5f5Yg+utTj6XVGEo24Lhx+0=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "e0da498ad77ac8909a980f07eff060862417ccf7", "rev": "3cb4ae6689d2aa3f363516234572613b31212b78",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -111,11 +136,11 @@
}, },
"nixpkgs-unstable": { "nixpkgs-unstable": {
"locked": { "locked": {
"lastModified": 1708296515, "lastModified": 1708655239,
"narHash": "sha256-FyF489fYNAUy7b6dkYV6rGPyzp+4tThhr80KNAaF/yY=", "narHash": "sha256-ZrP/yACUvDB+zbqYJsln4iwotbH6CTZiTkANJ0AgDv4=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "b98a4e1746acceb92c509bc496ef3d0e5ad8d4aa", "rev": "cbc4211f0afffe6dfd2478a62615dd5175a13f9a",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -127,6 +152,7 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"agenix": "agenix",
"home-manager": "home-manager", "home-manager": "home-manager",
"home-manager-unstable": "home-manager-unstable", "home-manager-unstable": "home-manager-unstable",
"impermanence": "impermanence", "impermanence": "impermanence",
@ -135,6 +161,21 @@
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"nixpkgs-unstable": "nixpkgs-unstable" "nixpkgs-unstable": "nixpkgs-unstable"
} }
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
} }
}, },
"root": "root", "root": "root",

View file

@ -18,6 +18,12 @@
impermanence = { impermanence = {
url = "github:nix-community/impermanence"; url = "github:nix-community/impermanence";
}; };
agenix = {
url = "github:ryantm/agenix";
inputs.nixpkgs.follows = "nixpkgs"; # use the same nixpkgs as the system
inputs.home-manager.follows = "home-manager"; # use the same home-manager as the system
inputs.darwin.follows = ""; # don't download dawrin dependencies
};
nix-index-database = { nix-index-database = {
url = "github:nix-community/nix-index-database"; url = "github:nix-community/nix-index-database";
inputs.nixpkgs.follows = "nixpkgs"; # use the same nixpkgs as the system inputs.nixpkgs.follows = "nixpkgs"; # use the same nixpkgs as the system

21
modules/base/agenix.nix Normal file
View file

@ -0,0 +1,21 @@
{ agenix, pkgs, ... }: {
# Agenix manages the deployment of secrets by public-key encrypting them to
# each system's ssh host key. See the README for more information.
# https://github.com/ryantm/agenix
# https://nixos.wiki/wiki/Comparison_of_secret_managing_schemes
imports = [
agenix.nixosModules.default
];
# Agenix attempts to decrypt secrets before impermanence symlinks the ssh
# host key. Refer directly to the key on the persistent partition, which is
# mounted in stage 1 of the boot process, before agenix runs.
# https://github.com/ryantm/agenix/issues/45#issuecomment-901383985
age.identityPaths = [ "/nix/persist/etc/ssh/ssh_host_ed25519_key" ];
# `agenix` cli tool
environment.systemPackages = [
agenix.packages.${pkgs.system}.default
];
}

View file

@ -1,5 +1,6 @@
{ ... }: { { ... }: {
imports = [ imports = [
./agenix.nix
./docker.nix ./docker.nix
./fish.nix ./fish.nix
./git.nix ./git.nix

View file

@ -1,22 +1,16 @@
{ pkgs, ... }: { { config, pkgs, ... }: {
users = { users = {
# Don't allow imperative modifications to users (incompatible with impermanence) # Don't allow imperative modifications to users (incompatible with impermanence)
mutableUsers = false; mutableUsers = false;
users = { users = {
root = { root = {
# TODO: The passwordfile is manually generated during the initial setup hashedPasswordFile = config.age.secrets.users-hashed-password-file.path;
# to avoid (hashed) secrets in the public git repo. It should replaced
# with a proper secret management scheme, such as agenix.
hashedPasswordFile = "/nix/persist/passwordfile";
}; };
caspervk = { caspervk = {
isNormalUser = true; isNormalUser = true;
description = "Casper V. Kristensen"; description = "Casper V. Kristensen";
# TODO: The hashedPasswordFile is manually generated during the initial hashedPasswordFile = config.age.secrets.users-hashed-password-file.path;
# setup to avoid (hashed) secrets in the public git repo. It should
# replaced with a proper secret management scheme, such as agenix.
hashedPasswordFile = "/nix/persist/passwordfile";
extraGroups = [ extraGroups = [
"wheel" # allows sudo "wheel" # allows sudo
"video" # allows controlling brightness "video" # allows controlling brightness
@ -27,4 +21,11 @@
}; };
}; };
}; };
age.secrets.users-hashed-password-file = {
file = ../../secrets/users-hashed-password-file.age;
mode = "400";
owner = "root";
group = "root";
};
} }

23
secrets/secrets.nix Normal file
View file

@ -0,0 +1,23 @@
# This file is NOT imported into the NixOS configuration. It is only used for
# the agenix CLI tool to know which public keys to use for encryption. See the
# README for more information.
# https://github.com/ryantm/agenix
let
# Get a system's public key using:
# > cat /etc/ssh/ssh_host_ed25519_key.pub
# If you change or add a key, all secrets need to be `agenix --rekey`'ed.
mu = "todo";
omega = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILvFN4vnqPX31+4/ZJxOJ7/bSUEu2xB6ovezPQjLm13H root@omega";
tor = "todo";
zeta = "todo";
# Recovery and management key from Keepass. Used like so:
# > set AGE_KEY_FILE (mktemp); read -s > $AGE_KEY_FILE
# > agenix -i $AGE_KEY_FILE -e foo.age
recovery = "age1rd6hhd724s3r9xe4gfuy38rl0xfu8c7pkuefsrdwqfcknujzecyqz7ldyj";
all = [ omega recovery ];
in
{
"users-hashed-password-file.age".publicKeys = all;
}

View file

@ -0,0 +1,7 @@
age-encryption.org/v1
-> ssh-ed25519 fY+XUg ThWnidSUv20sqdMebPW0aV512ascEV4WyDia72vhTnI
fbFAnyqqqpp9fEct2EiLG1wWw//U8kWcpf0QnbSh33Y
-> X25519 ZbC+v0St7P+W/AHq1Afst7ylmZUFA7OIhiElfexTHgg
2DbCqyjULhmDji3E1HrPuO8WW74dIia1GFOSCaeGliU
--- 6W7LaM4dc6tJONcmtVAwhI/NcOE8EUYPrg75K6Qpynw
%4k=/ýä_ƒ<5F>½a#]Éào>Ÿ¬¨tVÆ°EªW“õµŽåRþ÷~¾8­Ñ;më¬"˜&˹ÏGŠ]ïsAN¦pÀŸõW²ƒŽÅNKø„Ɖ˜™p¿ƒªóP$8e