Merge pull request 'nixos-anywhere' (#4) from nixos-anywhere into master

Reviewed-on: #4
This commit is contained in:
Pim Kunis 2023-11-15 13:47:05 +01:00
commit 1beef05467
25 changed files with 329 additions and 193 deletions

1
.envrc Normal file
View file

@ -0,0 +1 @@
use_flake

View file

@ -1,19 +1,27 @@
# nixos-servers # nixos-servers
Nix definitions to configure our physical servers. Nix definitions to configure our physical servers.
Currently, only one physical server (named jefke) is implemented. Currently, only one physical server (named jefke) is implemented but more are planned!
## Prerequisites
1. Install the Nix package manager or NixOS ([link](https://nixos.org/download))
2. Enable flake and nix commands ([link](https://nixos.wiki/wiki/Flakes#Enable_flakes_permanently_in_NixOS))
3. Install Direnv ([link](https://direnv.net/))
4. Allow direnv for this repository: `direnv allow`
## Bootstrapping
We bootstrap our physical server using [nixos-anywhere](https://github.com/nix-community/nixos-anywhere).
This reformats the hard disk of the server and installs a fresh NixOS.
Additionally, it deploys an age identity, which is later used for decrypting secrets.
⚠️ This will wipe your server completely ⚠️
1. Make sure your have a [Secret service](https://www.gnu.org/software/emacs/manual/html_node/auth/Secret-Service-API.html) running (such as Keepassxc) that provides the age identity.
2. Ensure you have root SSH access to the server.
3. Run nixos-anywhere: `./bootstrap.sh <servername>`
## Deployment ## Deployment
### Prerequisites Deployment can simply be done as follows: `deploy`
Before a NixOS definition can be deployed, some prerequite preparational steps must be performed.
1. Manually install NixOS on the physical machine. This could potentially be automated in the future with [nixos-anywhere](https://github.com/nix-community/nixos-anywhere), but for now this is a manual process.
2. Enable SSH and install authorized keys.
3. Ensure Python3 is installed for Ansible.
4. Run Ansible playbook which deploys secrets `ansible-playbook deploy_secrets.yml`.
### NixOS deployment
Finally, the NixOS definition can be deployed as follows: `nix run github:serokell/deploy-rs`.

10
agenix.nix Normal file
View file

@ -0,0 +1,10 @@
{ machine, ... }: {
age = {
identityPaths = [ "/root/age_ed25519" ];
secrets = {
"host_ed25519".file = ./secrets/${machine.name}_host_ed25519.age;
"user_ed25519".file = ./secrets/${machine.name}_user_ed25519.age;
};
};
}

View file

@ -1 +0,0 @@
use flake

View file

@ -1,8 +0,0 @@
[defaults]
inventory=inventory
vault_password_file=$HOME/.config/home/ansible-vault-secret
host_key_checking = False
remote_user = root
[diff]
always = True

View file

@ -1,32 +0,0 @@
- name: Deploy secrets
hosts: jefke
tasks:
- name: Place user certificate
copy:
src: files/jefke_user_ed25519.crt
dest: /etc/ssh/ssh_user_ed25519_key-cert.pub
- name: Place user public key
copy:
src: files/jefke_user_ed25519.pub
dest: /etc/ssh/ssh_user_ed25519_key.pub
- name: Place user private key
copy:
src: files/jefke_user_ed25519
dest: /etc/ssh/ssh_user_ed25519_key
- name: Place host certificate
copy:
src: files/jefke_host_ed25519.crt
dest: /etc/ssh/ssh_host_ed25519_key-cert.pub
- name: Place host public key
copy:
src: files/jefke_host_ed25519.pub
dest: /etc/ssh/ssh_host_ed25519_key.pub
- name: Place host private key
copy:
src: files/jefke_host_ed25519
dest: /etc/ssh/ssh_host_ed25519_key

View file

@ -1,25 +0,0 @@
$ANSIBLE_VAULT;1.1;AES256
37613631656435623262663132613734663862346638313566623466663838333634663934663539
3035363062373461313937383365383233643861346562660a666235323134663361366635343037
35316364633964333963363866333364333834646636326632313261633863616661373763346539
3266346433356362620a663634356331306538386463616261626232396464663166316533613330
63633664626261333862623366666235383862386233313761616561623932666364636237346663
32616633616364356537336463643237383233356232363836376337343166336332386530653338
31643635303630386166393236616237343262653862323436636465613736393762623239646538
35666266656465656333666266326639326161323230326232363461383634356264336333663664
61656361666430356238666366363138343239316631313861636463376462613336613631633233
38343161356464353138376131333563633539323231646530636566386434613463623934646162
36323665353766313034623261336336393862366561343165613733396236326365656436373930
65633838333438356464353436343638616163363637313665333336313137623035346235323332
36383731663366356634653837306561613037633166653939336434623637353665326538303165
66636332363131313332663130663332393237643361363166663634633661626137346264303938
30383132376331633938353934393939373437343438613861653837613337373638336636653039
39336637373730333434636134633062623064653432633730366139666265373066346132373639
64353536646639366636656634633431316330656634383234343631626138393936663637653239
62393130366136396363633264623139323437643862343964383963663162636332386630363363
34636535376264323564383533306162316437306462326636313936316430326235633761356138
39666235646364353332613038623935343265346661633032303036653461396139383933316263
36316465383063643961353031633365613962383264663636623662363461626365356330663232
39393632366439623063326232373733333766353638393466396365663039666130383239366534
32326139306235306332376565366137373630303363346366306337306439643866393361333032
38626139633761613365

View file

@ -1 +0,0 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKTzrsjwRmKg3JbRLY/RrWnIBfCupfFdMWZ/8AQAXg9u root@jefke

View file

@ -1,25 +0,0 @@
$ANSIBLE_VAULT;1.1;AES256
61393933316139623835666133666433393235376532643538363733656439356465393062636265
3236373661386566326631636333346430316264616537320a386336376239613865363032666239
63616166363837393562643836333765393536363564636365616638333939323436383735616262
3331363766353038620a626662666331613734313564636564633238653762336364666237353635
36353837666366346565626162666466353661646630376261643133393966336236656234626139
38326164366565646539396139343538636234646330623965623430303535316131636261336133
61373763326566666565366432353535653430326466316130376337656431363038666334653332
63646439323635303432653536643464666266303533633330663137376432353563366133663661
31393430356235323535303562323662313936393132383162316238666162373232313736646630
34343131393963313839393330356539636532613936383932393537346134356337306336633434
32653961616161656136306234313335653336336230366237303336346631623735646564323962
31316165333264613433313761393936643433323762363161393730363161613839333038363032
63393038346365353362366639386334666134613961383033306566333361373630353539366635
32363732353262313436376462616437363337623933363964333763396233656438346638633432
66383338336237313266666161656633656264623532633764333565663331666665623031353265
31646233383238313734633234653666313734343263653936333636323463653636333535656565
30646133366265363938363561623335653239643637656339393236313535326366643238396562
30623631656530353362613536633935343131353961353735333561626463353632623465613063
37373661333339353030626437653863653736353939643966373834663262383035336337656335
34333836373535373164623436666465346564356539313032316130616439323161653134646364
32363938356235343736396431333639656366663130366439363062643137326162366563346266
30343834386135616663613964353262333462613465646362353437373362326363326136333131
66356466656162393038316361323335363261653036316533646563376262353039623939306663
35333430633836373064

View file

@ -1 +0,0 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINZ3aw6gjrOt561j1Mh7kINqlavorKeujN1Q8mn/Fy69 root@jefke

View file

@ -1,27 +0,0 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1698434055,
"narHash": "sha256-Phxi5mUKSoL7A0IYUiYtkI9e8NcGaaV5PJEaJApU1Ko=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "1a3c95e3b23b3cdb26750621c08cc2f1560cb883",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-23.05",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

View file

@ -1,26 +0,0 @@
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-23.05";
};
outputs = {
self,
nixpkgs,
...
}: let
supportedSystems = ["x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin"];
forEachSupportedSystem = f:
nixpkgs.lib.genAttrs supportedSystems (system:
f {
pkgs = import nixpkgs {inherit system;};
});
in {
devShells = forEachSupportedSystem ({pkgs}: {
default = pkgs.mkShell {
packages = with pkgs; [
ansible
];
};
});
};
}

View file

@ -1,5 +0,0 @@
all:
hosts:
jefke:
ansible_user: root
ansible_host: jefke.hyp

43
bootstrap.sh Executable file
View file

@ -0,0 +1,43 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
servername="${1-}"
if [ -z "$servername" ]
then
echo "Usage: $0 SERVERNAME"
exit 1
fi
confirmation="Yes, wipe ${servername}."
echo "⚠️ This will wipe ${servername} completely! ⚠️"
echo "Confirm by typing: \"${confirmation}\""
read response
if [ "$response" != "$confirmation" ]; then
echo "Aborting."
exit 1
fi
# Create a temporary directory
temp=$(mktemp -d)
# Function to cleanup temporary directory on exit
cleanup() {
rm -rf "$temp"
}
trap cleanup EXIT
# Create directory where age key will go.
# Nixos-anwhere creates a kind of overlay and retains this structure on the final file system.
mkdir "$temp/root"
secret-tool lookup age-identity "$servername" > "$temp/root/age_ed25519"
# Set the correct permissions
chmod 600 "$temp/root/age_ed25519"
# Install NixOS to the host system with our age identity
nix run github:numtide/nixos-anywhere -- --extra-files "$temp" --flake ".#${servername}" "root@${servername}.hyp"

View file

@ -1,5 +1,5 @@
{ pkgs, ... }: { { pkgs, config, machine, ... }: {
imports = [ ./hardware-configuration.nix ]; imports = [ ./hardware-configuration.nix ./disk-config.nix ./agenix.nix ];
boot.loader = { boot.loader = {
systemd-boot.enable = true; systemd-boot.enable = true;
@ -32,7 +32,10 @@
KbdInteractiveAuthentication = false; KbdInteractiveAuthentication = false;
}; };
extraConfig = '' extraConfig = ''
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub HostCertificate ${
builtins.toFile "host_ed25519-cert.pub" machine.host-cert
}
HostKey ${config.age.secrets.host_ed25519.path}
''; '';
}; };
@ -65,8 +68,10 @@
}; };
extraConfig = '' extraConfig = ''
CertificateFile /etc/ssh/ssh_user_ed25519_key-cert.pub CertificateFile ${
HostKey /etc/ssh/ssh_user_ed25519_key builtins.toFile "user_ed25519-cert.pub" machine.user-cert
}
HostKey ${config.age.secrets.user_ed25519.path}
''; '';
}; };

55
disk-config.nix Normal file
View file

@ -0,0 +1,55 @@
# Running system:
# NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
# nvme0n1 259:0 0 465,8G 0 disk
# ├─nvme0n1p1 259:1 0 512M 0 part /boot
# ├─nvme0n1p2 259:2 0 456,5G 0 part /nix/store
# │ /
# └─nvme0n1p3 259:3 0 8,8G 0 part [SWAP]
# Filesystem 1K-blocks Used Available Use% Mounted on
# devtmpfs 809892 0 809892 0% /dev
# tmpfs 8098920 0 8098920 0% /dev/shm
# tmpfs 4049460 3988 4045472 1% /run
# tmpfs 8098920 456 8098464 1% /run/wrappers
# /dev/nvme0n1p2 469995160 17597168 428450100 4% /
# /dev/nvme0n1p1 523248 119660 403588 23% /boot
# tmpfs 1619784 0 1619784 0% /run/user/0
# Disk name: nvme0n1
# disko template: simple-efi
# https://raw.githubusercontent.com/nix-community/disko/master/example/simple-efi.nix
{
disko.devices = {
disk = {
vdb = {
device = "/dev/nvme0n1";
type = "disk";
content = {
type = "gpt";
partitions = {
ESP = {
type = "EF00";
size = "500M";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
root = {
size = "100%";
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
};
};
};
};
};
};
}

View file

@ -1,5 +1,49 @@
{ {
"nodes": { "nodes": {
"agenix": {
"inputs": {
"darwin": "darwin",
"home-manager": "home-manager",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1696775529,
"narHash": "sha256-TYlE4B0ktPtlJJF9IFxTWrEeq+XKG8Ny0gc2FGEAdj0=",
"owner": "ryantm",
"repo": "agenix",
"rev": "daf42cb35b2dc614d1551e37f96406e4c4a2d3e4",
"type": "github"
},
"original": {
"owner": "ryantm",
"repo": "agenix",
"type": "github"
}
},
"darwin": {
"inputs": {
"nixpkgs": [
"agenix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1673295039,
"narHash": "sha256-AsdYgE8/GPwcelGgrntlijMg4t3hLFJFCRF3tL5WVjA=",
"owner": "lnl7",
"repo": "nix-darwin",
"rev": "87b9d090ad39b25b2400029c64825fc2a8868943",
"type": "github"
},
"original": {
"owner": "lnl7",
"ref": "master",
"repo": "nix-darwin",
"type": "github"
}
},
"deploy-rs": { "deploy-rs": {
"inputs": { "inputs": {
"flake-compat": "flake-compat", "flake-compat": "flake-compat",
@ -20,6 +64,26 @@
"type": "github" "type": "github"
} }
}, },
"disko": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1699781810,
"narHash": "sha256-LD+PIUbm1yQmQmGIbSsc/PB1dtJtGqXFgxRc1C7LlfQ=",
"owner": "nix-community",
"repo": "disko",
"rev": "2d7d77878c5d70f66f3d676ff66708d8d4f9d7df",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "disko",
"type": "github"
}
},
"flake-compat": { "flake-compat": {
"flake": false, "flake": false,
"locked": { "locked": {
@ -36,6 +100,27 @@
"type": "github" "type": "github"
} }
}, },
"home-manager": {
"inputs": {
"nixpkgs": [
"agenix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1682203081,
"narHash": "sha256-kRL4ejWDhi0zph/FpebFYhzqlOBrk0Pl3dzGEKSAlEw=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "32d3e39c491e2f91152c84f8ad8b003420eab0a1",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "home-manager",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1671417167, "lastModified": 1671417167,
@ -52,6 +137,22 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs-unstable": {
"locked": {
"lastModified": 1699725108,
"narHash": "sha256-NTiPW4jRC+9puakU4Vi8WpFEirhp92kTOSThuZke+FA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "911ad1e67f458b6bcf0278fa85e33bb9924fed7e",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1699291058, "lastModified": 1699291058,
@ -70,8 +171,11 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"agenix": "agenix",
"deploy-rs": "deploy-rs", "deploy-rs": "deploy-rs",
"nixpkgs": "nixpkgs_2" "disko": "disko",
"nixpkgs": "nixpkgs_2",
"nixpkgs-unstable": "nixpkgs-unstable"
} }
}, },
"utils": { "utils": {

View file

@ -3,31 +3,68 @@
inputs = { inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-23.05"; nixpkgs.url = "github:nixos/nixpkgs/nixos-23.05";
nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
deploy-rs.url = "github:serokell/deploy-rs"; deploy-rs.url = "github:serokell/deploy-rs";
disko = {
url = "github:nix-community/disko";
inputs.nixpkgs.follows = "nixpkgs";
};
agenix = {
url = "github:ryantm/agenix";
inputs.nixpkgs.follows = "nixpkgs";
};
}; };
outputs = { self, nixpkgs, deploy-rs, ... }: outputs = { self, nixpkgs, deploy-rs, disko, agenix, nixpkgs-unstable, ... }:
let system = "x86_64-linux"; let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
pkgs-unstable = nixpkgs-unstable.legacyPackages.${system};
machines = import ./machines;
mkNixosSystems = systemDef:
nixpkgs.lib.foldlAttrs (acc: name: machine:
acc // {
"${name}" = nixpkgs.lib.nixosSystem (systemDef machine);
}) { } machines;
mkDeployNodes = nodeDef:
nixpkgs.lib.foldlAttrs
(acc: name: machine: acc // { "${name}" = nodeDef machine; }) { }
machines;
in { in {
devShells.${system}.default = pkgs.mkShell {
formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.nixfmt; packages = [
pkgs.libsecret
nixosConfigurations.hypervisor = nixpkgs.lib.nixosSystem { # TODO: using nixos-anywhere from nixos-unstable produces buffer overflow.
inherit system; # Related to this issue: https://github.com/nix-community/nixos-anywhere/issues/242
modules = [ ./configuration.nix ]; # Should wait until this is merged in nixos-unstable.
# pkgs-unstable.nixos-anywhere
pkgs-unstable.deploy-rs
];
}; };
formatter.${system} = pkgs.nixfmt;
nixosConfigurations = mkNixosSystems (machine: {
inherit system;
specialArgs = { inherit machine; };
modules = [
disko.nixosModules.disko
agenix.nixosModules.default
./configuration.nix
];
});
deploy = { deploy = {
sshUser = "root"; sshUser = "root";
user = "root"; user = "root";
nodes.jefke = { nodes = mkDeployNodes (machine: {
hostname = "jefke.hyp"; hostname = machine.hostname;
profiles.hypervisor = { profiles.hypervisor = {
path = deploy-rs.lib.x86_64-linux.activate.nixos path = deploy-rs.lib.${system}.activate.nixos
self.nixosConfigurations.hypervisor; self.nixosConfigurations.${machine.name};
}; };
}; });
}; };
checks = builtins.mapAttrs checks = builtins.mapAttrs

View file

@ -7,18 +7,18 @@
boot.kernelModules = [ "kvm-intel" ]; boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ]; boot.extraModulePackages = [ ];
fileSystems."/" = { # fileSystems."/" = {
device = "/dev/disk/by-uuid/b78f591c-c9b6-4dae-9837-56716d38990b"; # device = "/dev/disk/by-uuid/b78f591c-c9b6-4dae-9837-56716d38990b";
fsType = "ext4"; # fsType = "ext4";
}; # };
fileSystems."/boot" = { # fileSystems."/boot" = {
device = "/dev/disk/by-uuid/6936-84C2"; # device = "/dev/disk/by-uuid/6936-84C2";
fsType = "vfat"; # fsType = "vfat";
}; # };
swapDevices = # swapDevices =
[{ device = "/dev/disk/by-uuid/79fbd322-e58d-4e45-8969-06ef494cefea"; }]; # [{ device = "/dev/disk/by-uuid/79fbd322-e58d-4e45-8969-06ef494cefea"; }];
networking.useDHCP = false; networking.useDHCP = false;

8
machines/default.nix Normal file
View file

@ -0,0 +1,8 @@
{
jefke = {
name = "jefke";
hostname = "jefke.hyp";
user-cert = builtins.readFile ./jefke_user_ed25519-cert.pub;
host-cert = builtins.readFile ./jefke_host_ed25519-cert.pub;
};
}

Binary file not shown.

Binary file not shown.

16
secrets/secrets.nix Normal file
View file

@ -0,0 +1,16 @@
let
pkgs = import <nixpkgs> { };
lib = pkgs.lib;
secrets = {
jefke = {
publicKeys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIJUSH2IQg8Y/CCcej7J6oe4co++6HlDo1MYDCR3gV3a pim@x260"
];
encryptedFiles = [ "jefke_host_ed25519.age" "jefke_user_ed25519.age" ];
};
};
in lib.attrsets.mergeAttrsList (builtins.map ({ publicKeys, encryptedFiles }:
lib.attrsets.mergeAttrsList (builtins.map
(encryptedFile: { "${encryptedFile}" = { inherit publicKeys; }; })
encryptedFiles)) (lib.attrsets.attrValues secrets))