authentik yay

This commit is contained in:
Lucy Hochkamp 2025-09-07 00:11:16 +02:00
parent d3a93fd115
commit f2fcbfb679
No known key found for this signature in database
34 changed files with 612 additions and 363 deletions

10
bin/import-server-gpg-pubkeys Executable file
View file

@ -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

126
flake.lock generated
View file

@ -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": {

View file

@ -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;
};
};
}

View file

@ -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";
}

View file

@ -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";
};
}

View file

@ -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;

View file

@ -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

View file

@ -17,6 +17,7 @@
configureTika = true;
enable = true;
database.createLocally = true;
domain = "paperless.hailsatan.eu";
exporter = {
enable = true;
directory = "/data/paperless-export";

View file

@ -1,83 +0,0 @@
{
config,
pkgs,
inputs,
lib,
...
}:
{
imports = [
(import "${inputs.mobile-nixos}/lib/configuration.nix" { device = "lenovo-krane"; })
./hardware-configuration.nix
# <mobile-nixos/examples/plasma-mobile/plasma-mobile.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;
}

View file

@ -1,4 +0,0 @@
{
modules = [ ./configuration.nix ];
hostName = "minos";
}

View file

@ -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;
}

View file

@ -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";
}

View file

@ -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";
};
}

View file

@ -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"
];
};
}

View file

@ -47,6 +47,8 @@
];
virtualisation.podman.enable = true;
services.vsmartcard-vpcd.enable = true;
hardware.gpgSmartcards.enable = true;
networking.firewall.interfaces."tailscale0".allowedTCPPorts = [ 35963 ] ;
environment.systemPackages = with pkgs; [
aerc

View file

@ -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

View file

@ -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 [

View file

@ -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")

View file

@ -6,21 +6,55 @@
}:
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" = {
path = "/etc/msmtprc";
};
sops.secrets."msmtp/aliases" = {
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
'';
};
programs.msmtp = {
enable = true;

View file

@ -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 = ''
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:${pkgs.opentofu}/bin
cd terrraformStateDir
export PATH=$PATH:${opentofu}/bin:${pkgs.curl}/bin
cd $STATE_DIRECTORY
cp ${terranixConfig} ./main.tf.json
source ${config.services.authentik.environmentFile}
export AUTHENTIK_URL=http://localhost:9000
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 output -raw proxy_config > ${environmentFileDir}/proxy_config
tofu output -raw ldap_config > ${environmentFileDir}/ldap_config
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 -raw ${n}_environment > ${v.environmentFile}") cfg.oauthApps
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;
};
}

View file

@ -0,0 +1,2 @@
authentik:
env: meow

View file

@ -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,8 +101,37 @@ 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 [
@ -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));
};
}

View file

@ -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")
'';
}

View file

@ -57,16 +57,22 @@ in
type = str;
default = "";
};
hosts = attrsOf (submodule {
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) {

View file

@ -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

View file

@ -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;

3
modules/test-list.nix Normal file
View file

@ -0,0 +1,3 @@
[
./services/authentik/test.nix
]

View file

@ -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;

View file

@ -22,7 +22,7 @@ python3Packages.buildPythonApplication rec {
dependencies = [
python3Packages.poetry-core
python3Packages.fido2_2
python3Packages.fido2
python3Packages.pyscard
python-uhid
python3Packages.flake8

View file

@ -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
}
```

66
secrets/common.yaml Normal file
View file

@ -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

View file

@ -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)

View file

@ -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
];
};
}

36
sops.nix Normal file
View file

@ -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