From 80bf651812699b4aefd4327b3a8a3cd5664042b1 Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 16 Jul 2024 23:08:58 +0200 Subject: [PATCH 01/15] checks: add snakeoil ssh key --- packages/checks/snakeoil/ssh/snakeoil-key | 7 +++++++ packages/checks/snakeoil/ssh/snakeoil-key.pub | 1 + 2 files changed, 8 insertions(+) create mode 100644 packages/checks/snakeoil/ssh/snakeoil-key create mode 100644 packages/checks/snakeoil/ssh/snakeoil-key.pub diff --git a/packages/checks/snakeoil/ssh/snakeoil-key b/packages/checks/snakeoil/ssh/snakeoil-key new file mode 100644 index 0000000..6faabb2 --- /dev/null +++ b/packages/checks/snakeoil/ssh/snakeoil-key @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACAOx03X+LtW0aN8ejdN4IJgDPrTZgVwe7WbXhhBvqVwgwAAAJAS78fWEu/H +1gAAAAtzc2gtZWQyNTUxOQAAACAOx03X+LtW0aN8ejdN4IJgDPrTZgVwe7WbXhhBvqVwgw +AAAEAUtGOZZIZdzGP6g85JuXBjDtciNQ9bLHNxSN5Gbwvb2Q7HTdf4u1bRo3x6N03ggmAM ++tNmBXB7tZteGEG+pXCDAAAACW1heEBUSVRBTgECAwQ= +-----END OPENSSH PRIVATE KEY----- diff --git a/packages/checks/snakeoil/ssh/snakeoil-key.pub b/packages/checks/snakeoil/ssh/snakeoil-key.pub new file mode 100644 index 0000000..66d752d --- /dev/null +++ b/packages/checks/snakeoil/ssh/snakeoil-key.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA7HTdf4u1bRo3x6N03ggmAM+tNmBXB7tZteGEG+pXCD -- 2.47.0 From 55866c153d1fb64ba4946a3533eed387c0bdd9de Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 17 Jul 2024 19:34:28 +0200 Subject: [PATCH 02/15] checks: add fake external storage module --- packages/checks/modules/nixos/external-storage.nix | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 packages/checks/modules/nixos/external-storage.nix diff --git a/packages/checks/modules/nixos/external-storage.nix b/packages/checks/modules/nixos/external-storage.nix new file mode 100644 index 0000000..d89f9df --- /dev/null +++ b/packages/checks/modules/nixos/external-storage.nix @@ -0,0 +1,12 @@ +{ config, lib, ... }: + +{ + systemd.tmpfiles.settings."00-testing-external-storage-underlays" = lib.mapAttrs' (name: cfg: { + name = cfg.mountpoint; + value.d = { + user = toString cfg.uid; + group = toString cfg.gid; + mode = "0700"; + }; + }) config.services.external-storage.underlays; +} -- 2.47.0 From 532a569c6673496f47a3cab3ce28d3305d155aa9 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 20 Jul 2024 22:15:48 +0200 Subject: [PATCH 03/15] cluster/lib: implement injectNixosConfigForServices to select individual services --- cluster/lib/inject-nixos-config.nix | 6 +++--- cluster/lib/services.nix | 10 +++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/cluster/lib/inject-nixos-config.nix b/cluster/lib/inject-nixos-config.nix index 6e5add1..4523b96 100644 --- a/cluster/lib/inject-nixos-config.nix +++ b/cluster/lib/inject-nixos-config.nix @@ -2,9 +2,9 @@ with lib; { - options.out.injectNixosConfig = mkOption { - description = "NixOS configuration to inject into the given host."; - type = with types; functionTo raw; + options.out = mkOption { + description = "Output functions."; + type = with types; lazyAttrsOf (functionTo raw); default = const []; }; } diff --git a/cluster/lib/services.nix b/cluster/lib/services.nix index b500f1b..4e9f8bc 100644 --- a/cluster/lib/services.nix +++ b/cluster/lib/services.nix @@ -39,7 +39,11 @@ in default = {}; }; - config.out.injectNixosConfig = hostName: (lib.flatten (lib.mapAttrsToList (getHostConfigurations hostName) config.services)) ++ [ - introspectionModule - ]; + config.out = { + injectNixosConfigForServices = services: hostName: (lib.flatten (lib.mapAttrsToList (getHostConfigurations hostName) (lib.getAttrs services config.services))) ++ [ + introspectionModule + ]; + + injectNixosConfig = config.out.injectNixosConfigForServices (lib.attrNames config.services); + }; } -- 2.47.0 From b28898c3ae3330125a3b2df470f9384b82e0a961 Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 22 Jul 2024 00:58:50 +0200 Subject: [PATCH 04/15] cluster/lib: implement simulacrum options --- cluster/default.nix | 1 + cluster/lib/service-module.nix | 18 ++++++++++++++++++ cluster/lib/testing.nix | 9 +++++++++ 3 files changed, 28 insertions(+) create mode 100644 cluster/lib/testing.nix diff --git a/cluster/default.nix b/cluster/default.nix index 97ab73c..548c3af 100644 --- a/cluster/default.nix +++ b/cluster/default.nix @@ -16,6 +16,7 @@ lib.evalModules { ./lib/port-magic-multi.nix ./lib/mesh.nix ./lib/secrets.nix + ./lib/testing.nix ./import-services.nix ]; diff --git a/cluster/lib/service-module.nix b/cluster/lib/service-module.nix index 3ef8c98..2fb07e7 100644 --- a/cluster/lib/service-module.nix +++ b/cluster/lib/service-module.nix @@ -52,6 +52,24 @@ in })); default = {}; }; + simulacrum = { + enable = mkEnableOption "testing this service in the Simulacrum"; + deps = mkOption { + description = "Other services to include."; + type = with types; listOf str; + default = []; + }; + settings = mkOption { + description = "NixOS test configuration."; + type = types.deferredModule; + default = {}; + }; + augments = mkOption { + description = "Cluster augments (will be propagated)."; + type = types.deferredModule; + default = {}; + }; + }; }; config.otherNodes = builtins.mapAttrs (const filterGroup) config.nodes; } diff --git a/cluster/lib/testing.nix b/cluster/lib/testing.nix new file mode 100644 index 0000000..6c96b37 --- /dev/null +++ b/cluster/lib/testing.nix @@ -0,0 +1,9 @@ +{ lib, ... }: + +{ + options.simulacrum = lib.mkOption { + description = "Whether we are in the Simulacrum."; + type = lib.types.bool; + default = false; + }; +} -- 2.47.0 From da9b933bb8c90859b7ea5bc02cefd98cec008a06 Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 23 Jul 2024 02:44:12 +0200 Subject: [PATCH 05/15] cluster/simulacrum: init --- cluster/simulacrum/default.nix | 111 +++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 cluster/simulacrum/default.nix diff --git a/cluster/simulacrum/default.nix b/cluster/simulacrum/default.nix new file mode 100644 index 0000000..a889189 --- /dev/null +++ b/cluster/simulacrum/default.nix @@ -0,0 +1,111 @@ +{ testers, config, extendModules, lib, system }: + +{ service }: + +let + serviceConfig = config.cluster.config.services.${service}; + serviceList = [ service ] ++ serviceConfig.simulacrum.deps; + allAugments = map (svc: config.cluster.config.services.${svc}.simulacrum.augments) serviceList; + + lift = config; + + snakeoil = { + ssh = { + public = lib.fileContents ../../packages/checks/snakeoil/ssh/snakeoil-key.pub; + private = ../../packages/checks/snakeoil/ssh/snakeoil-key; + }; + }; + + nodes = lib.attrNames config.gods.fromLight; + digits = lib.attrsets.listToAttrs (lib.zipListsWith lib.nameValuePair nodes (lib.range 1 255)); + depot' = extendModules { + modules = [ + ({ config, ... }: { + gods.fromLight = lib.mapAttrs (name: cfg: { + interfaces.primary = { + link = lib.mkForce "vprimary"; + }; + ssh.id.publicKey = lib.mkForce snakeoil.ssh.public; + }) lift.gods.fromLight; + + cluster = lib.mkForce (lift.cluster.extendModules { + specialArgs.depot = config; + modules = [ + { simulacrum = true; } + ]; + }); + }) + ]; + }; + specialArgs = depot'.config.lib.summon system lib.id; +in + +testers.runNixOSTest { + name = "simulacrum-${service}"; + + imports = [ + serviceConfig.simulacrum.settings + ] ++ allAugments; + + _module.args = { + inherit (depot'.config) cluster; + }; + + node = { inherit specialArgs; }; + nodes = lib.genAttrs nodes (node: let + hour = depot'.config.hours.${node}; + in { + imports = [ + specialArgs.depot.hours.${node}.nixos + ../../packages/checks/modules/nixos/age-dummy-secrets + ../../packages/checks/modules/nixos/external-storage.nix + ] ++ depot'.config.cluster.config.out.injectNixosConfigForServices serviceList node; + + boot.kernel.sysctl."net.ipv4.ip_forward" = "1"; + networking = { + interfaces = { + ${hour.interfaces.primary.link} = { + useDHCP = lib.mkForce false; + virtual = true; + ipv4.addresses = lib.mkForce [ + { + address = hour.interfaces.primary.addr; + prefixLength = 32; + } + ]; + }; + eth1.ipv4.routes = lib.pipe nodes [ + (lib.filter (n: n != node)) + (map (n: let + hour = depot'.config.hours.${n}; + in { + address = hour.interfaces.primary.addrPublic; + prefixLength = 32; + via = "192.168.1.${toString digits.${n}}"; + })) + ]; + }; + + firewall.extraCommands = lib.mkAfter (lib.optionalString (hour.interfaces.primary.isNat) '' + # self-nat + iptables -t nat -A PREROUTING -d ${hour.interfaces.primary.addrPublic} -j DNAT --to-destination ${hour.interfaces.primary.addr} + iptables -t nat -A POSTROUTING -s ${hour.interfaces.primary.addr} -j SNAT --to-source ${hour.interfaces.primary.addrPublic} + ''); + }; + + systemd.services = { + hyprspace.enable = false; + }; + + environment.etc = { + "ssh/ssh_host_ed25519_key" = { + source = snakeoil.ssh.private; + mode = "0400"; + }; + }; + virtualisation = { + cores = 2; + memorySize = 4096; + }; + }); +} -- 2.47.0 From 40fd5c4be9d273fa77e310ad2a1d7e1165fadd41 Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 23 Jul 2024 02:46:34 +0200 Subject: [PATCH 06/15] cluster/services/wireguard: make simulacrum compatible --- cluster/services/wireguard/default.nix | 31 ++++++++++++++----- .../simulacrum/keys/snakeoilPrivateKey-VEGAS | 1 + .../keys/snakeoilPrivateKey-checkmate | 1 + .../simulacrum/keys/snakeoilPrivateKey-grail | 1 + .../keys/snakeoilPrivateKey-prophet | 1 + .../keys/snakeoilPrivateKey-thunderskin | 1 + .../wireguard/simulacrum/snakeoil-keys.nix | 6 ++++ 7 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-VEGAS create mode 100644 cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-checkmate create mode 100644 cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-grail create mode 100644 cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-prophet create mode 100644 cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-thunderskin create mode 100644 cluster/services/wireguard/simulacrum/snakeoil-keys.nix diff --git a/cluster/services/wireguard/default.nix b/cluster/services/wireguard/default.nix index a1f25eb..54b893a 100644 --- a/cluster/services/wireguard/default.nix +++ b/cluster/services/wireguard/default.nix @@ -10,6 +10,19 @@ let }; getExtAddr = host: host.interfaces.primary.addrPublic; + + snakeoilPublicKeys = { + checkmate = "TESTtbFybW5YREwtd18a1A4StS4YAIUS5/M1Lv0jHjA="; + grail = "TEsTh7bthkaDh9A1CpqDi/F121ao5lRZqIJznLH8mB4="; + thunderskin = "tEST6afFmVN18o+EiWNFx+ax3MJwdQIeNfJSGEpffXw="; + VEGAS = "tEsT6s7VtM5C20eJBaq6UlQydAha8ATlmrTRe9T5jnM="; + prophet = "TEstYyb5IoqSL53HbSQwMhTaR16sxcWcMmXIBPd+1gE="; + }; + + grease = hourName: realPublicKey: if config.simulacrum then + snakeoilPublicKeys.${hourName} + else + realPublicKey; in { vars = { @@ -22,7 +35,7 @@ in extra = { meshIp = "10.1.1.32"; inherit meshNet; - pubKey = "fZMB9CDCWyBxPnsugo3Uxm/TIDP3VX54uFoaoC0bP3U="; + pubKey = grease "checkmate" "fZMB9CDCWyBxPnsugo3Uxm/TIDP3VX54uFoaoC0bP3U="; extraRoutes = []; }; }; @@ -31,7 +44,7 @@ in extra = { meshIp = "10.1.1.6"; inherit meshNet; - pubKey = "0WAiQGdWySsGWFUk+a9e0I+BDTKwTyWQdFT2d7BMfDQ="; + pubKey = grease "grail" "0WAiQGdWySsGWFUk+a9e0I+BDTKwTyWQdFT2d7BMfDQ="; extraRoutes = []; }; }; @@ -40,7 +53,7 @@ in extra = { meshIp = "10.1.1.4"; inherit meshNet; - pubKey = "xvSsFvCVK8h2wThZJ7E5K0fniTBIEIYOblkKIf3Cwy0="; + pubKey = grease "thunderskin" "xvSsFvCVK8h2wThZJ7E5K0fniTBIEIYOblkKIf3Cwy0="; extraRoutes = []; }; }; @@ -49,7 +62,7 @@ in extra = { meshIp = "10.1.1.5"; inherit meshNet; - pubKey = "NpeB8O4erGTas1pz6Pt7qtY9k45YV6tcZmvvA4qXoFk="; + pubKey = grease "VEGAS" "NpeB8O4erGTas1pz6Pt7qtY9k45YV6tcZmvvA4qXoFk="; extraRoutes = [ "${hours.VEGAS.interfaces.vstub.addr}/32" "10.10.0.0/16" ]; }; }; @@ -58,7 +71,7 @@ in extra = { meshIp = "10.1.1.9"; inherit meshNet; - pubKey = "MMZAbRtNE+gsLm6DJy9VN/Y39E69oAZnvOcFZPUAVDc="; + pubKey = grease "prophet" "MMZAbRtNE+gsLm6DJy9VN/Y39E69oAZnvOcFZPUAVDc="; extraRoutes = []; }; }; @@ -69,8 +82,12 @@ in storm = [ "VEGAS" ]; }; nixos = { - mesh = ./mesh.nix; - storm = ./storm.nix; + mesh = [ + ./mesh.nix + ] ++ lib.optionals config.simulacrum [ + ./simulacrum/snakeoil-keys.nix + ]; + storm = [ ./storm.nix ]; }; secrets.meshPrivateKey = { nodes = config.services.wireguard.nodes.mesh; diff --git a/cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-VEGAS b/cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-VEGAS new file mode 100644 index 0000000..e15616d --- /dev/null +++ b/cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-VEGAS @@ -0,0 +1 @@ +MNvWpMluuzQvPyGTp7jtyPSyz6n9lIly/WX1gW2NAHg= diff --git a/cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-checkmate b/cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-checkmate new file mode 100644 index 0000000..f498b5b --- /dev/null +++ b/cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-checkmate @@ -0,0 +1 @@ +YHzP8rBP6qiXs6ZdnvHop9KnCYRADIEejwZzAzvj8m4= diff --git a/cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-grail b/cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-grail new file mode 100644 index 0000000..7496093 --- /dev/null +++ b/cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-grail @@ -0,0 +1 @@ +uD7X5E6N9d0sN+xPr/bWnehSa3bAok741GO7Z4I+Z3I= diff --git a/cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-prophet b/cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-prophet new file mode 100644 index 0000000..d46aa5e --- /dev/null +++ b/cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-prophet @@ -0,0 +1 @@ +QHyIJ3HoKGGFN28qOrQP4UyoQMP5bM7Idn2MzayKzEM= diff --git a/cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-thunderskin b/cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-thunderskin new file mode 100644 index 0000000..6088510 --- /dev/null +++ b/cluster/services/wireguard/simulacrum/keys/snakeoilPrivateKey-thunderskin @@ -0,0 +1 @@ +YLl+hkWaCWx/5PpWs3cQ+bKqYdJef/qZ+FMTsM9ammM= diff --git a/cluster/services/wireguard/simulacrum/snakeoil-keys.nix b/cluster/services/wireguard/simulacrum/snakeoil-keys.nix new file mode 100644 index 0000000..d3dd500 --- /dev/null +++ b/cluster/services/wireguard/simulacrum/snakeoil-keys.nix @@ -0,0 +1,6 @@ +{ lib, config, ... }: { + config.environment.etc = { + "dummy-secrets/cluster-wireguard-meshPrivateKey".source = lib.mkForce ./keys/snakeoilPrivateKey-${config.networking.hostName}; + "dummy-secrets/wireguard-key-storm".source = lib.mkForce ./keys/snakeoilPrivateKey-${config.networking.hostName}; + }; +} -- 2.47.0 From fa0d6f046b11397bf7c80a2798e1225d12189397 Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 23 Jul 2024 19:02:11 +0200 Subject: [PATCH 07/15] cluster/lib: introduce testConfig --- cluster/lib/testing.nix | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/cluster/lib/testing.nix b/cluster/lib/testing.nix index 6c96b37..90c9106 100644 --- a/cluster/lib/testing.nix +++ b/cluster/lib/testing.nix @@ -1,9 +1,15 @@ { lib, ... }: { - options.simulacrum = lib.mkOption { - description = "Whether we are in the Simulacrum."; - type = lib.types.bool; - default = false; + options = { + simulacrum = lib.mkOption { + description = "Whether we are in the Simulacrum."; + type = lib.types.bool; + default = false; + }; + testConfig = lib.mkOption { + type = lib.types.attrs; + readOnly = true; + }; }; } -- 2.47.0 From f140de7a1a1c06a7b9f49166ea19b507d5c303f1 Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 23 Jul 2024 19:02:31 +0200 Subject: [PATCH 08/15] cluster/simulacrum: set testConfig --- cluster/simulacrum/default.nix | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cluster/simulacrum/default.nix b/cluster/simulacrum/default.nix index a889189..a900de7 100644 --- a/cluster/simulacrum/default.nix +++ b/cluster/simulacrum/default.nix @@ -31,7 +31,13 @@ let cluster = lib.mkForce (lift.cluster.extendModules { specialArgs.depot = config; modules = [ - { simulacrum = true; } + { + simulacrum = true; + testConfig = { + subject = service; + activeServices = serviceList; + }; + } ]; }); }) -- 2.47.0 From 62fbeb02c0bbc95a16219d28ac0b2ef8a30f053a Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 23 Jul 2024 19:03:19 +0200 Subject: [PATCH 09/15] cluster/lib: implement config.lib.forService for better option filtering --- cluster/default.nix | 1 + cluster/lib/lib.nix | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 cluster/lib/lib.nix diff --git a/cluster/default.nix b/cluster/default.nix index 548c3af..54a8969 100644 --- a/cluster/default.nix +++ b/cluster/default.nix @@ -17,6 +17,7 @@ lib.evalModules { ./lib/mesh.nix ./lib/secrets.nix ./lib/testing.nix + ./lib/lib.nix ./import-services.nix ]; diff --git a/cluster/lib/lib.nix b/cluster/lib/lib.nix new file mode 100644 index 0000000..1aedf13 --- /dev/null +++ b/cluster/lib/lib.nix @@ -0,0 +1,12 @@ +{ config, lib, ... }: + +{ + options.lib = { + forService = lib.mkOption { + description = "Enable these definitions for a particular service only."; + type = lib.types.functionTo lib.types.raw; + readOnly = true; + default = service: lib.mkIf (!config.simulacrum || lib.any (s: s == service) config.testConfig.activeServices); + }; + }; +} -- 2.47.0 From 4b76b6ed471705128c5006c448b7f05fd6967095 Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 23 Jul 2024 20:05:21 +0200 Subject: [PATCH 10/15] cluster/simulacrum: expose checks --- cluster/part.nix | 1 + cluster/simulacrum/checks.nix | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 cluster/simulacrum/checks.nix diff --git a/cluster/part.nix b/cluster/part.nix index eae3222..58e93b3 100644 --- a/cluster/part.nix +++ b/cluster/part.nix @@ -3,6 +3,7 @@ { imports = [ ./catalog + ./simulacrum/checks.nix ]; options.cluster = lib.mkOption { diff --git a/cluster/simulacrum/checks.nix b/cluster/simulacrum/checks.nix new file mode 100644 index 0000000..bf3e918 --- /dev/null +++ b/cluster/simulacrum/checks.nix @@ -0,0 +1,16 @@ +{ config, extendModules, lib, ... }: + +{ + perSystem = { pkgs, system, ... }: { + checks = lib.mkIf (system == "x86_64-linux") (lib.mapAttrs' (name: svc: let + runSimulacrum = pkgs.callPackage ./. { + inherit config extendModules; + }; + in { + name = "simulacrum-${name}"; + value = runSimulacrum { + service = name; + }; + }) (lib.filterAttrs (_: svc: svc.simulacrum.enable) config.cluster.config.services)); + }; +} -- 2.47.0 From c1720ec30dc8bfca29c17ee34629d02d104ccd69 Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 23 Jul 2024 20:07:16 +0200 Subject: [PATCH 11/15] packages/catalog: expose simulacrum checks differently --- packages/catalog/checks.nix | 41 +++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/packages/catalog/checks.nix b/packages/catalog/checks.nix index 1dab997..d8c2c72 100644 --- a/packages/catalog/checks.nix +++ b/packages/catalog/checks.nix @@ -1,21 +1,32 @@ { lib, ... }: { - perSystem = { config, ... }: { - catalog.depot = { - checks = lib.mapAttrs (name: check: { - description = "NixOS Test: ${name}"; - actions = { - build = { - description = "Build this check."; - command = "nix build -L --no-link '${builtins.unsafeDiscardStringContext check.drvPath}^*'"; - }; - runInteractive = { - description = "Run interactive driver."; - command = lib.getExe check.driverInteractive; - }; + perSystem = { config, pkgs, ... }: { + catalog = lib.mkMerge (lib.mapAttrsToList (name': check: let + simulacrum = lib.hasPrefix "simulacrum-" name'; + name = lib.removePrefix "simulacrum-" name'; + baseAttrPath = if simulacrum then + [ "cluster" "simulacrum" ] + else + [ "depot" "checks" ]; + in lib.setAttrByPath (baseAttrPath ++ [ name ]) { + description = if simulacrum then + "Simulacrum Test: ${name}" + else + "NixOS Test: ${name}"; + actions = { + build = { + description = "Build this check."; + command = "nix build -L --no-link '${builtins.unsafeDiscardStringContext check.drvPath}^*'"; }; - }) config.checks; - }; + runInteractive = { + description = "Run interactive driver."; + command = if simulacrum then + "${pkgs.bubblewrap}/bin/bwrap --unshare-all --bind / / --dev-bind /dev /dev ${lib.getExe check.driverInteractive}" + else + lib.getExe check.driverInteractive; + }; + }; + }) config.checks); }; } -- 2.47.0 From f37fed0ebb48e97bbaf3e2946f32507df2687052 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 10 Aug 2024 13:37:14 +0200 Subject: [PATCH 12/15] cluster/simulacrum: implement nowhere, fix networking --- cluster/simulacrum/default.nix | 17 ++++- cluster/simulacrum/nowhere/default.nix | 101 +++++++++++++++++++++++++ cluster/simulacrum/nowhere/options.nix | 16 ++++ 3 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 cluster/simulacrum/nowhere/default.nix create mode 100644 cluster/simulacrum/nowhere/options.nix diff --git a/cluster/simulacrum/default.nix b/cluster/simulacrum/default.nix index a900de7..101b345 100644 --- a/cluster/simulacrum/default.nix +++ b/cluster/simulacrum/default.nix @@ -17,7 +17,8 @@ let }; nodes = lib.attrNames config.gods.fromLight; - digits = lib.attrsets.listToAttrs (lib.zipListsWith lib.nameValuePair nodes (lib.range 1 255)); + nodes' = lib.attrNames (config.gods.fromLight // { nowhere = null; }); + digits = lib.attrsets.listToAttrs (lib.zipListsWith lib.nameValuePair nodes' (lib.range 1 255)); depot' = extendModules { modules = [ ({ config, ... }: { @@ -51,6 +52,12 @@ testers.runNixOSTest { imports = [ serviceConfig.simulacrum.settings + ./nowhere + { + nodes.nowhere.imports = [ + config.flake.nixosModules.port-magic + ]; + } ] ++ allAugments; _module.args = { @@ -73,12 +80,15 @@ testers.runNixOSTest { ${hour.interfaces.primary.link} = { useDHCP = lib.mkForce false; virtual = true; - ipv4.addresses = lib.mkForce [ + ipv4.addresses = lib.mkForce ([ { address = hour.interfaces.primary.addr; prefixLength = 32; } - ]; + ] ++ lib.optional hour.interfaces.primary.isNat { + address = hour.interfaces.primary.addrPublic; + prefixLength = 32; + }); }; eth1.ipv4.routes = lib.pipe nodes [ (lib.filter (n: n != node)) @@ -95,6 +105,7 @@ testers.runNixOSTest { firewall.extraCommands = lib.mkAfter (lib.optionalString (hour.interfaces.primary.isNat) '' # self-nat iptables -t nat -A PREROUTING -d ${hour.interfaces.primary.addrPublic} -j DNAT --to-destination ${hour.interfaces.primary.addr} + iptables -t nat -A OUTPUT -d ${hour.interfaces.primary.addrPublic} -j DNAT --to-destination ${hour.interfaces.primary.addr} iptables -t nat -A POSTROUTING -s ${hour.interfaces.primary.addr} -j SNAT --to-source ${hour.interfaces.primary.addrPublic} ''); }; diff --git a/cluster/simulacrum/nowhere/default.nix b/cluster/simulacrum/nowhere/default.nix new file mode 100644 index 0000000..4e3aaaf --- /dev/null +++ b/cluster/simulacrum/nowhere/default.nix @@ -0,0 +1,101 @@ +{ cluster, config, lib, pkgs, ... }: + +let + lift = config; + + cfsslConfigIntermediateCA = pkgs.writeText "simulacrum-cfssl-config.json" (builtins.toJSON { + signing = { + default.expiry = "8760h"; + profiles.intermediate = { + expiry = "8760h"; + usages = [ + "cert sign" + "crl sign" + ]; + ca_constraint = { + is_ca = true; + max_path_len = 1; + }; + }; + }; + }); + + caCsr = pkgs.writeText "simulacrum-ca-csr.json" (builtins.toJSON { + CN = "Simulacrum Root CA"; + }); + + ca = pkgs.runCommand "simulacrum-snakeoil-ca" { + nativeBuildInputs = [ + pkgs.cfssl + ]; + } '' + mkdir $out + cfssl gencert --initca ${caCsr} | cfssljson --bare $out/ca + ''; + + genCert = extraFlags: csrData: let + csr = pkgs.writeText "simulacrum-csr.json" (builtins.toJSON csrData); + in pkgs.runCommand "simulacrum-snakeoil-cert" { + nativeBuildInputs = [ + pkgs.cfssl + ]; + } '' + mkdir $out + cfssl gencert ${lib.escapeShellArgs ([ + "--ca=file:${ca}/ca.pem" + "--ca-key=file:${ca}/ca-key.pem" + ] ++ extraFlags ++ [ + csr + ])} | cfssljson --bare $out/cert + ''; + + genHostCert = hostname: genCert [ "--hostname=${hostname}" ] { CN = hostname; }; + + getNodeAddr = node: (builtins.head config.nodes.${node}.networking.interfaces.eth1.ipv4.addresses).address; +in + +{ + imports = [ + ./options.nix + ]; + defaults = { + networking.hosts."${getNodeAddr "nowhere"}" = lib.attrNames config.nowhere.names; + security.pki.certificateFiles = [ + "${ca}/ca.pem" + ]; + }; + + nowhere.certs = { + inherit ca; + intermediate = genCert [ "--config=${cfsslConfigIntermediateCA}" "--profile=intermediate" ] { + CN = "Simulacrum Intermediate CA"; + }; + }; + + nodes.nowhere = { config, depot, ... }: { + networking = { + firewall.allowedTCPPorts = [ 443 ]; + interfaces.eth1.ipv4.routes = lib.mapAttrsToList (name: hour: { + address = hour.interfaces.primary.addrPublic; + prefixLength = 32; + via = getNodeAddr name; + }) depot.gods.fromLight; + nameservers = map (name: depot.hours.${name}.interfaces.primary.addrPublic) cluster.config.services.dns.nodes.authoritative; + }; + services.nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts = lib.mapAttrs (name: link: let + cert = genHostCert name; + in { + forceSSL = true; + sslCertificate = "${cert}/cert.pem"; + sslCertificateKey = "${cert}/cert-key.pem"; + locations."/" = { + proxyPass = config.links.${link}.url; + extraConfig = "proxy_ssl_verify off;"; + }; + }) lift.nowhere.names; + }; + }; +} diff --git a/cluster/simulacrum/nowhere/options.nix b/cluster/simulacrum/nowhere/options.nix new file mode 100644 index 0000000..b0420b6 --- /dev/null +++ b/cluster/simulacrum/nowhere/options.nix @@ -0,0 +1,16 @@ +{ lib, ... }: + +{ + options.nowhere = { + names = lib.mkOption { + description = "Hostnames that point Nowhere."; + type = with lib.types; attrsOf str; + default = {}; + }; + certs = lib.mkOption { + description = "Snakeoil certificate packages."; + type = with lib.types; attrsOf package; + default = {}; + }; + }; +} -- 2.47.0 From e2ebdd097ea5249efaf7ae54cca257320c251968 Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 11 Aug 2024 00:50:00 +0200 Subject: [PATCH 13/15] cluster/simulacrum: recursive service deps --- cluster/simulacrum/default.nix | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cluster/simulacrum/default.nix b/cluster/simulacrum/default.nix index 101b345..26eca7e 100644 --- a/cluster/simulacrum/default.nix +++ b/cluster/simulacrum/default.nix @@ -4,9 +4,15 @@ let serviceConfig = config.cluster.config.services.${service}; - serviceList = [ service ] ++ serviceConfig.simulacrum.deps; + serviceList = getDepsRecursive [] service; allAugments = map (svc: config.cluster.config.services.${svc}.simulacrum.augments) serviceList; + getDepsRecursive = acc: service: let + deps = lib.subtractLists acc config.cluster.config.services.${service}.simulacrum.deps; + acc' = acc ++ [ service ]; + recurse = getDepsRecursive acc'; + in lib.unique (lib.flatten ([ service ] ++ map recurse deps)); + lift = config; snakeoil = { -- 2.47.0 From a10f8c18ee9b5684fdabdb95faef0eb4a153bdae Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 13 Aug 2024 18:51:26 +0200 Subject: [PATCH 14/15] cluster/services/wireguard: test in simulacrum --- cluster/services/wireguard/default.nix | 4 ++++ cluster/services/wireguard/test.nix | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 cluster/services/wireguard/test.nix diff --git a/cluster/services/wireguard/default.nix b/cluster/services/wireguard/default.nix index 54b893a..b3ba747 100644 --- a/cluster/services/wireguard/default.nix +++ b/cluster/services/wireguard/default.nix @@ -93,5 +93,9 @@ in nodes = config.services.wireguard.nodes.mesh; shared = false; }; + simulacrum = { + enable = true; + settings = ./test.nix; + }; }; } diff --git a/cluster/services/wireguard/test.nix b/cluster/services/wireguard/test.nix new file mode 100644 index 0000000..dfa7e92 --- /dev/null +++ b/cluster/services/wireguard/test.nix @@ -0,0 +1,26 @@ +{ cluster, lib, ... }: + +{ + testScript = '' + start_all() + ${lib.pipe cluster.config.services.wireguard.nodes.mesh [ + (map (node: /*python*/ '' + ${node}.wait_for_unit("wireguard-wgmesh.target") + '')) + (lib.concatStringsSep "\n") + ]} + + ${lib.pipe cluster.config.services.wireguard.nodes.mesh [ + (map (node: /*python*/ '' + with subtest("${node} can reach all other nodes"): + ${lib.pipe (cluster.config.services.wireguard.otherNodes.mesh node) [ + (map (peer: /*python*/ '' + ${node}.succeed("ping -c3 ${cluster.config.hostLinks.${peer}.mesh.extra.meshIp}") + '')) + (lib.concatStringsSep "\n ") + ]} + '')) + (lib.concatStringsSep "\n") + ]} + ''; +} -- 2.47.0 From a54f20d779d1fd1b16b14ae3ae0af471864ee25e Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 13 Aug 2024 20:59:43 +0200 Subject: [PATCH 15/15] modules/motd: use fixed rev --- modules/motd/default.nix | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/motd/default.nix b/modules/motd/default.nix index be403a6..91417e1 100644 --- a/modules/motd/default.nix +++ b/modules/motd/default.nix @@ -1,4 +1,4 @@ -{ config, depot, pkgs, ... }: +{ cluster, config, depot, pkgs, ... }: { users.motd = builtins.readFile ./motd.txt; environment.interactiveShellInit = let @@ -8,6 +8,11 @@ grep = exec pkgs.gnugrep "grep"; countUsers = '' ${util "who"} -q | ${util "head"} -n1 | ${util "tr"} ' ' \\n | ${util "uniq"} | ${util "wc"} -l''; countSessions = '' ${util "who"} -q | ${util "head"} -n1 | ${util "wc"} -w''; + + rev = if cluster.config.simulacrum then + "simulacrum" + else + depot.rev or "\${BRED}(✘)\${CO}\${BWHITE} Dirty"; in '' ( # Reset colors @@ -40,7 +45,7 @@ echo -e " █ ''${BGREEN}(✓)''${CO} ''${BWHITE}You are using a genuine Private Void™ system.''${CO}" echo " █" echo -e " █ ''${BWHITE}OS Version....:''${CO} NixOS ''${CAB}${config.system.nixos.version}''${CO}" - echo -e " █ ''${BWHITE}Configuration.:''${CO} ''${CAB}${depot.rev or "\${BRED}(✘)\${CO}\${BWHITE} Dirty"}''${CO}" + echo -e " █ ''${BWHITE}Configuration.:''${CO} ''${CAB}${rev}''${CO}" echo -e " █ ''${BWHITE}Uptime........:''${CO} $(${uptime} -p | ${util "cut"} -d ' ' -f2- | GREP_COLORS='mt=01;35' ${grep} --color=always '[0-9]*')" echo -e " █ ''${BWHITE}SSH Logins....:''${CO} There are currently ''${CAB}$(${countUsers})''${CO} users logged in on ''${CAB}$(${countSessions})''${CO} sessions" ) -- 2.47.0