diff --git a/bin/import-server-gpg-pubkeys b/bin/import-server-gpg-pubkeys new file mode 100755 index 00000000..6218088e --- /dev/null +++ b/bin/import-server-gpg-pubkeys @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -euo pipefail + +HOSTNAMES=$(nix eval .#nixosConfigurations.ds9._module.specialArgs.instanceConfigs --json | jq '.[].publicHostname | select(.)' -r) + +for h in $HOSTNAMES; do + echo "[+] importing key from $h" + ssh -t $h "sudo nix-shell -p ssh-to-pgp --run \"ssh-to-pgp -i /etc/ssh/ssh_host_rsa_key -email root@$h\"" | gpg --import +done diff --git a/flake.lock b/flake.lock index c5ca7e5a..017bf260 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ "uv2nix": "uv2nix" }, "locked": { - "lastModified": 1753369162, - "narHash": "sha256-pSAsUVueht3WyyFJ3K+QJKWqFZNbyvsXijHOAHApeLk=", + "lastModified": 1757062396, + "narHash": "sha256-403iuoMVVjk64sF1GgZfrRwOnVU1H14sflE+LNp927c=", "owner": "nix-community", "repo": "authentik-nix", - "rev": "1361d269fe10c527528264185567a053252e22b0", + "rev": "22827e9a0cc002a076ee8bd14c3433ebc6c87f95", "type": "github" }, "original": { @@ -32,16 +32,16 @@ "authentik-src": { "flake": false, "locked": { - "lastModified": 1753187012, - "narHash": "sha256-bs/ThY3YixwBObahcS7BrOWj0gsaUXI664ldUQlJul8=", + "lastModified": 1755873658, + "narHash": "sha256-5l1g55b0xozGg0NaZFimiO5JbHGcudaNSEn1/XsweaU=", "owner": "goauthentik", "repo": "authentik", - "rev": "23ffad1c6be80bea223caf5f1cf265b984b76328", + "rev": "dd7c6b29d950664deadbcf5390272619a8bf9a5e", "type": "github" }, "original": { "owner": "goauthentik", - "ref": "version/2025.6.4", + "ref": "version/2025.8.1", "repo": "authentik", "type": "github" } @@ -69,11 +69,11 @@ ] }, "locked": { - "lastModified": 1755003551, - "narHash": "sha256-UGWNAIPJZUGtshdgb6wuNj5QD4YBI3YDvlmsFGApisM=", + "lastModified": 1757077534, + "narHash": "sha256-qX9A9/ymQtWlEtMCeUXaZp+OVGzn+ebZKGTb83i3G4U=", "owner": "sofusa", "repo": "csharp-language-server", - "rev": "2a0fe57d77a00ff91ebea96cbd2be848293a56e1", + "rev": "89c5ad77cdb3b8b6ba7371b151ee6e4819955540", "type": "github" }, "original": { @@ -119,11 +119,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1749398372, - "narHash": "sha256-tYBdgS56eXYaWVW3fsnPQ/nFlgWi/Z2Ymhyu21zVM98=", + "lastModified": 1754487366, + "narHash": "sha256-pHYj8gUBapuUzKV/kN/tR3Zvqc7o6gdFB9XKXIp1SQ8=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "9305fe4e5c2a6fcf5ba6a3ff155720fbe4076569", + "rev": "af66ad14b28a127c5c0f3bbb298218fc63528a18", "type": "github" }, "original": { @@ -314,11 +314,11 @@ ] }, "locked": { - "lastModified": 1755914636, - "narHash": "sha256-VJ+Gm6YsHlPfUCpmRQxvdiZW7H3YPSrdVOewQHAhZN8=", + "lastModified": 1757075491, + "narHash": "sha256-a+NMGl5tcvm+hyfSG2DlVPa8nZLpsumuRj1FfcKb2mQ=", "owner": "nix-community", "repo": "home-manager", - "rev": "8b55a6ac58b678199e5bba701aaff69e2b3281c0", + "rev": "f56bf065f9abedc7bc15e1f2454aa5c8edabaacf", "type": "github" }, "original": { @@ -415,11 +415,11 @@ "lix": { "flake": false, "locked": { - "lastModified": 1747597901, - "narHash": "sha256-jS+P57tXZEl+zvPfEIHFbd1j3xfuWcrcMrcnbm9wWbE=", - "rev": "33eaaf02fd3f380e99032b25e741eeeb10573cad", + "lastModified": 1753306924, + "narHash": "sha256-jLCEW0FvjFhC+c4RHzH+xbkSOxrnpFHnhjOw6sudhx0=", + "rev": "1a4393d0aac31aba21f5737ede1b171e11336d77", "type": "tarball", - "url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/33eaaf02fd3f380e99032b25e741eeeb10573cad.tar.gz?rev=33eaaf02fd3f380e99032b25e741eeeb10573cad" + "url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/1a4393d0aac31aba21f5737ede1b171e11336d77.tar.gz?rev=1a4393d0aac31aba21f5737ede1b171e11336d77" }, "original": { "type": "tarball", @@ -436,11 +436,11 @@ ] }, "locked": { - "lastModified": 1755826954, - "narHash": "sha256-csTdFThUiCvqZj1R8tTcSiVGxIXbuZ9K+0TywhHCGZY=", + "lastModified": 1756125859, + "narHash": "sha256-6a+PWILmqHCs9B5eIBLg6HSZ8jYweZpgOWO8FlyVwYI=", "ref": "release-2.93", - "rev": "174dc5796138f7e29f9baddd672ac548d8a12d76", - "revCount": 154, + "rev": "d3292125035b04df00d01549a26e948631fabe1e", + "revCount": 156, "type": "git", "url": "https://git.lix.systems/lix-project/nixos-module.git" }, @@ -453,11 +453,11 @@ "mobile-nixos": { "flake": false, "locked": { - "lastModified": 1755608111, - "narHash": "sha256-m1sfLwDBAGhvNtLgddpja259K/7L1HVYuWoe/j5SxAA=", + "lastModified": 1757174863, + "narHash": "sha256-PFu4TTHm/GSbrBBl6waxSNyQfpMoC4YkL1RMXkb2gyE=", "owner": "mobile-nixos", "repo": "mobile-nixos", - "rev": "6d6b7ff7cf2a538eb86d0b6f25b92a1c581c842b", + "rev": "c3164daaf62a81d0c4bfab67e6763a4319212557", "type": "github" }, "original": { @@ -511,11 +511,11 @@ "nheko": { "flake": false, "locked": { - "lastModified": 1755336566, - "narHash": "sha256-GaBCbxki/0Dt4EBfIRjMhEk47tmTiqJOOI03/sz9bkQ=", + "lastModified": 1757024319, + "narHash": "sha256-UgFN4xSuzDp/XtTurhhpVRiEbbmcCNutehnV+bxvOVo=", "owner": "Nheko-Reborn", "repo": "nheko", - "rev": "f59f77a21e60c80a0f37f23e2926992a1d3a8ddc", + "rev": "5b025fa2b0143d87d6ffceeb47edd84cc60de64a", "type": "github" }, "original": { @@ -532,11 +532,11 @@ "rust-overlay": "rust-overlay_3" }, "locked": { - "lastModified": 1755879086, - "narHash": "sha256-fUQ1iuR2/7UrHQ7LXRJ8a2DahcyTard4WvL/wQ18SII=", + "lastModified": 1756926064, + "narHash": "sha256-5/1vyFRLvJWxhBgpPaV2orC0pjSgIny6JM6+joLyZok=", "owner": "YaLTeR", "repo": "niri", - "rev": "2865ec3e47fa0b170f82f4beeefa56a5ea49d133", + "rev": "c69464c1288789020d9a086f86c970a7dc49b8c7", "type": "github" }, "original": { @@ -563,11 +563,11 @@ }, "nixos-hardware": { "locked": { - "lastModified": 1755330281, - "narHash": "sha256-aJHFJWP9AuI8jUGzI77LYcSlkA9wJnOIg4ZqftwNGXA=", + "lastModified": 1757103352, + "narHash": "sha256-PtT7ix43ss8PONJ1VJw3f6t2yAoGH+q462Sn8lrmWmk=", "owner": "NixOS", "repo": "nixos-hardware", - "rev": "3dac8a872557e0ca8c083cdcfc2f218d18e113b0", + "rev": "11b2a10c7be726321bb854403fdeec391e798bf0", "type": "github" }, "original": { @@ -579,11 +579,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1755615617, - "narHash": "sha256-HMwfAJBdrr8wXAkbGhtcby1zGFvs+StOp19xNsbqdOg=", + "lastModified": 1756787288, + "narHash": "sha256-rw/PHa1cqiePdBxhF66V7R+WAP8WekQ0mCDG4CFqT8Y=", "owner": "nixos", "repo": "nixpkgs", - "rev": "20075955deac2583bb12f07151c2df830ef346b4", + "rev": "d0fc30899600b9b3466ddb260fd83deb486c32f1", "type": "github" }, "original": { @@ -595,11 +595,11 @@ }, "nixpkgs-lib": { "locked": { - "lastModified": 1748740939, - "narHash": "sha256-rQaysilft1aVMwF14xIdGS3sj1yHlI6oKQNBRTF40cc=", + "lastModified": 1753579242, + "narHash": "sha256-zvaMGVn14/Zz8hnp4VWT9xVnhc8vuL3TStRqwk22biA=", "owner": "nix-community", "repo": "nixpkgs.lib", - "rev": "656a64127e9d791a334452c6b6606d17539476e2", + "rev": "0f36c44e01a6129be94e3ade315a5883f0228a6e", "type": "github" }, "original": { @@ -610,11 +610,11 @@ }, "nixpkgs-master": { "locked": { - "lastModified": 1755976423, - "narHash": "sha256-HdE59xk26UZ4fASYLOpYUhwP0SI8PKc7pIDMXiLqdXY=", + "lastModified": 1757182960, + "narHash": "sha256-xnA8bgigocJME3sMfXKH5STQ9yG5tv9Jp+c5mrGfdIM=", "owner": "nixos", "repo": "nixpkgs", - "rev": "33e0bcd1c1d578200c615e8fa75d01a0ddc0610b", + "rev": "70719dcf0748dcfc922b71a7bf788e824b7a8ea0", "type": "github" }, "original": { @@ -643,11 +643,11 @@ "polkit": { "flake": false, "locked": { - "lastModified": 1751722581, - "narHash": "sha256-zBoiGIq+l+GHzotH9BMC9zZ8e9E7SmKCcs8Vnt1teqU=", + "lastModified": 1756282082, + "narHash": "sha256-VGY6MbzUDekt3Dd/GbW+fQDeW/k7oZXXLUyvgU23cBI=", "owner": "polkit-org", "repo": "polkit", - "rev": "0c022e4ff621eb8d2efa9d6b5c4c0f32c9814fd3", + "rev": "93ed9a0bb689916fe28cc5da317dbcb91ca989d2", "type": "github" }, "original": { @@ -699,11 +699,11 @@ ] }, "locked": { - "lastModified": 1749519371, - "narHash": "sha256-UJONN7mA2stweZCoRcry2aa1XTTBL0AfUOY84Lmqhos=", + "lastModified": 1756087852, + "narHash": "sha256-4jc3JDQt75fYXFrglgqyzF6C6zLU0QGLymzian4aP+U=", "owner": "pyproject-nix", "repo": "build-system-pkgs", - "rev": "7c06967eca687f3482624250428cc12f43c92523", + "rev": "6edb3ae27395cd88be3d64b732d1539957dad59c", "type": "github" }, "original": { @@ -720,11 +720,11 @@ ] }, "locked": { - "lastModified": 1750499893, - "narHash": "sha256-ThKBd8XSvITAh2JqU7enOp8AfKeQgf9u7zYC41cnBE4=", + "lastModified": 1756395552, + "narHash": "sha256-5aJM14MpoLk2cdZAetu60OkLQrtFLWTICAyn1EP7ZpM=", "owner": "pyproject-nix", "repo": "pyproject.nix", - "rev": "e824458bd917b44bf4c38795dea2650336b2f55d", + "rev": "030dffc235dcf240d918c651c78dc5f158067b51", "type": "github" }, "original": { @@ -971,11 +971,11 @@ ] }, "locked": { - "lastModified": 1750987094, - "narHash": "sha256-GujDElxLgYatnNvuL1U6qd18lcuG6anJMjpfYRScV08=", + "lastModified": 1756466761, + "narHash": "sha256-ALXRHIMXQ4qVNfCbcWykC23MjMwUoHn9BreoBfqmq0Y=", "owner": "pyproject-nix", "repo": "uv2nix", - "rev": "4b703d851b61e664a70238711a8ff0efa1aa2f52", + "rev": "0529e6d8227517205afcd1b37eee3088db745730", "type": "github" }, "original": { @@ -993,11 +993,11 @@ "rust-overlay": "rust-overlay_4" }, "locked": { - "lastModified": 1755963545, - "narHash": "sha256-hGXzVhlk+gelqagKAgOHbilNYasM+jM3T8JPshDl2/M=", + "lastModified": 1757179758, + "narHash": "sha256-TIvyWzRt1miQj6Cf5Wy8Qz43XIZX7c4vTVwRLAT5S4Y=", "owner": "Supreeeme", "repo": "xwayland-satellite", - "rev": "d759c64681bab7cd34f48122037d7420d42f3024", + "rev": "970728d0d9d1eada342bb8860af214b601139e58", "type": "github" }, "original": { @@ -1014,11 +1014,11 @@ ] }, "locked": { - "lastModified": 1755922982, - "narHash": "sha256-YMchUKtaIhICzwwiAP/j6G+KaqRA8xSnGV2dfdVXoHw=", + "lastModified": 1757174751, + "narHash": "sha256-HB01usaR5wg5LK3lV6S7Za2x4AfKrNceOnun/mlpChk=", "owner": "0xc000022070", "repo": "zen-browser-flake", - "rev": "25f56c0f5b813312f38078418b2229ada41c4bcc", + "rev": "6a0d727b623f46108c9bcaa87901e7f6e69e78c2", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 6c0fd2d4..df838a32 100644 --- a/flake.nix +++ b/flake.nix @@ -85,6 +85,16 @@ inherit system overlays; config.allowUnfree = true; }; + modules = [ + inputs.kmonad.nixosModules.default + inputs.home-manager.nixosModules.default + inputs.lanzaboote.nixosModules.lanzaboote + inputs.sops-nix.nixosModules.sops + inputs.impermanence.nixosModules.impermanence + inputs.lix-module.nixosModules.lixFromNixpkgs + inputs.authentik.nixosModules.default + ] + ++ (import ./modules/module-list.nix); in { overlays.default = @@ -99,18 +109,7 @@ // (import ./overlays inputs final prev) ); - nixosConfigurations = lib.xyno.loadInstances ./instances ( - [ - inputs.kmonad.nixosModules.default - inputs.home-manager.nixosModules.default - inputs.lanzaboote.nixosModules.lanzaboote - inputs.sops-nix.nixosModules.sops - inputs.impermanence.nixosModules.impermanence - inputs.lix-module.nixosModules.lixFromNixpkgs - inputs.authentik.nixosModules.default - ] - ++ (import ./modules/module-list.nix) - ); + nixosConfigurations = lib.xyno.loadInstances ./instances (modules); devShell."x86_64-linux" = let pkgs = genPkgs "x86_64-linux"; @@ -120,9 +119,24 @@ pkgs.nixfmt-rfc-style pkgs.nil pkgs.sops - pkgs.ssh-to-age + (pkgs.runCommand "nix-config-bin" {} '' + mkdir -p $out/bin + cp ${./bin}/* $out/bin + '') ]; - SOPS_AGE_KEY_CMD = ""; + SOPS_CONFIG = (pkgs.callPackage ./sops.nix { instanceConfigs = lib.xyno.getDirs ./instances; }); + + }; + checks."x86_64-linux"."nixos" = + let + pkgs = genPkgs "x86_64-linux"; + in + pkgs.testers.runNixOSTest { + imports = (import ./modules/test-list.nix); + node.specialArgs = { inherit inputs; }; + extraBaseModules.imports = modules; + extraBaseModules.services.openssh.enable = true; + node.pkgsReadOnly = false; }; }; } diff --git a/instances/ds9/configuration.nix b/instances/ds9/configuration.nix index a4a7bc2a..2346c049 100644 --- a/instances/ds9/configuration.nix +++ b/instances/ds9/configuration.nix @@ -15,7 +15,10 @@ ]; time.timeZone = "Europe/Berlin"; + networking.hostId = "7b4c2932"; + xyno.presets.cli.enable = true; + xyno.presets.server.enable = true; xyno.services.wireguard.enable = true; xyno.services.caddy.enable = true; xyno.services.monitoring.enable = true; @@ -26,5 +29,6 @@ enable = true; }; + system.stateVersion = "24.11"; } diff --git a/instances/ds9/default.nix b/instances/ds9/default.nix index b1ea5987..47aa5670 100644 --- a/instances/ds9/default.nix +++ b/instances/ds9/default.nix @@ -1,11 +1,12 @@ { + sopsKey = "fada7e7be28e186e463ad745a38d17f36849d8a7"; modules = [ ./configuration.nix ]; hostName = "ds9"; publicHostname = "ds9.hailsatan.eu"; prometheusServer = true; wg = { pubKey = ""; - server = true; - v4 = "10.13.12.1"; + # server = true; + # v4 = "10.13.12.1"; }; } diff --git a/instances/ds9/hardware-configuration.nix b/instances/ds9/hardware-configuration.nix index 381f25ef..338b716d 100644 --- a/instances/ds9/hardware-configuration.nix +++ b/instances/ds9/hardware-configuration.nix @@ -6,6 +6,14 @@ { imports = [ "${modulesPath}/installer/scan/not-detected.nix" ]; + boot.lanzaboote = { + enable = true; + pkiBundle = "/var/lib/sbctl"; + }; + boot.loader.systemd-boot.enable = lib.mkForce false; + + + boot.initrd.availableKernelModules = [ "r8169" "ahci" "vfio-pci" "xhci_pci" "ehci_pci" "nvme" "usbhid" "sd_mod" "sr_mod" ]; boot.kernelModules = [ "kvm-amd" ]; nix.settings.max-jobs = lib.mkDefault 12; diff --git a/instances/ds9/secrets/authentik.yaml b/instances/ds9/secrets/authentik.yaml new file mode 100644 index 00000000..9d8bde0d --- /dev/null +++ b/instances/ds9/secrets/authentik.yaml @@ -0,0 +1,57 @@ +authentik: + env: ENC[AES256_GCM,data:lHo29WanGT+AqxfIPFACXfklsYRZss/iZwsZmjbhXu9Od9GnUozzh9P2P0h+AeMIw6CCreJyohIe53ju+nlFGkyRsQ0BJ6K8fRiIglDuFF2vLK6ATuDP6QpoK2tOFpUW2Ne5SqnnAhEnAyJ42NpmDTiepuZPiUYLH/vg35AavQhE5OrRGG2YjblZ12e3pXxIWC/Frqa7fnbzh2I2dhyLGCkYkDfOI4WiZieERphnTkP9wBIi3on1I27dZEZJ0f6k5ei5Upre3kIaQKwGJSIw2NoD6FiFTQ5ytsv8tbN37nIyTPp4O+mvEuXYCwM6BqCvZnNkvoZkTOnAVr2CjzNK/JCmimFU6Kk9rxRzhbmAsoCkx1Rns9c6qdCo8qMH94o+4YWOdW9GcQT0FsLa/WzIRgDpOIfqCpKQiXbU1wlh+Yw87MInMZpvXsRpwtVnZz0SVvjr9c1IOyqWwyThM0lg+wijepAzEZZVJfUU5+GR+RgQNoQJAeUyXubH07RDTcV5XfjsLP85C8grgN/PieIC,iv:eoQ8QEBAW9w6/PV+HDdZ6NgB2kINpphPMCbarmKBay0=,tag:TsINizOipDtkXjbWPJ4pRQ==,type:str] +sops: + lastmodified: "2025-09-06T18:00:23Z" + mac: ENC[AES256_GCM,data:bI9CvBD1vFgTJc6L13alqYPJ1/Jj5h/KCWqSSlaYVm0SZVigeRWxAg84RKRZki1DcUpLFxQdCcNUEGfffMcg6PVHJkQMiQJ1vfmRDDRNijCIoWjUDuL+QXpR38y+dBX7VL67z435jcqAOw/K9/mDfHF92BNmYDuzp4edS4tJOfY=,iv:M5/tgSh2NsZnedBxfgQO/+e9OMuDweTYbUNhtLP8q1s=,tag:pWJaXjUp65G2Buz8M2eq4A==,type:str] + pgp: + - created_at: "2025-09-06T17:57:55Z" + enc: |- + -----BEGIN PGP MESSAGE----- + + hL4DAAAAAAAAAAASBAMEfRbweJXEuALhkTVq+G9vZKseHSs0v2RJ7BlrCXX1HlqN + QMk+uNFyogw+4+0NAqOSWcj5nBBtRH/hX/p6G2l88wlc9JydmbbYQ2Gi+8TnuOgG + VamODcj9AWsJQ8y3CW/10RfcniyHB9JZcaBqFGsXUDDvmZPu0N+SUeEHSzg7tAUw + SwJUjalaTPDROP+R/y0ZFka4jKp8XqPr4H/4hvnpf6TXd+8WzYH/yC6yuoZDIexx + 0l4BzxHrfFkN0qdQazATJDB/Rqxr+aWCw6OtO2+wt7O/rXhiqJdumGcK6/ZgqCGJ + V29dn+x3oUM/wsc7LEFVAZe1cXB9DAZ4jJLUjRyUdHHgauYS4XZBRvsFMAJ2P9km + =29z4 + -----END PGP MESSAGE----- + fp: 0D98D5964AC8BB1CA034CE4EC456133700066642 + - created_at: "2025-09-06T17:57:55Z" + enc: |- + -----BEGIN PGP MESSAGE----- + + hQGMAwAAAAAAAAAAAQv/UGwFHKX91CovaBAeRVKqT0asZCb9gJ1CYOLllY9GzZGq + yvFXAd13d8+ckQEI2w482sgMgpxUxxxJV9L68AT5nZSFWxQLATAA9Jx2Vxa7eUWH + HC9ImmtU+nhF5HuErq3/eMRdtbskvrvSD4MKI47apNh+OWyNJ3Oapv38Fu8c3jtY + 0zdYgKSQgu6O/5XbvuPJcQu44zEPr5q8IkXEt43R/SVBEWCN3NVvK0wQcUn6Li0j + rhdnZyLVB8BdlzjV2Q7X/6k4bcE+q+r//fNwQTw/CkWgYejt40VzZf0do2Z/iYgb + Vqmc4ka99z9laSsrxd8974k6ZYcgb1ZY76pLZwyo17LNn5yYamp6fDaat9p0+Jyw + UlD9nz+JOnnlRaN7hGs5kXuUTCmvEbck5nKhbejPhCKhUFY+42Mrk+X3cdXUyk4u + wYBFN/wW9TPMeJ2QxaXqmiBKJznMz0I32gJ/wPmUNLSlPlnb2CXG4jJjuKfMI8Px + 9hQhxS/t4ztZB4Cny2l80lgB10M5NTaOz9VCr/lsX9tTcnRNHsKuByHGgtbTTkiF + ozE/5VeSpfOfR/nDmE2HwqvXP9aBHYBo2bX0BWCpHcbLddynptNVmorwvDchlmjJ + Mp6Lg0T+d21O + =wy3b + -----END PGP MESSAGE----- + fp: fada7e7be28e186e463ad745a38d17f36849d8a7 + - created_at: "2025-09-06T17:57:55Z" + enc: |- + -----BEGIN PGP MESSAGE----- + + hQGMAwAAAAAAAAAAAQv/VcY7gbDGzqkJARd+73lH/Az24Phmyq5vF4KKBU6bpwN1 + AZJsglCNYYekR99Iadjz7Wj8mxpSEf8VxmjW7EYH0SIh71YLFDaOPkcebTVWpsFA + xYdiYUFiujYz71CfvOSweC3hEqREWma15FPD3jA0TPfoekAYOML95ytCf452hOL+ + YHaIe8LiaqchJ0AX5JtUZS+NWsiyITd1S9VPgraDH3skUruF+JpzYvg/NIW3wexT + +Ul6ACzDOtpx7lfZlcj5rYndR4glhELF/bsIfhM9s2ESAuc/uFK46kzhDfe1rnRw + Edx09n7udIB5RZcn4x3jgCS721Dz0wSqnbC49OWfxHux4DadcIwzITI6MZFyWPhk + 3Gbo1cNnxMvYSE4X86J6ZY9zqrxu9w2hRV7JSeR2ATeC5AHYdU+gTsUyzTlaSNKn + 9uVOLuczajuaFMnp7Hbd/H8rVJv8SNTeDtZE+wvUnRX2+yjDsPzdqquTEnk6N2uM + WTGKHc6DJk9/MDmovJMa0lgBzaUUSCHoxeOaWUuNUiyvLJyyzClmD60VkU0DrBID + rdotdzKIYL1GLfjfD/tSjKCqEQ3d2PSXSSnvvVkBUvkZSFNRYYqJOKwcFs3szmvM + 0ZJFm0C+a3YJ + =Us6w + -----END PGP MESSAGE----- + fp: b730b2bf54eb792a14bfd3e68c14c08894376c5f + unencrypted_suffix: _unencrypted + version: 3.10.2 diff --git a/instances/ds9/services/paperless.nix b/instances/ds9/services/paperless.nix index 44395637..f59a702f 100644 --- a/instances/ds9/services/paperless.nix +++ b/instances/ds9/services/paperless.nix @@ -17,6 +17,7 @@ configureTika = true; enable = true; database.createLocally = true; + domain = "paperless.hailsatan.eu"; exporter = { enable = true; directory = "/data/paperless-export"; diff --git a/instances/minos/configuration.nix b/instances/minos/configuration.nix deleted file mode 100644 index b1ed71b4..00000000 --- a/instances/minos/configuration.nix +++ /dev/null @@ -1,83 +0,0 @@ -{ - config, - pkgs, - inputs, - lib, - ... -}: -{ - imports = [ - (import "${inputs.mobile-nixos}/lib/configuration.nix" { device = "lenovo-krane"; }) - ./hardware-configuration.nix - # - ]; - nixpkgs.system = "aarch64-linux"; - time.timeZone = "Europe/Berlin"; - networking.firewall.allowedTCPPorts = [ - 1880 - 2021 - ]; - networking.firewall.allowedUDPPorts = [ - 1880 - 2021 - ]; - - # fix accelerometer - services.udev.extraRules = '' - ACTION=="remove", GOTO="sensor_end" - - SUBSYSTEM=="iio", KERNEL=="iio*", SUBSYSTEMS=="platform", - ATTRS{modalias}=="platform:cros-ec-accel", - ENV{ACCEL_MOUNT_MATRIX}="0, 1, 0; -1, 0, 0; 0, 0, -1", - GOTO="sensor_end" - - LABEL="sensor_end" - ''; - environment.etc."libinput/local-overrides.quirks".text = '' - [Touchpad pressure override] - MatchUdevType=touchpad - MatchName=Google Inc. Hammer - AttrPressureRange=20:10 - ''; - - security.rtkit.enable = true; - services.tailscale.enable = true; - # services.tailscale.useRoutingFeatures = "client"; - xyno.hardware.kmonad.enable = true; - xyno.presets.cli.enable = true; - xyno.presets.gui.enable = true; - xyno.presets.home-manager.enable = true; - xyno.system.user.enable = true; - xyno.user-services.syncthing = { - enable = true; - tray = true; - }; - xyno.networking.networkd = { - enable = true; - # enableWifi = true; - }; - - # Enable power management options - powerManagement.enable = true; - - users.users."xyno".extraGroups = [ - "dialout" - "feedbackd" - "networkmanager" - "video" - "wheel" - ]; - # It's recommended to keep enabled on these constrained devices - zramSwap.enable = true; - # Use Network Manager - networking.wireless.enable = false; - networking.networkmanager.enable = true; - hardware.bluetooth.enable = true; - services.blueman.enable = true; - services.power-profiles-daemon.enable = true; - programs.kdeconnect.enable = true; - services.flatpak.enable = true; - - system.stateVersion = "24.11"; - programs.nh.enable = true; -} diff --git a/instances/minos/default.nix b/instances/minos/default.nix deleted file mode 100644 index aa50c939..00000000 --- a/instances/minos/default.nix +++ /dev/null @@ -1,4 +0,0 @@ -{ - modules = [ ./configuration.nix ]; - hostName = "minos"; -} diff --git a/instances/minos/hardware-configuration.nix b/instances/minos/hardware-configuration.nix deleted file mode 100644 index 489f2f8c..00000000 --- a/instances/minos/hardware-configuration.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - fileSystems = { - "/" = { - device = "/dev/disk/by-uuid/0565c87f-d576-4016-ada7-b3d44ce5e6b3"; - fsType = "ext4"; - }; - }; - - boot.initrd.luks.devices = { - "LUKS-MINOS-ROOTFS" = { - device = "/dev/disk/by-uuid/a9134654-519e-4611-894d-b6244d1ea0f7"; - }; - }; - - nix.settings.max-jobs = lib.mkDefault 4; -} diff --git a/instances/picard/configuration.nix b/instances/picard/configuration.nix new file mode 100644 index 00000000..384ebf17 --- /dev/null +++ b/instances/picard/configuration.nix @@ -0,0 +1,32 @@ +{ + config, + pkgs, + lib, + ... +}: +{ + nixpkgs.system = "x86_64-linux"; + + boot.loader.grub.enable = true; + boot.loader.grub.device = "/dev/sda"; + boot.loader.systemd-boot.enable = false; + + + imports = [ + ./hardware-configuration.nix + ]; + time.timeZone = "Europe/Berlin"; + + xyno.presets.server.enable = true; + xyno.presets.cli.enable = true; + xyno.services.wireguard.enable = true; + xyno.services.caddy.enable = true; + xyno.services.monitoring.enable = true; + xyno.presets.home-manager.enable = true; + xyno.system.user.enable = true; + xyno.networking.networkd = { + enable = true; + }; + + system.stateVersion = "25.05"; +} diff --git a/instances/picard/default.nix b/instances/picard/default.nix new file mode 100644 index 00000000..e867a324 --- /dev/null +++ b/instances/picard/default.nix @@ -0,0 +1,12 @@ +{ + modules = [ ./configuration.nix ]; + sopsKey = "b730b2bf54eb792a14bfd3e68c14c08894376c5f"; + hostName = "picard"; + publicHostname = "xyno.space"; + # prometheusServer = true; + wg = { + pubKey = ""; + server = true; + v4 = "10.13.12.1"; + }; +} diff --git a/instances/picard/hardware-configuration.nix b/instances/picard/hardware-configuration.nix new file mode 100644 index 00000000..17ef0279 --- /dev/null +++ b/instances/picard/hardware-configuration.nix @@ -0,0 +1,58 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ + config, + lib, + pkgs, + modulesPath, + ... +}: + +{ + imports = [ "${modulesPath}/installer/scan/not-detected.nix" ]; + + boot.initrd.availableKernelModules = [ + "r8169" + "ahci" + "vfio-pci" + "xhci_pci" + "ehci_pci" + "nvme" + "usbhid" + "sd_mod" + "sr_mod" + ]; + boot.kernelModules = [ "kvm-amd" ]; + nix.settings.max-jobs = lib.mkDefault 12; + powerManagement.powertop.enable = true; + powerManagement.cpuFreqGovernor = "powersave"; + powerManagement.scsiLinkPolicy = "min_power"; + + fileSystems."/persistent" = { + device = "/dev/disk/by-uuid/ca79f433-163a-4c5c-b176-8e694a674dda"; + fsType = "xfs"; + neededForBoot = true; + }; + fileSystems."/" = { + device = "none"; + fsType = "tmpfs"; + options = [ + "size=8G" + "defaults" + "mode=755" + ]; + }; + + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/DA11-68A6"; + fsType = "vfat"; + options = [ + "fmask=0022" + "dmask=0022" + "noauto" + "x-systemd.automount" + ]; + }; + +} diff --git a/instances/theseus/configuration.nix b/instances/theseus/configuration.nix index 87e90223..aab8ecd0 100644 --- a/instances/theseus/configuration.nix +++ b/instances/theseus/configuration.nix @@ -46,7 +46,9 @@ "olm-3.2.16" ]; virtualisation.podman.enable = true; - services.vsmartcard-vpcd.enable = true; + services.vsmartcard-vpcd.enable = true; + hardware.gpgSmartcards.enable = true; + networking.firewall.interfaces."tailscale0".allowedTCPPorts = [ 35963 ] ; environment.systemPackages = with pkgs; [ aerc diff --git a/modules/module-list.nix b/modules/module-list.nix index 87ada48c..8a85749e 100644 --- a/modules/module-list.nix +++ b/modules/module-list.nix @@ -18,6 +18,7 @@ ./presets/cli.nix ./presets/common.nix ./presets/gui.nix + ./presets/server.nix ./presets/home-manager.nix ./services/authentik.nix ./services/caddy.nix diff --git a/modules/presets/cli.nix b/modules/presets/cli.nix index ab822df6..f6ea3e09 100644 --- a/modules/presets/cli.nix +++ b/modules/presets/cli.nix @@ -38,11 +38,11 @@ in nix.settings = { substituters = [ - "https://cache.lix.systems" + # "https://cache.lix.systems" "https://helix.cachix.org" ]; trusted-public-keys = [ - "cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o=" + # "cache.lix.systems:aBnZUw8zA7H35Cz2RyKFVs3H4PlGTLawyY5KRbvJR8o=" "helix.cachix.org-1:ejp9KQpR1FBI2onstMQ34yogDm4OgU2ru6lIwPvuCVs=" ]; trusted-users = lib.mkDefault [ diff --git a/modules/presets/common.nix b/modules/presets/common.nix index b113807b..97525f05 100644 --- a/modules/presets/common.nix +++ b/modules/presets/common.nix @@ -28,10 +28,6 @@ in # ]; }); security.polkit.extraConfig = '' - polkit.addRule(function(action, subject) { - polkit.log("action=" + action); - polkit.log("subject=" + subject); -}); polkit.addRule(function(action, subject) { // make run0 keep pw for some time (tm) if ( subject.isInGroup("wheel") diff --git a/modules/presets/server.nix b/modules/presets/server.nix index e4606b35..f34cc249 100644 --- a/modules/presets/server.nix +++ b/modules/presets/server.nix @@ -6,22 +6,56 @@ }: let cfg = config.xyno.presets.server; + msmtpConfigItems = [ + "host" + "port" + "from" + "user" + "password" + + ]; in { options.xyno.presets.server.enable = lib.mkEnableOption "enables xynos base server config (ssh/smart/email/zed/...)"; config = lib.mkIf cfg.enable { services.openssh.enable = true; - users.users.root.openssh.authorizedKeys.keys = ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID/oMAi5jyQsNohfhcSH2ItisTpBGB0WtYTVxJYKKqhj"]; # theseus + users.users.root.openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID/oMAi5jyQsNohfhcSH2ItisTpBGB0WtYTVxJYKKqhj" + ]; # theseus environment.etc."msmtprc".enable = false; - sops.secrets."msmtp/rc" = { + sops.defaultSopsFile = ../../secrets/common.yaml; + sops.secrets = lib.mkMerge ( + [ + { + "msmtp/aliases" = { + path = "/etc/aliases"; + }; + } + ] + ++ (map (x: { "msmtp/${x}" = { }; }) msmtpConfigItems) + ); + sops.templates."msmtprc" = { path = "/etc/msmtprc"; + content = '' + defaults + allow_from_override off + set_from_header on + auth on + tls on + tls_starttls off + + account default + ${lib.concatStringsSep "\n" ( + map (x: "${x} ${config.sops.placeholder."msmtp/${x}"}") msmtpConfigItems + )} + auth on + + aliases /etc/aliases + ''; }; - sops.secrets."msmtp/aliases" = { - path = "/etc/aliases"; - }; - + programs.msmtp = { enable = true; }; diff --git a/modules/services/authentik.nix b/modules/services/authentik.nix index cdc57d99..fc951d97 100644 --- a/modules/services/authentik.nix +++ b/modules/services/authentik.nix @@ -19,7 +19,7 @@ let }; groups = mkOption { type = types.listOf types.str; - default = []; + default = [ ]; }; meta_description = mkOption { type = types.nullOr types.str; @@ -47,7 +47,13 @@ let modules = [ ./authentik/provider.nix { - inherit (cfg) oauthApps ldapApps proxyApps; + inherit (cfg) + oauthApps + ldapApps + proxyApps + url + insecure + ; stateFile = "${terrraformStateDir}/state.tfstate"; } ]; @@ -89,6 +95,18 @@ in }) ); }; + options.xyno.services.authentik.url = mkOption { + type = types.str; + default = "https://auth.hailsatan.eu"; + }; + options.xyno.services.authentik.insecure = mkOption { + type = types.bool; + default = false; + }; + options.xyno.services.authentik.after = mkOption { + type = types.listOf types.str; + default = []; + }; config = lib.mkIf cfg.enable { environment.etc."authentik-config/config.tf.json".source = terranixConfig; xyno.impermanence.directories = [ @@ -98,13 +116,20 @@ in enable = true; createDatabase = true; environmentFile = config.sops.secrets."authentik/env".path; + settings = { + disable_startup_analytics = true; + }; }; + systemd.services.authentik.after = cfg.after; systemd.services.authentik-ldap.after = [ "authentik-config.service" ]; + systemd.services.authentik-ldap.environment.AUTHENTIK_LISTEN__METRICS = "[::1]:9302"; services.authentik-ldap = { environmentFile = "${environmentFileDir}/ldap_config"; enable = true; }; systemd.services.authentik-proxy.after = [ "authentik-config.service" ]; + systemd.services.authentik-proxy.environment.AUTHENTIK_LISTEN__HTTP = "[::1]:9001"; + systemd.services.authentik-proxy.environment.AUTHENTIK_LISTEN__METRICS = "[::1]:9301"; services.authentik-proxy = { enable = true; environmentFile = "${environmentFileDir}/proxy_config"; @@ -112,49 +137,80 @@ in systemd.services.authentik-config = { after = [ "authentik.service" ]; + wantedBy = [ "multi-user.target" ]; + wants = [ "network-online.target" ]; + before = [ + "authentik-ldap.service" + "authentik-proxy.service" + ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; - StateDirectory = terrraformStateDir; + EnvironmentFile = [ config.services.authentik.environmentFile ]; + Restart = "on-failure"; + RestartSec = 30; + StateDirectory = "authentik-config"; }; - script = '' - umask u=rw,go= - export PATH=$PATH:${pkgs.opentofu}/bin - cd terrraformStateDir - cp ${terranixConfig} ./main.tf.json - source ${config.services.authentik.environmentFile} - export AUTHENTIK_URL=http://localhost:9000 - export AUTHENTIK_TOKEN=$AUTHENTIK_BOOTSTRAP_TOKEN + script = + let + opentofu = pkgs.opentofu.withPlugins (p: [ + inputs.authentik.packages.${pkgs.system}.terraform-provider-authentik + ]); + in + '' + set -xeuo pipefail + umask u=rw,go= + export PATH=$PATH:${opentofu}/bin:${pkgs.curl}/bin + cd $STATE_DIRECTORY + cp ${terranixConfig} ./main.tf.json + export AUTHENTIK_URL=${cfg.url} + export AUTHENTIK_INSECURE=${toString cfg.insecure} + export AUTHENTIK_TOKEN=$AUTHENTIK_BOOTSTRAP_TOKEN - tofu init - tofu validate || exit 1 - tofu apply + tofu init + tofu validate || exit 1 - tofu output -raw proxy_config > ${environmentFileDir}/proxy_config - tofu output -raw ldap_config > ${environmentFileDir}/ldap_config - ${concatStringsSep "\n" ( - mapAttrsToList (n: v: "tofu output -raw ${n}_environment > ${v.environmentFile}") cfg.oauthApps - )} - ''; + while [[ "$(curl -L -s -o /dev/null -I -w "%{http_code}" ''${AUTHENTIK_URL}/api/v3/flows/instances/)" =~ (502|000) ]]; do + echo "[+] Authentik still starting, sleeping for 2s" + sleep 2 + done + + tofu apply -auto-approve + + tofu show -state + + mkdir ${environmentFileDir} + tofu output -show-sensitive -raw proxy_config > ${environmentFileDir}/proxy_config + cat ${environmentFileDir}/proxy_config + tofu output -show-sensitive -raw ldap_config > ${environmentFileDir}/ldap_config + ${concatStringsSep "\n" ( + mapAttrsToList ( + n: v: "tofu output -show-sensitive -raw ${n}_environment > ${v.environmentFile}" + ) cfg.oauthApps + )} + ''; }; sops.secrets."authentik/env" = { - + sopsFile = ../../instances/${config.networking.hostName}/secrets/authentik.yaml; }; services.caddy.extraConfig = '' (reverse_proxy_auth) { route { # always forward outpost path to actual outpost - reverse_proxy /outpost.goauthentik.io/* http://[::1]:9000 { + reverse_proxy /outpost.goauthentik.io/* http://[::1]:9001 { } - forward_auth http://[::1]:9000 { + forward_auth http://[::1]:9001 { uri /outpost.goauthentik.io/auth/caddy copy_headers X-Authentik-Username X-Copyparty-Group X-Authentik-Groups X-Authentik-Entitlements X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version X-Grafana-Role } reverse_proxy {args[:]} } ''; + xyno.services.monitoring.exporters.authentik = 9300; + xyno.services.monitoring.exporters.authentik-proxy = 9301; + xyno.services.monitoring.exporters.authentik-ldap = 9302; }; } diff --git a/modules/services/authentik/fakesops.yaml b/modules/services/authentik/fakesops.yaml new file mode 100644 index 00000000..5f6c484c --- /dev/null +++ b/modules/services/authentik/fakesops.yaml @@ -0,0 +1,2 @@ +authentik: + env: meow diff --git a/modules/services/authentik/provider.nix b/modules/services/authentik/provider.nix index 9def57f8..2cdbb216 100644 --- a/modules/services/authentik/provider.nix +++ b/modules/services/authentik/provider.nix @@ -6,6 +6,7 @@ let authorizationFlow = tfRef "data.authentik_flow.default-authorization-flow.id"; authenticationFlow = tfRef "data.authentik_flow.default-authentication-flow.id"; + invalidationFlow = tfRef "data.authentik_flow.default-provider-invalidation-flow.id"; genApp = provider: n: v: { protocol_provider = provider; slug = n; @@ -25,29 +26,34 @@ in oauthApps = mkOption { type = types.attrs; }; proxyApps = mkOption { type = types.attrs; }; ldapApps = mkOption { type = types.attrs; }; + url = mkOption { type = types.str; }; + insecure = mkOption { type = types.bool; }; }; config = { terraform.backend.local.path = config.stateFile; - provider.authentik = { }; + terraform.required_providers.authentik.source = "goauthentik/authentik"; data.authentik_flow."default-authorization-flow" = { slug = "default-provider-authorization-implicit-consent"; }; data."authentik_flow"."default-authentication-flow" = { slug = "default-authentication-flow"; }; + data."authentik_flow"."default-provider-invalidation-flow" = { + slug = "default-provider-invalidation-flow"; + }; resource.authentik_outpost.proxy = { name = "proxy"; type = "proxy"; protocol_providers = mapAttrsToList ( - n: v: (tfRef "authentik_provider_proxy.${n}.id") + n: v: (tfRef "resource.authentik_provider_proxy.${n}.id") ) config.proxyApps; }; resource.authentik_outpost.ldap = { name = "ldap"; type = "ldap"; protocol_providers = mapAttrsToList ( - n: v: (tfRef "authentik_provider_ldap.${n}.id") + n: v: (tfRef "resource.authentik_provider_ldap.${n}.id") ) config.ldapApps; }; @@ -55,6 +61,7 @@ in name = n; client_id = n; authorization_flow = authorizationFlow; + invalidation_flow = invalidationFlow; }) config.oauthApps; data.authentik_provider_oauth2_config = mapAttrs (n: v: { provider_id = tfRef "resource.authentik_provider_oauth2.${n}.id"; @@ -62,19 +69,23 @@ in resource.authentik_provider_proxy = mapAttrs (n: v: { name = n; - mode = "forward-single"; + mode = "forward_single"; external_host = v.externalHost; authorization_flow = authorizationFlow; + invalidation_flow = invalidationFlow; }) config.proxyApps; resource.authentik_provider_ldap = mapAttrs (n: v: { name = n; base_dn = "dc=ldap,dc=goauthentik,dc=io"; bind_flow = authenticationFlow; + unbind_flow = invalidationFlow; }) config.ldapApps; + output = (mapAttrs' ( n: v: nameValuePair ("${n}_environment") ({ + sensitive = true; value = let val = val: tfRef "resource.authentik_provider_oauth2.${n}.${val}"; @@ -90,10 +101,39 @@ in }) ) config.oauthApps) // { - proxy_config.value = tfRef "resource.authentik_outpost.proxy.config"; - ldap_config.value = tfRef "resource.authentik_outpost.ldap.config"; + proxy_config.sensitive = true; + proxy_config.value = '' + AUTHENTIK_HOST=http://localhost:9000 + AUTHENTIK_HOST_BROWSER=${config.url} + AUTHENTIK_TOKEN=${tfRef "resource.authentik_token.proxy_outpost.key"} + ''; + ldap_config.sensitive = true; + ldap_config.value = '' + AUTHENTIK_HOST=http://localhost:9000 + AUTHENTIK_HOST_BROWSER=${config.url} + AUTHENTIK_TOKEN=${tfRef "resource.authentik_token.ldap_outpost.key"} + ''; }; + data.authentik_user."proxy" = { + username = "ak-outpost-${tfRef ''replace(resource.authentik_outpost.proxy.id,"-","")''}"; + }; + data.authentik_user."ldap" = { + username = "ak-outpost-${tfRef ''replace(resource.authentik_outpost.ldap.id,"-","")''}"; + }; + resource.authentik_token."proxy_outpost" = { + identifier = "proxy-outpost-token"; + user = tfRef "data.authentik_user.proxy.id"; + expiring = false; + retrieve_key = true; + }; + resource.authentik_token."ldap_outpost" = { + identifier = "ldap-outpost-token"; + user = tfRef "data.authentik_user.ldap.id"; + expiring = false; + retrieve_key = true; + }; + resource.authentik_application = mkMerge [ (mapAttrs (n: v: genApp (tfRef "authentik_provider_oauth2.${n}.id") n v) config.oauthApps) (mapAttrs (n: v: genApp (tfRef "authentik_provider_proxy.${n}.id") n v) config.proxyApps) @@ -122,7 +162,7 @@ in let genEnts = apps: - lib.flatten ( + flatten ( mapAttrsToList ( n: v: (map (g: { @@ -135,10 +175,6 @@ in ) apps ); in - mkMerge [ - (genEnts config.oauthApps) - (genEnts config.proxyApps) - (genEnts config.ldapApps) - ]; + mkMerge ((genEnts config.oauthApps) ++ (genEnts config.proxyApps) ++ (genEnts config.ldapApps)); }; } diff --git a/modules/services/authentik/test.nix b/modules/services/authentik/test.nix new file mode 100644 index 00000000..f68b70e9 --- /dev/null +++ b/modules/services/authentik/test.nix @@ -0,0 +1,30 @@ +{ + name = "authentik"; + nodes.machine = {lib, config, pkgs, ...}: { + virtualisation = { + cores = 3; + memorySize = 2048; + }; + xyno.services.authentik = { + enable = true; + url = "http://[::1]:9000"; + oauthApps."app1".name = "app1-name"; + ldapApps."app2".name = "app2-name"; + proxyApps."app3".name = "app3-name"; + proxyApps."app3".externalHost = "https://test.example.org"; + }; + services.authentik.environmentFile = lib.mkForce "/etc/authentik-env"; + sops.defaultSopsFile = ../../../secrets/common.yaml; + environment.etc."authentik-env".text = '' + AUTHENTIK_SECRET_KEY=db6363ba033b111c6835489c5c0aca5ec192c20ee1ea3116a601065c3b118c3d + AUTHENTIK_BOOTSTRAP_TOKEN=75c041b7e79aac71ff0a74f7905c9f818ab2f0d21d8618fa5fd753f9e57a02f8 + ''; + sops.secrets."authentik/env" = lib.mkForce { sopsFile = ../../../instances/ds9/secrets/authentik.yaml; }; + }; + testScript = '' + machine.wait_for_unit("authentik-config.service") + print(machine.succeed("cat /run/authentik-terraform-config/app1_environment")) + machine.wait_for_unit("authentik-proxy.service") + machine.wait_for_unit("authentik-ldap.service") + ''; +} diff --git a/modules/services/caddy.nix b/modules/services/caddy.nix index 731c81b0..652d589e 100644 --- a/modules/services/caddy.nix +++ b/modules/services/caddy.nix @@ -57,16 +57,22 @@ in type = str; default = ""; }; - hosts = attrsOf (submodule { - options = { - extraConfig = mkOption { type = lines; }; - }; - }); + hosts = mkOption { + default = {}; + type = attrsOf (submodule { + options = { + extraConfig = mkOption { type = lines; }; + }; + }); + }; }; }); }; config = lib.mkIf cfg.enable { - networking.firewall.allowedTCPPorts = [ 80 443 ]; + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ]; networking.firewall.allowedUDPPorts = [ 443 ]; services.caddy = { enable = true; @@ -78,7 +84,6 @@ in metrics { per_host } - admin ${config.xyno.monitoring.ip}:2019 ''; extraConfig = '' (blockBots) { diff --git a/modules/services/wireguard.nix b/modules/services/wireguard.nix index 00ccd231..16481892 100644 --- a/modules/services/wireguard.nix +++ b/modules/services/wireguard.nix @@ -30,10 +30,10 @@ let (lib.optional (c?publicHostname) { # if peer is publicly on the internet AllowedIPs = - (lib.optionals (c.wg.server) [ + (lib.optionals ( c?wg.server && c.wg.server) [ "${ulaPrefix}::/48" # all traffic in the ula shall be sent to the server ]) - ++ (lib.optionals (!c.wg.server) [ + ++ (lib.optionals (!c?wg.server || !c.wg.server) [ "${genUlaForHost ulaPrefix c.hostName}/128" # if a host is reachable but shouldn't play server, send only to the hosts ip ]); Endpoint = "${c.publicHostname}:51820"; @@ -90,9 +90,15 @@ in name = (genUlaForHost monitoringUlaPrefix v.hostName); } ) instanceConfigs); - networking.firewall.allowedUDPPorts = lib.optional wgServer [ 51820 ]; - networking.firewall.interfaces."wg0".allowedUDPPorts = lib.optional wgServer [ 53 ]; + networking.firewall.allowedUDPPorts = lib.optional wgServer 51820; + networking.firewall.interfaces."wg0".allowedUDPPorts = lib.optional wgServer 53; systemd.network.netdevs."wg0" = { + netdevConfig = { + Name = "wg0"; + Kind = "wireguard"; + Description = "main wireguard tunnel"; + + }; wireguardConfig = { ListenPort = lib.mkIf wgServer 51820; PrivateKeyFile = config.sops.secrets."wg/privkey".path; # TODO diff --git a/modules/system/impermanence.nix b/modules/system/impermanence.nix index f237d363..ca725075 100644 --- a/modules/system/impermanence.nix +++ b/modules/system/impermanence.nix @@ -46,6 +46,7 @@ in "/var/log" "/var/lib/systemd/coredump" "/etc/ssh" # host keys + "/var/lib/sbctl" # lanzaboote ]; xyno.impermanence.user.directories = [ @@ -72,6 +73,7 @@ in ".local/share/direnv" ]; + sops.gnupg.sshKeyPaths = [ "/persistent/etc/ssh/ssh_host_rsa_key" ]; xyno.impermanence.cache.directories = [ "/var/cache" ]; xyno.impermanence.cache.user.directories = [ ".cache" ]; environment.persistence."/persistent" = genImpermanenceCfg cfg; diff --git a/modules/test-list.nix b/modules/test-list.nix new file mode 100644 index 00000000..22571545 --- /dev/null +++ b/modules/test-list.nix @@ -0,0 +1,3 @@ +[ + ./services/authentik/test.nix +] diff --git a/packages/caddy-desec.nix b/packages/caddy-desec.nix index 0b5a13e1..b62750e5 100644 --- a/packages/caddy-desec.nix +++ b/packages/caddy-desec.nix @@ -1,6 +1,6 @@ { lib, caddy, buildGoModule, stdenv, xcaddy, cacert, git, go, ... }: caddy.override { - buildGoModule = args: buildGoModule (args // { + buildGo125Module = args: buildGoModule (args // { src = stdenv.mkDerivation rec { pname = "caddy-using-xcaddy-${xcaddy.version}"; inherit (caddy) version; diff --git a/packages/fido2-hid-bridge.nix b/packages/fido2-hid-bridge.nix index 2941a846..83a7afca 100644 --- a/packages/fido2-hid-bridge.nix +++ b/packages/fido2-hid-bridge.nix @@ -22,7 +22,7 @@ python3Packages.buildPythonApplication rec { dependencies = [ python3Packages.poetry-core - python3Packages.fido2_2 + python3Packages.fido2 python3Packages.pyscard python-uhid python3Packages.flake8 diff --git a/secrets.md b/secrets.md deleted file mode 100644 index b07b5dd3..00000000 --- a/secrets.md +++ /dev/null @@ -1,11 +0,0 @@ -how should the secret generation thingamajig work: - -- read all systemd.service.$service.encrypedSecrets.NAME_OF_ENV_VAR -```nix -{ - systemd.services.meows.encrypedSecrets.MEOW = { - random = true; # grenerates 64 chars of random data - random = 20; # generates 20 chars of random data - }; # if random not set, expect age file at hosts/$host/secrets/$serviceName-$NAME_OF_ENV_VAR.age -} -``` diff --git a/secrets/common.yaml b/secrets/common.yaml new file mode 100644 index 00000000..0c72d97d --- /dev/null +++ b/secrets/common.yaml @@ -0,0 +1,66 @@ +victoriametrics: + basicAuthPassword: ENC[AES256_GCM,data:5QuhkQ344qDYzhGZBJimaX94C6oxgYBRZw4MSlycdgs6zRAudMIu/HF1gpjythQpait81jMpFhIn57w433s7QQ==,iv:gytJ63cBaJseCis7gEPmOX6LeddNloQsTjc1SnS56jo=,tag:Jn6TevGsBEeHxYmVHy896w==,type:str] +wg: + psk: ENC[AES256_GCM,data:Anpe6IxtzsqZyvas+ddV3yjJozdZgZOl2KG/Z4YtWUB5gAVLtxsQKc/WA/M=,iv:j/A5k2VXbdqUDXEd1WRfJYdb3DsUZ1B9gPHCpDpRjmw=,tag:KQGi1O5iP2+nQccgBzytSQ==,type:str] +msmtp: + host: ENC[AES256_GCM,data:YxiLT5t2H52IZvB02Pjntvg=,iv:nuMPI6fuvQ4U0+xj3SF27ZO/b2knKUsO6jCf9aJqQa4=,tag:9DucIq+LUozuPLL3s8UjDQ==,type:str] + port: ENC[AES256_GCM,data:zbe7,iv:cwoK0oCIzwmQ6xHFX94KDfd7Fu+pC96c9+AnK/KpQp4=,tag:IfsCHk0SpBeQ4bD0WXyQcw==,type:int] + from: ENC[AES256_GCM,data:QpUgsghc7e5OFJO8afzx6bt1,iv:ffrlbqFu2p5/uwv5MN9rf7iZSmfozYSwr3WkEvXNZhA=,tag:B3g+6WexBw6j6EgukX5LDg==,type:str] + user: ENC[AES256_GCM,data:H2OxJp6q1QCxBxIXThXrj+SU,iv:Cu7KFDaiqM0cuofnqkLnE6Zb6ufLw6wQRSk1pthDAAo=,tag:oM1VefUo9kK8k7lHKnxOjA==,type:str] + password: ENC[AES256_GCM,data:mAgsvDPzt8f/RB/2T8nrd+KUcuxUGIdCBDs5sFla5x0=,iv:qndiiKTuSpbf/gtNXPaZ6AnHHwzZ7IPJrDFriM7bKwE=,tag:5j+gjpaxIu03x1lBkRMLhQ==,type:str] + aliases: ENC[AES256_GCM,data:fOZRYZ8rVs3IXhiS+VaP54gF4bir66oIZvb7ZfKV,iv:bsmh1ZCwERZuHrvORP68hj5Gz7j3+K6ZW8BR3/IQVQg=,tag:jWozmXpjk3JHCINSgP4KGg==,type:str] +sops: + lastmodified: "2025-09-06T16:50:17Z" + mac: ENC[AES256_GCM,data:QdWLok9IBqTaO3StKRiAXcMIZSV5YJQoYY+3cZZ7xARbmvn5cDqnapv3HIJju7v5V48tNG3aXy1nJHG4kKVuDIMd7s7PPjLL1k0dEsnTs4YwE8XugZX86nXuSUZeUuQNfnR9sFOKho/o/I9W5hCp0IcEgo+Bs1dD3IvYxuv6Nzk=,iv:IHEDtI6lo76qPgBvBETg/SiT/tfFivN8r8J7tt93IbQ=,tag:ifW8UVaf5r8Y9HUUtCkAQQ==,type:str] + pgp: + - created_at: "2025-09-06T16:37:33Z" + enc: |- + -----BEGIN PGP MESSAGE----- + + hL4DAAAAAAAAAAASBAMEo8G+ATJBHsaSSDlUcbO8DIUVsdkQX89uewGyB6VB0bsl + PYyC465BriUoCYLuob8JFkVvHL1fkcRf4+EAZv9Zuqm05iOBEFxizRn2s9OXshfO + B58S3aWlCMPi40OT8zpdtABeKYH8FwVuG2y+JxFJgXZ1dyrT72QvqnIilaphMdkw + 8fTx8Z33q0Mr0Qpw9QViOYlGYH1noFdwtv37kxrBOGSibXLaux9yksvw2tR0iZbE + 0lwBffsODaWMDRpxKN/w5d/G+x6LD4T3kjJHo8pXfElPowLyYJVEg9xGxm5UZvTR + UpAKltoDQ5URiWMcHfFd9LlMqVzNC3I3hCdQdgyDhyypHjjKTRriUav5q9eXVw== + =eIGU + -----END PGP MESSAGE----- + fp: 0D98D5964AC8BB1CA034CE4EC456133700066642 + - created_at: "2025-09-06T16:37:33Z" + enc: |- + -----BEGIN PGP MESSAGE----- + + hQGMAwAAAAAAAAAAAQv/eHdSXzib4ebCSgYp+JklSTfhRpwk5dX+D+dgJyvz1TVI + eIuuCbKHMSGr9GJbyxhoZ9I0tZ3AL+vmYy4gKa3uQWrP/D1Zc4oZ8nYj4+saMD+W + OUmV+o0u7MMpGQqi5HSWGHyxCc+S+dT/14rYDPh2iPw15h5hCG43KlM6OoL2gG0a + 0HJ57y6DjzdCzJ66MDKeXSac7GI4lsf+8yimK1MvXtXJ3w6qxvY8Mar+k2QKrAT+ + QBAt22oJHz31X4xGeD9Ns4MJiEfYYRLgzh8INW0UTOi/2tSWvroFKRFJt9hZD4Ey + ar8yqSMp1GPEBUkluJPLcOACq3l4IExmqscp1QhhHp7m/+dJfEKq8Xf5WkBkeiiS + QnNowMDjbfdY/4Bwt2995AjDBYeU0w03Aw+wsMH81Zio/J4bbLIcQ7pO5cEpfT+R + ItC0f7DlLjKkQxvi9n2aYIWzDQA908yy1JIlk/UKqiH4x8ACtcp+9/HVu9Rv6sv+ + 6CWZcRLPL9C3bHlff5hV0lYBiGwXZVn5Vjgq+J08vyZth1e0EhjQTkyVFoek8uxS + kah0UxAcQA9978NYwyYdGPSq6eyZSf79ZwmB/KL9jCqV9CEGnVTBlEm46y9xCkMR + SeTVXQInPQ== + =ISty + -----END PGP MESSAGE----- + fp: fada7e7be28e186e463ad745a38d17f36849d8a7 + - created_at: "2025-09-06T16:37:33Z" + enc: |- + -----BEGIN PGP MESSAGE----- + + hQGMAwAAAAAAAAAAAQv9FqBlKRGJgVzJg9sWKdmqPnUVffGETE/0/qeI68hxzeUo + Axx1Ff3xjUSQYTUrLpVwHCOIT+3r1RtSMgZYIIMJsbPvffssTR9dJeE/BsCLvMLM + AbfNvPyoSKDi3cHQ4UoqGuy/GwTuXaWNM9ilBhdBDv87MfeC+UEkqXJ5gWjUu7uH + vS0LwcwmvikRBK7poES/i1kaRStvCIF2biOVYAzB9IMLt+sltsngZUtefVk1UuKi + sj9iTxFpfYfEoA0bA1YfUw//STqxvmlC8doYWH2TfIn93HNi74bZ5mFu2JDnY0pU + pfodbhY7ltPHqo+mOKvSVDtVrdQkOZyjI33wXcS8vyWxt0EVHH3kVtbWH80J0+pR + Tz72bpW1wUKXwCXg7gKfLJFJ5kGNUkARVw/tD1/ZzcFqJ9NJz1c4jdtvzWlYqRxG + XlcRcRCfZmlrV96QD9Ai2IdIj5IgLFcrOZehHvH2rXjVWqoThWK6gvn9irPGsurW + d+Se7fP8UWZMXPOTCQII0lYBuZfd3BFbe5Xfx9hW4vazWddbKFXakylSy4M8WSOq + nCKLNTMvinlb4QPWKGsDnQvlu4fMus1vINnvthphEs7dKBO0TQyoRZ0fO7hBiOUX + OKJvcyTUrA== + =qv0p + -----END PGP MESSAGE----- + fp: b730b2bf54eb792a14bfd3e68c14c08894376c5f + unencrypted_suffix: _unencrypted + version: 3.10.2 diff --git a/secrets/deploy-secrets.py b/secrets/deploy-secrets.py deleted file mode 100644 index 3bdf1f04..00000000 --- a/secrets/deploy-secrets.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python - -import subprocess -import sys -import argparse -import json - -parser = argparse.ArgumentParser() -parser.add_argument("flake") -parser.add_argument("-f", "--force", action='store_true') -args = parser.parse_args() - -NIX_OUTPUT_JSON_PATH = subprocess.run(["nix", "build", f"{args.flake}.config.xyno.secret-output", "--no-link") -HOSTNAME = subprocess.run(["nix", "eval", f"{args.flake}.config.networking.hostName", "--raw"]) - -nix_output_json - -with open(NIX_OUTPUT_JSON_PATH, "r") as f: - nix_output_json = json.load(f) - -def run_ssh(command): - return subprocess.run("ssh", HOSTNAME, command) - -def check_tpm(): - return run_ssh("systemd-analyze has-tpm2").returncode == 0 - -def push_secret(secret_name, secret_content): - - if !args.force && secret_name in run_ssh("systemd-creds list"): - print(f"[INFO] secret {secret_name} exists on target, skipping") - print(f"[INFO] run with --force to skip") - return - - command - if secret_content["random"] != null: - command = f"openssl rand -hex {secret_content["random"]} | systemd-creds encrypt - {secret_name}" - else if secret_content["ageFile"] != null: - secret_output = subprocess.run(["rage", "-d", secret_content["ageFile"]]) - command = f"echo '{secret_output}' | systemd-creds encrypt - {secret_name}" - else if secret_content["command"] != null: - secret_output = subprocess.run(["sh", "-c", secret_content["command"]]) - command = f"echo '{secret_output}' | systemd-creds encrypt - {secret_name}" - else: - print(f"[ERROR] no secret content set for {secret_name}: {secret_content}") - return - run_ssh(command) - - - -for secret_name, secret_content in nix_output_json: - push_secret(secret_name,secret_content) diff --git a/secrets/nixos-module.nix b/secrets/nixos-module.nix deleted file mode 100644 index 2382ab74..00000000 --- a/secrets/nixos-module.nix +++ /dev/null @@ -1,56 +0,0 @@ -{ - pkgs, - config, - lib, - ... -}: -with lib; -let - cfg = config.xyno.secrets; - json = builtins.toJSON cfg; - -in -{ - options.xyno.secret-output = lib.mkOption { - type = types.str; - }; - options.xyno.secrets = mkOption { - type = types.attrsOf ( - types.submodule { - options = { - random = mkOption { - type = types.nullOr types.int; - default = null; - description = '' - have the secret be a random hex string with n bytes - ''; - }; - ageFile = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - have the secret be a age encrypted file - ''; - }; - command = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - have the secret be the output of a command (impure grrrrr) - ''; - }; - }; - } - ); - }; - config = { - systemd.tpm2.enable = true; - boot.initrd.systemd.tpm2.enable = true; - # TODO: ensure secrets are loaded in activation script - - xyno.secret-output = pkgs.writeFile "xyno-secret.json" json; - environment.systemPackages = [ - pkgs.openssl # needed for random secrets - ]; - }; -} diff --git a/sops.nix b/sops.nix new file mode 100644 index 00000000..86386e9e --- /dev/null +++ b/sops.nix @@ -0,0 +1,36 @@ +{ + sops, + instanceConfigs, + writeScriptBin, + writeText, + lib, + ... +}: +with lib; +let + adminKeys = [ + "0D98D5964AC8BB1CA034CE4EC456133700066642" # xyno main gpg key + ]; + keysPerHost = (mapAttrs (n: v: (toList v.sopsKey)) ( + filterAttrs (n: v: v ? sopsKey) instanceConfigs + )); + hostKeys = flatten (attrValues keysPerHost); + + sopsCfg = { + keys = adminKeys ++ hostKeys; + creation_rules = [ + { + path_regex = "secrets/[^/]+\.(yaml|json|env|ini)$"; + key_groups = [ { pgp = adminKeys ++ hostKeys; } ]; + } + ] + ++ (mapAttrsToList (n: v: { + # path_regex = "instances/${n}/secrets/[^/]+\.(yaml|json|env|ini)$"; + path_regex = "instances/${n}/secrets/[^/]+\.(yaml|json|env|ini)$"; + key_groups = [ { pgp = adminKeys ++ v; } ]; + + }) keysPerHost); + }; + sopsCfgFile = writeText ".sops.yaml" (builtins.toJSON sopsCfg); + +in sopsCfgFile