diff options
| author | adikro <adikro@disroot.org> | 2026-06-27 02:41:27 +0200 |
|---|---|---|
| committer | adikro <adikro@disroot.org> | 2026-06-27 02:41:27 +0200 |
| commit | 9b8f9a4bf5e13efe49ec101f127d0df3d7bb3cf3 (patch) | |
| tree | b857cd260647dea82b0c63367eef9fa18cd63b8d | |
| parent | 30f34740891096471b5663704fbbd9bf67ebe885 (diff) | |
revamped sanoid, syncoid and nfs
| -rw-r--r-- | flake.lock | 72 | ||||
| -rw-r--r-- | hosts/bibus-lab/disko.nix | 111 | ||||
| -rw-r--r-- | os/core/networking.nix | 23 | ||||
| -rw-r--r-- | os/srv/authelia.nix | 152 | ||||
| -rw-r--r-- | os/srv/backup.nix | 110 | ||||
| -rw-r--r-- | os/srv/cluster.nix | 16 | ||||
| -rw-r--r-- | os/srv/crowdsec.nix | 81 | ||||
| -rw-r--r-- | os/srv/default.nix | 4 | ||||
| -rw-r--r-- | os/srv/gaming.nix | 27 | ||||
| -rw-r--r-- | os/srv/headscale.nix | 40 | ||||
| -rw-r--r-- | os/srv/i2p.nix | 98 | ||||
| -rw-r--r-- | os/srv/lldap.nix | 52 | ||||
| -rw-r--r-- | os/srv/monero.nix | 88 | ||||
| -rw-r--r-- | os/srv/nfs.nix | 13 | ||||
| -rw-r--r-- | os/srv/nginx.nix | 2 | ||||
| -rw-r--r-- | os/srv/postgres.nix | 72 | ||||
| -rw-r--r-- | os/srv/redis.nix | 37 | ||||
| -rw-r--r-- | os/srv/restic.nix | 12 | ||||
| -rw-r--r-- | os/srv/wireguard.nix | 8 | ||||
| -rw-r--r-- | os/srv/zfs.nix | 48 |
20 files changed, 811 insertions, 255 deletions
@@ -374,11 +374,11 @@ ] }, "locked": { - "lastModified": 1782051614, - "narHash": "sha256-xBRAhYLEXcjp8hM2tkkTTLb6PWU7VDxDoogl25g7Ezs=", + "lastModified": 1782423922, + "narHash": "sha256-qPNd6lUohHP5gcJhqQ7rLV87RwIx0xYR2A4Frb9Zjc4=", "owner": "nix-community", "repo": "home-manager", - "rev": "d1ccd0721ec599866622665f3651e19e6e2d4c6a", + "rev": "5d320ab301cfaaca7d32514f13815d19d109f5f4", "type": "github" }, "original": { @@ -417,11 +417,11 @@ "spectrum": "spectrum" }, "locked": { - "lastModified": 1781738058, - "narHash": "sha256-wgKY6pbZbFpBXae+8bjvJtW1Z9qekZergGly44n2qZw=", + "lastModified": 1782324740, + "narHash": "sha256-EpaYlgijQUv8nvbhMStQEFoO7aDWxJmVTOlsoHWqHpg=", "owner": "microvm-nix", "repo": "microvm.nix", - "rev": "225b35c204e29efb5bbe9b55b1a38b07b3fca2af", + "rev": "49a3e9fe33d33f189d24dafca36096766faa60ad", "type": "github" }, "original": { @@ -492,11 +492,11 @@ "xwayland-satellite-unstable": "xwayland-satellite-unstable" }, "locked": { - "lastModified": 1781795508, - "narHash": "sha256-VKrApQ3WCkEe9D8DbaeFjGqLAh7zqYGYjbQYtY5ikxc=", + "lastModified": 1782333733, + "narHash": "sha256-QYrNYMNPKErRgNlxWwk0cjNKftnq6WzSs84pcZnUskM=", "owner": "sodiboo", "repo": "niri-flake", - "rev": "493ce1e33e72f86312584f331c8cf52b3432ec99", + "rev": "a6351044a3d69877d1c23be54971d18f8531c930", "type": "github" }, "original": { @@ -543,11 +543,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1781622756, - "narHash": "sha256-JrPh4M6S7aPsEE9tOENuZrxC6o2szSLlK+t4+nLke9s=", + "lastModified": 1782379505, + "narHash": "sha256-zPvPiU+a7pqtH47xrtZLNRABJKpOjfZQclDbcvNtH+I=", "owner": "NixOS", "repo": "nixos-hardware", - "rev": "08018c72174a4df5657f8d94178ac69fb9c243e5", + "rev": "603d3afd1b6145bd66e97ae38a34d91c95df70cf", "type": "github" }, "original": { @@ -614,11 +614,11 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1781509190, - "narHash": "sha256-uJZs9Di8I6ciTp6jiojj0HzlNpBkud8ax5aT/O5aJkw=", + "lastModified": 1782188297, + "narHash": "sha256-imdcA5fgbHK259bhHlyiiSr7bMY1AZ6onOWDdAcydc4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "d6df3513510aa548c83868fd22bfddd0a8c0a0d4", + "rev": "9a1a7dbb18f0eb31c49b031babb8def7eab0af54", "type": "github" }, "original": { @@ -630,11 +630,11 @@ }, "nixpkgs-stable_2": { "locked": { - "lastModified": 1781216227, - "narHash": "sha256-9mUW6gNwoN2SWc/l0fW4svPNOulXLl8ijqKyeSOGgJE=", + "lastModified": 1782233679, + "narHash": "sha256-QyuGP5+QOtmXpy4i2X4DhBVBaySBdDKQEhqKcphcp34=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "a0374025a863d007d98e3297f6aa46cc3141c2f0", + "rev": "667d5cf1c59585031d743c78b394b0a647537c35", "type": "github" }, "original": { @@ -698,11 +698,11 @@ "systems": "systems_2" }, "locked": { - "lastModified": 1782062554, - "narHash": "sha256-v2J6/S33H2ms6jz3qr6in0UUlGFqUW46+iB3hMJDuD4=", + "lastModified": 1782254890, + "narHash": "sha256-kjsEECqhpPnJWqhooXp6tWh2qGQftCPAo2G1GvZtKdw=", "owner": "nix-community", "repo": "nixvim", - "rev": "b3e7b2d2e568f29becae04217242ed18a90febc4", + "rev": "dbf9550dba8448b03e11d58e5695d6c44a464554", "type": "github" }, "original": { @@ -722,11 +722,11 @@ "systems": "systems_3" }, "locked": { - "lastModified": 1781997110, - "narHash": "sha256-6D6xtYN5t1kZGNd69eMZsRBkgX5Df1roErn/kFR1C+A=", + "lastModified": 1782369036, + "narHash": "sha256-jxbvrIvE+NklSd6HPNSdEhGr8RvwNj4b7Gd5tgEXwSQ=", "owner": "NotAShelf", "repo": "nvf", - "rev": "320f60b97075a58d38b90fc5e39f478421dbd38a", + "rev": "096045d0e927bf7064989e9181a89b47c1b8779c", "type": "github" }, "original": { @@ -909,11 +909,11 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1781902199, - "narHash": "sha256-VD/bm9ZinziQdfUZDeTXd4H+T+TQ5WHwWXK9FpOniUs=", + "lastModified": 1782333283, + "narHash": "sha256-57ycRZHQkootKokT5VDSVZIyeGGaq05G7i2iqh1NApI=", "owner": "gabm", "repo": "Satty", - "rev": "32b2be3618a5617b196942b8fc023f998b44beca", + "rev": "26848045f3565cb05f6c18ad9e0d8ca5b3a7e1c1", "type": "github" }, "original": { @@ -929,11 +929,11 @@ ] }, "locked": { - "lastModified": 1781157498, - "narHash": "sha256-gDNHztsHGFAmbbj7Gcu8vWcFU5+4c1EeGU4lhb7Hnqo=", + "lastModified": 1782389855, + "narHash": "sha256-LhalI4N/bv20fvi0ag+f6ESWLS5VbOdzJKLoEGnJDMk=", "owner": "AceSLS", "repo": "SLSsteam", - "rev": "981da676e76f72b1ed3c387f192509ac9a1b91e4", + "rev": "ceb07e711cc0e831b2851236b46629827f87bbc4", "type": "github" }, "original": { @@ -972,11 +972,11 @@ ] }, "locked": { - "lastModified": 1781943681, - "narHash": "sha256-NFHmA7H47adqiyp+0iEOyZOQhmigDqA/NBAlf4imB6U=", + "lastModified": 1782165805, + "narHash": "sha256-478kKQBvK6SYTOdN2h9jhKJv94nbXRbFMfuL1WshErg=", "owner": "Mic92", "repo": "sops-nix", - "rev": "420f8d2e9882911f65cfac15cc706f639ba96cca", + "rev": "56b24064fdcaedca53553b1a6d607fd23b613a24", "type": "github" }, "original": { @@ -1155,11 +1155,11 @@ "rust-overlay": "rust-overlay_2" }, "locked": { - "lastModified": 1781971032, - "narHash": "sha256-lxliQTpjaN1iF2ntK2gJ4UO55HM4w47Hcqwe6gBo85o=", + "lastModified": 1782458355, + "narHash": "sha256-qa+ReXlH0m+5SZrmUKWK3xAri4qE45M8FcmM4L7VC5s=", "owner": "sxyazi", "repo": "yazi", - "rev": "4f45ddb514c3db558da0c5fffabaaa44f18cc18e", + "rev": "bf1274315dbcef858b46a55f212cfa34b916c3d3", "type": "github" }, "original": { diff --git a/hosts/bibus-lab/disko.nix b/hosts/bibus-lab/disko.nix index 5d0f0b8..6ca17b9 100644 --- a/hosts/bibus-lab/disko.nix +++ b/hosts/bibus-lab/disko.nix @@ -2,7 +2,8 @@ disko.devices = { main = { type = "disk"; - device = "/dev/disk/by-id/"; + # TODO fill id + device = "/dev/disk/by-id/CHANGEME"; content = { type = "gpt"; partitions = { @@ -10,7 +11,7 @@ size = "2G"; type = "EF00"; content = { - type = "flesystem"; + type = "filesystem"; format = "vfat"; mountpoint = "/boot"; }; @@ -27,7 +28,8 @@ }; hdd1 = { type = "disk"; - device = "/dev/disk/by-id/"; + # TODO fill id + device = "/dev/disk/by-id/CHANGEME"; content = { type = "gpt"; partitions = { @@ -43,7 +45,8 @@ }; hdd2 = { type = "disk"; - device = "/dev/disk/by-id/"; + # TODO fill id + device = "/dev/disk/by-id/CHANGEME"; content = { type = "gpt"; partitions = { @@ -59,7 +62,8 @@ }; hdd3 = { type = "disk"; - device = "/dev/disk/by-id/"; + # TODO fill id + device = "/dev/disk/by-id/CHANGEME"; content = { type = "gpt"; partitions = { @@ -80,11 +84,11 @@ datasets = { "rpool" = { type = "zfs_fs"; - options.mountpoint = "none"; - encryption = "aes-256-gcm"; - keyformat = "raw"; - keylocation = "file:///mnt/zroot.key"; options = { + encryption = "on"; + keyformat = "passphrase"; + keylocation = "prompt"; + mountpoint = "none"; compression = "zstd"; atime = "off"; }; @@ -92,10 +96,12 @@ "rpool/root" = { type = "zfs_fs"; mountpoint = "/"; + options.mountpoint = "legacy"; }; "rpool/nix" = { type = "zfs_fs"; mountpoint = "/nix"; + options.mountpoint = "legacy"; }; "rpool/home" = { type = "zfs_fs"; @@ -104,32 +110,61 @@ "rpool/log" = { type = "zfs_fs"; mountpoint = "/var/log"; + options.mountpoint = "legacy"; }; - "rpool/var/systemd" = { + "rpool/var" = { type = "zfs_fs"; - mountpoint = "/var/lib/systemd"; + options.mountpoint = "none"; }; "rpool/var/acme" = { type = "zfs_fs"; mountpoint = "/var/lib/acme"; }; - "rpool/docker" = { + "rpool/containers" = { type = "zfs_fs"; mountpoint = "/var/lib/containers"; }; - "rpool/appdata/configs" = { + "rpool/appdata" = { type = "zfs_fs"; - mountpoint = "/var/lib/appdata/configs"; + options.mountpoint = "none"; }; - "rpool/appdata/databases" = { + "rpool/appdata/cfg" = { type = "zfs_fs"; - mountpoint = "/var/lib/appdata/databases"; - options.recordsize = "16K"; + mountpoint = "/var/lib/appdata/cfg"; + }; + "rpool/appdata/db" = { + type = "zfs_fs"; + mountpoint = "/var/lib/appdata/db"; + options.canmount = "off"; + }; + "rpool/appdata/db/postgres" = { + type = "zfs_fs"; + mountpoint = "/var/lib/appdata/db/postgres"; + options = { + recordsize = "8K"; + logbias = "latency"; + }; + }; + "rpool/appdata/db/couchdb" = { + type = "zfs_fs"; + mountpoint = "/var/lib/appdata/db/couchdb"; + options.recordsize = "64K"; + }; + "rpool/appdata/db/redis" = { + type = "zfs_fs"; + mountpoint = "/var/lib/appdata/db/redis"; + options = { + recordsize = "128K"; + compression = "lz4"; + }; }; "rpool/appdata/monero" = { type = "zfs_fs"; mountpoint = "/var/lib/monero"; - options.recordsize = "8K"; + options = { + compression = "off"; + recordsize = "8K"; + }; }; "rpool/appdata/mail" = { type = "zfs_fs"; @@ -154,10 +189,10 @@ "ztank" = { type = "zfs_fs"; mountpoint = "none"; - encryption = "aes-256-gcm"; - keyformat = "raw"; - keylocation = "file:///mnt/ztank.key"; options = { + encryption = "on"; + keyformat = "passphrase"; + keylocation = "prompt"; compression = "zstd"; atime = "off"; }; @@ -173,39 +208,39 @@ "ztank/vault" = { type = "zfs_fs"; mountpoint = "/data/vault"; + options.xattr = "sa"; }; - "ztank/vault/seafile" = { + "ztank/seafile" = { type = "zfs_fs"; - mountpoint = "/data/vault/seafile"; - options.recordsize = "1M"; + mountpoint = "none"; + options.recordsize = "128K"; }; - "ztank/vault/seafile/personal" = { + "ztank/seafile/personal" = { type = "zfs_fs"; - mountpoint = "/data/vault/seafile/personal"; + mountpoint = "/data/seafile/personal"; }; - "ztank/vault/seafile/shared" = { + "ztank/seafile/shared" = { type = "zfs_fs"; - mountpoint = "/data/vault/seafile/shared"; + mountpoint = "/data/seafile/shared"; refquota = "1T"; }; - "ztank/downloads/active" = { + "ztank/dl" = { type = "zfs_fs"; - mountpoint = "/data/downloads/active"; - options.recordsize = "16K"; + options.mountpoint = "none"; }; - "ztank/downloads/complete" = { + "ztank/dl/active" = { type = "zfs_fs"; - mountpoint = "/data/downloads/complete"; - options.recordsize = "1M"; + mountpoint = "/data/dl/active"; + options.recordsize = "16K"; }; - "ztank/cctv" = { + "ztank/dl/complete" = { type = "zfs_fs"; - mountpoint = "/data/cctv"; + mountpoint = "/data/dl/complete"; options.recordsize = "1M"; }; - "ztank/backups" = { + "ztank/backup" = { type = "zfs_fs"; - mountpoint = "/data/backups"; + mountpoint = "/data/backup"; options.recordsize = "1M"; }; }; diff --git a/os/core/networking.nix b/os/core/networking.nix index 638ecd4..b94b540 100644 --- a/os/core/networking.nix +++ b/os/core/networking.nix @@ -21,18 +21,19 @@ in ips = lib.mkOption { type = lib.types.attrsOf lib.types.str; default = rec { - router = vm1-opnsense; + router = opnsense-vm; host = "10.0.0.2"; - vm1-opnsense = "10.0.0.1"; - vm2-gateway = "10.0.0.3"; - vm3-monitor = "10.0.0.4"; - vm4-media = "10.0.0.5"; - vm5-sandbox = "10.0.0.6"; - vm6-storage = "10.0.0.7"; - vm7-web = "10.0.0.8"; - vm8-mail = "10.0.0.9"; - vm9-relays = "10.0.0.10"; - vm10-mc = "10.0.0.11"; + opnsense-vm = "10.0.0.1"; + gateway-vm = "10.0.0.3"; + databse-vm = "10.0.0.4"; + monitor-vm = "10.0.0.5"; + media-vm = "10.0.0.6"; + sandbox-vm = "10.0.0.7"; + storage-vm = "10.0.0.8"; + web-vm = "10.0.0.9"; + mail-vm = "10.0.0.10"; + relay-vm = "10.0.0.11"; + gameserver-vm = "10.0.0.12"; }; description = "Central registry of static IP allocations for the cluster."; }; diff --git a/os/srv/authelia.nix b/os/srv/authelia.nix index 52b7114..2c42b0a 100644 --- a/os/srv/authelia.nix +++ b/os/srv/authelia.nix @@ -2,48 +2,146 @@ config, lib, masterDomain, + securityTemplates, ... }: let cfg = config.os.srv.authelia; + computedBaseDN = lib.concatStringsSep "," ( + map (domainPart: "dc=${domainPart}") (lib.splitString "." masterDomain) + ); in { - options.os.srv.authelia = { - enable = lib.mkEnableOption "enables authelia scanning"; - extraRules = lib.mkOption { - type = lib.types.listOf lib.types.attrs; - default = [ ]; - description = "Additional access control rules to be appended to Authelia."; - }; - }; + options.os.srv.authelia.enable = + lib.mkEnableOption "enables authelia authentication gateway instance"; + config = lib.mkIf cfg.enable { assertions = [ { assertion = config.os.srv.sops.enable; - message = "Required for password secure password storing"; + message = "sops must be enabled for secure cryptographic token storage"; } { - assertion = config.os.srv.lldap.enable; - message = "required for user accounts"; + assertion = config.os.core.network.enableFirewall; + message = "Requires firewall"; } ]; + + sops.secrets = { + "authelia/jwt_secret" = { + owner = "authelia-main"; + group = "authelia-main"; + restartUnits = [ "authelia-main.service" ]; + }; + "authelia/session_secret" = { + owner = "authelia-main"; + group = "authelia-main"; + restartUnits = [ "authelia-main.service" ]; + }; + "authelia/encryption_key" = { + owner = "authelia-main"; + group = "authelia-main"; + restartUnits = [ "authelia-main.service" ]; + }; + + "authelia/oidc_hmac" = { + owner = "authelia-main"; + group = "authelia-main"; + restartUnits = [ "authelia-main.service" ]; + }; + "authelia/oidc_private_key" = { + owner = "authelia-main"; + group = "authelia-main"; + restartUnits = [ "authelia-main.service" ]; + }; + + "postgres/authelia_password" = { + owner = "authelia-main"; + group = "authelia-main"; + restartUnits = [ "authelia-main.service" ]; + }; + "redis/password" = { + owner = "authelia-main"; + group = "authelia-main"; + restartUnits = [ "authelia-main.service" ]; + }; + }; + services.authelia.instances.main = { enable = true; + secrets = { jwtSecretFile = config.sops.secrets."authelia/jwt_secret".path; - storageEncryptionKeyFile = config.sops.secrets."authelia/encryptionKey".path; + sessionSecretFile = config.sops.secrets."authelia/session_secret".path; + storageEncryptionKeyFile = config.sops.secrets."authelia/encryption_key".path; + + oidcHmacSecretFile = config.sops.secrets."authelia/oidc_hmac".path; + oidcIssuerPrivateKeyFile = config.sops.secrets."authelia/oidc_private_key".path; }; + settings = { theme = "dark"; + default_2fa_method = "totp"; + + log = { + level = "info"; + format = "json"; + path = "/var/log/authelia/authelia.log"; + keep_stdout = true; + }; + + server.address = "tcp://127.0.0.1:9091"; + + telemetry.metrics = { + enabled = true; + address = "tcp://127.0.0.1:9959"; + }; + + storage = { + postgres = { + host = config.os.core.network.ips.database-vm; + port = 5432; + database = "authelia"; + username = "authelia"; + timeout = "5s"; + schema = "public"; + }; + }; + + session = { + name = "authelia_session"; + expiration = "1h"; + inactivity = "15m"; + remember_me = "1M"; + provider = { + redis = { + host = config.os.core.network.ips.database-vm; + port = 6379; + database = 0; + timeout = "5s"; + }; + }; + }; + authentication_backend = { ldap = { - address = "ldap://127.0.0.1:3890"; + address = "ldap://${config.os.core.network.ips.gateway-vm}:3890"; implementation = "lldap"; - base_dn = "dc=example,dc=com"; - user = "uid=authelia,ou=people,dc=example,dc=com"; - password_file = config.sops.secrets."lldap/bind_password".path; + base_dn = computedBaseDN; + user = "uid=authelia,ou=people,${computedBaseDN}"; }; }; + + identity_providers = { + oidc = { + cors.allowed_origins = map (domain: "https://${domain}") ( + builtins.attrNames config.os.cluster.nginxProxies + ); + + clients = config.os.cluster.oidcClients; + }; + }; + access_control = { default_policy = "deny"; rules = [ @@ -52,10 +150,30 @@ in policy = "bypass"; } ] - ++ cfg.extraRules; + ++ config.os.cluster.autheliaRules; }; + session.domain = masterDomain; }; + + environmentVariables = { + AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE = config.sops.secrets."lldap/password".path; + AUTHELIA_SESSION_REDIS_PASSWORD_FILE = config.sops.secrets."redis/password".path; + AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE = config.sops.secrets."postreg/authelia_password".path; + }; + }; + + os.cluster.nginxProxies."auth.${masterDomain}" = { + enableACME = true; + forceSSL = true; + locations."/" = { + proxyPass = "http://${config.os.core.network.ips.gateway-vm}:9091"; + extraConfig = securityTemplates.restrictToInternal; + }; }; + + networking.firewall.extraInputRules = '' + ip saddr ${config.os.core.network.ips.monitor-vm} tcp dport 9959 accept + ''; }; } diff --git a/os/srv/backup.nix b/os/srv/backup.nix index dad9b66..3d1d583 100644 --- a/os/srv/backup.nix +++ b/os/srv/backup.nix @@ -1,32 +1,94 @@ -{ config, lib, ... }: +{ + config, + lib, + pkgs, + ... +}: let - cfg = config.os.srv.backup; + cfg = config.os.srv.replication; + pgLockScript = pkgs.writeScriptBin "pg-lock" '' + #!/bin/sh + microvm -s database-vm -- sudo -u postgres psql -c "SELECT pg_backup_start('sanoid_snap');" + ''; + + pgUnlockScript = pkgs.writeScriptBin "pg-unlock" '' + #!/bin/sh + microvm -s database-vm -- sudo -u postgres psql -c "SELECT pg_backup_stop();" + ''; in { - options.os.srv.backup.enable = lib.mkEnableOption "enables backups"; + options.os.srv.replication.enable = lib.mkEnableOption "enables replications"; config = lib.mkIf cfg.enable { - services.sanoid = { - enable = true; - templates.production = { - hourly = 36; - daily = 30; - monthly = 3; - }; - datasets."zroot/rpool/appdata/databases".useTemplate = [ "production" ]; - datasets."ztank/vault".useTemplates = [ "production" ]; - }; - services.syncoid = { - enable = true; - commands = { - "sync-db" = { - source = "zroot/rpool/appdata/databases"; - target = "ztank/backups/nvme/databases"; - sendOptions = "w"; + services = { + sanoid = { + enable = true; + templates.production = { + autosnap = true; + autoprune = true; + hourly = 24; + daily = 7; + weekly = 4; + monthly = 3; }; - "sync-configs" = { - source = "zroot/rpool/appdata/configs"; - target = "ztank/backups/nvme/configs"; - sendOptions = "w"; + datasets = { + "zroot/rpool/appdata/db/postgres" = { + useTemplate = [ "production" ]; + + pre_snapshot_script = "${pgLockScript}/bin/pg-lock"; + post_snapshot_script = "${pgUnlockScript}/bin/pg-unlock"; + no_inconsistent_snapshot = true; + force_post_snapshot_script = true; + script_timeout = 30; + }; + + "zroot/rpool/appdata/db/redis".useTemplate = [ "production" ]; + + "zroot/rpool/appdata/db/couchdb".useTemplate = [ "production" ]; + + "zroot/rpool/appdata/cfg".useTemplate = [ "production" ]; + + "zroot/rpool/appdata/games".useTemplate = [ "production" ]; + + "zroot/rpool/appdata/mail".useTemplate = [ "production" ]; + + "zroot/rpool/containers".useTemplate = [ "production" ]; + }; + }; + + syncoid = { + enable = true; + commonArgs = [ + "-w" + "--delete-target-snapshots" + "--use-hold" + "--no-sync-snap" + ]; + commands = { + "sync-databases" = { + source = "zroot/rpool/appdata/db"; + target = "tank/ztank/backup/nvme/db"; + recursive = true; + }; + + "sync-config" = { + source = "zroot/rpool/appdata/cfg"; + target = "tank/ztank/backup/nvme/cfg"; + }; + + "sync-games" = { + source = "zroot/rpool/appdata/games"; + target = "tank/ztank/backup/nvme/games"; + }; + + "sync-mail" = { + source = "zroot/rpool/appdata/mail"; + target = "tank/ztank/backup/nvme/mail"; + }; + + "sync-docker" = { + source = "zroot/rpool/containers"; + target = "tank/ztank/backup/nvme/containers"; + }; }; }; }; diff --git a/os/srv/cluster.nix b/os/srv/cluster.nix new file mode 100644 index 0000000..6e54ee2 --- /dev/null +++ b/os/srv/cluster.nix @@ -0,0 +1,16 @@ +{ lib, ... }: { + options.os.cluster = { + nginxProxies = lib.mkOption { + type = lib.types.attrsOf lib.types.attrs; + default = { }; + }; + autheliaRules = lib.mkOption { + type = lib.types.listOf lib.types.attrs; + default = [ ]; + }; + oidcClients = lib.mkOption { + type = lib.types.listOf lib.types.attrs; + default = [ ]; + }; + }; +} diff --git a/os/srv/crowdsec.nix b/os/srv/crowdsec.nix index 79c8718..71818bd 100644 --- a/os/srv/crowdsec.nix +++ b/os/srv/crowdsec.nix @@ -5,6 +5,9 @@ in { options.os.srv.security.crowdsec = { enable = lib.mkEnableOption "enables CrowdSec collaborative intrusion prevention"; + + aggregator.enable = lib.mkEnableOption "this node acting as a central LAPI aggregator for the network"; + agent.enable = lib.mkEnableOption "local log parsing and threat intelligence generation on this node"; }; config = lib.mkIf cfg.enable { @@ -13,66 +16,104 @@ in assertion = config.networking.nftables.enable; message = "CrowdSec requires networking.nftables to be enabled for blocking."; } + { + assertion = cfg.agent.enable || cfg.aggregator.enable; + message = "You must enable at least one CrowdSec role: 'agent.enable' or 'aggregator.enable'."; + } ]; services.crowdsec = { enable = true; autoUpdateService = true; + openFirewall = cfg.aggregator.enable; + + settings = { + api.server.enable = cfg.aggregator.enable; + lapi.client.api_url = "http://${config.os.core.network.ips.gateway-vm}:8080"; + }; + + hub = lib.mkIf cfg.agent.enable { + collections = [ + "crowdsecurity/linux" + "crowdsecurity/nginx" + "crowdsecurity/authelia" + "crowdsecurity/sshd" + ]; + }; + localConfig = { - acquisitions = [ + acquisitions = lib.mkIf cfg.agent.enable [ { source = "journalctl"; journalctl_filter = [ "_SYSTEMD_UNIT=sshd.service" ]; labels.type = "syslog"; } { - filenames = [ - "/var/log/nginx/access.log" - "/var/log/nginx/error.log" - ]; + source = "file"; + filenames = [ "/var/log/nginx/*.log" ]; labels.type = "nginx"; } + { + source = "file"; + filenames = [ "/var/log/authelia/authelia.log" ]; + labels.type = "authelia"; + } ]; - parsers.s02Enrich = [ + parsers.s02Enrich = lib.mkIf cfg.agent.enable [ { name = "myips/whitelist"; description = "Prevent local address ranges from triggering bans"; whitelist = { reason = "Internal private subnets"; cidr = [ - "10.0.0.0/16" + "10.0.0.0/24" + "10.1.0.0/24" + "10.3.0.0/24" + "10.4.0.0/24" ]; }; } ]; - }; - hub = { - collections = [ - "crowdsecurity/linux" - "crowdsecurity/nginx" - "crowdsecurity/sshd" + notifications = lib.mkIf cfg.aggregator.enable [ + { + name = "ntfy_alerts"; + type = "http"; + method = "POST"; + #TODO add ntfy sops thing + url = "https://ntfy.sh/your_secret_topic_here"; + headers = { + Title = "CrowdSec Alert on Bibus-Lab"; + Priority = "high"; + }; + format = '' + {{range .}} {{.Alert.Message}} (Scenario: {{.Alert.Scenario}}) from IP {{.Alert.Source.IP}} {{end}} + ''; + log_level = "info"; + } ]; }; - - settings = { - lapi.credentialsFile = "/var/lib/crowdsec/state/lapi.yaml"; - capi.credentialsFile = "/var/lib/crowdsec/state/capi.yaml"; - }; }; services.crowdsec-firewall-bouncer = { enable = true; + + registerBouncer.enable = cfg.aggregator.enable; + settings = { + mode = "nftables"; update_frequency = "10s"; + + api_url = "http://${config.os.core.network.ips.gateway-vm}:8080"; }; }; - users.users.crowdsec.extraGroups = [ - "nginx" + users.users.crowdsec.extraGroups = lib.mkIf cfg.agent.enable [ "systemd-journal" + "nginx" + "authelia-main" ]; }; } diff --git a/os/srv/default.nix b/os/srv/default.nix index 34aa179..073067d 100644 --- a/os/srv/default.nix +++ b/os/srv/default.nix @@ -5,6 +5,7 @@ ./backup.nix ./bluetooth.nix ./clamav.nix + ./cluster.nix ./compat.nix ./crowdsec.nix ./dns.nix @@ -26,7 +27,9 @@ ./ntopng.nix ./oci.nix ./omnisearch.nix + ./postgres.nix ./prometheus.nix + ./redis.nix ./scrutiny.nix ./simplex.nix ./sops.nix @@ -37,6 +40,7 @@ ./tor.nix ./ups.nix ./uptime-kuma.nix + ./vector.nix ./virtualization.nix ./wireguard.nix ./yggdrasil.nix diff --git a/os/srv/gaming.nix b/os/srv/gaming.nix index 36f2db5..730dcd2 100644 --- a/os/srv/gaming.nix +++ b/os/srv/gaming.nix @@ -30,22 +30,24 @@ in config = lib.mkMerge [ # --- PERFORMANCE & TOOLING --- (lib.mkIf cfg.tools.enable { - programs.gamescope = { - enable = true; - capSysNice = true; - }; + hardware.xone.enable = true; + programs = { + gamescope = { + enable = true; + capSysNice = true; + }; - programs.gamemode = { - enable = true; - enableRenice = true; - settings = { - general.renice = 10; + gamemode = { + enable = true; + enableRenice = true; + settings = { + general.renice = 10; + }; }; }; environment = { - # sets the optiscaler shortcut key to be home by default sessionVariables = { - OPTISCALER_ShortcutKey = "0x24"; + OPTISCALER_ShortcutKey = "0x24"; # sets the optiscaler shortcut key to be home by default }; systemPackages = with pkgs; [ @@ -61,10 +63,9 @@ in (lib.mkIf cfg.launchers.enable { environment.systemPackages = with pkgs; [ heroic - # (pkgs.bottles.override { removeWarningPopup = true; }) (prismlauncher.override { additionalLibs = with pkgs; [ ocl-icd ]; - jdks = with pkgs; [ javaPackages.compiler.temurin-bin.jdk-25 ]; + jdks = with pkgs; [ javaPackages.compiler.temurin-bin.jdk-26 ]; }) ]; }) diff --git a/os/srv/headscale.nix b/os/srv/headscale.nix index a650067..01fc06c 100644 --- a/os/srv/headscale.nix +++ b/os/srv/headscale.nix @@ -1,14 +1,46 @@ { config, lib, + pkgs, masterDomain, ... }: let cfg = config.os.srv.headscale; + aclPolicy = pkgs.writeText "headscale-policy.json" ( + builtins.toJSON { + groups = { + "group:admin" = [ "your-device-name" ]; + "group:friends" = [ "friend-device-name" ]; + }; + + hosts = { + "server" = "10.4.0.1"; + }; + + acls = [ + { + action = "accept"; + src = [ "group:admin" ]; + dst = [ "*:*" ]; + } + + { + action = "accept"; + src = [ "group:friends" ]; + dst = [ + "server:18080" + "server:18081" + "server:25565" + ]; + } + ]; + } + ); in { options.os.srv.headscale.enable = lib.mkEnableOption "enables headscales"; + config = lib.mkIf cfg.enable { services.headscale = { enable = true; @@ -18,14 +50,16 @@ in settings = { server_url = "https://vpn.${masterDomain}"; + policy.path = "${aclPolicy}"; + dns = { magic_dns = true; - base_domain = "vpn.internal"; - nameservers = [ "10.255.1.1" ]; + base_domain = "vpn"; + nameservers = [ config.os.core.network.ips.vm2-gateway ]; }; ip_prefixes = [ - "10.254.0.0/16" + "10.4.0.0/16" ]; }; }; diff --git a/os/srv/i2p.nix b/os/srv/i2p.nix index fa7f102..5e36c20 100644 --- a/os/srv/i2p.nix +++ b/os/srv/i2p.nix @@ -1,7 +1,8 @@ { config, lib, - pkgs, + masterDomain, + securityTemplates, ... }: let @@ -9,45 +10,72 @@ let in { options.os.srv.i2p = { - enable = lib.mkEnableOption "enables i2pd"; - enableBrowser = lib.mkEnableOption "enables mullvad browser for browsing eepsites"; + enable = lib.mkEnableOption "enables a flexible, polymorphic i2pd deployment profile"; + + mode = lib.mkOption { + type = lib.types.enum [ + "server" + "client" + ]; + default = "client"; + description = ""; + }; }; - config = lib.mkMerge [ - (lib.mkIf cfg.enable { - services.i2pd = { - enable = true; - enableIPv6 = true; - # upnp.enable = true; - bandwidth = 1024; - reseed.verify = true; - ntcp2 = { - enable = true; - # published = true; - }; - ssu2 = { + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + { + services.i2pd = { enable = true; - # published = true; + enableIPv6 = true; + reseed.verify = true; + + yggdrasil.enable = true; + + proto = { + http.enable = true; + httpProxy.enable = true; + socksProxy = { + enable = true; + outproxyEnable = true; + }; + sam.enable = true; + i2pControl.enable = true; + }; }; - yggdrasil = { - enable = true; - address = "200:5857:a255:4db6:8687:6928:ddc4:dad6"; + } + + (lib.mkIf (cfg.mode == "server") { + services.i2pd = { + bandwidth = 4096; + + ntcp2.published = true; + ssu2.published = true; + + #TODO add address + yggdrasil.address = ""; }; - proto = { - http.enable = true; - httpProxy.enable = true; - socksProxy = { - enable = true; - outproxyEnable = true; + + os.cluster.nginxProxies."i2p.${masterDomain}" = { + enableACME = true; + forceSSL = true; + locations."/" = { + proxyPass = "http://${config.os.core.network.ips.relay-vm}:7070"; + extraConfig = securityTemplates.restrictToInternal; }; - sam.enable = true; - i2pControl.enable = true; }; - }; - # environment.systemPackages = [ pkgs.i2pd-tools ]; - }) - (lib.mkIf cfg.enableBrowser { - environment.systemPackages = [ pkgs.mullvad-browser ]; - }) - ]; + }) + + (lib.mkIf (cfg.mode == "client") { + services.i2pd = { + bandwidth = 512; + + ntcp2.published = false; + ssu2.published = false; + + yggdrasil.address = ""; + }; + }) + ] + ); } diff --git a/os/srv/lldap.nix b/os/srv/lldap.nix index 1cf43e4..1463ab6 100644 --- a/os/srv/lldap.nix +++ b/os/srv/lldap.nix @@ -1,6 +1,15 @@ -{ config, lib, ... }: +{ + config, + lib, + masterDomain, + securityTemplates, + ... +}: let cfg = config.os.srv.lldap; + computedBaseDN = lib.concatStringsSep "," ( + map (domainPart: "dc=${domainPart}") (lib.splitString "." masterDomain) + ); in { options.os.srv.lldap.enable = lib.mkEnableOption "enables lldap scanning"; @@ -10,15 +19,48 @@ in assertion = config.os.srv.sops.enable; message = "Required for password secure password storing"; } + { + assertion = config.os.core.network.enableFirewall; + message = "Requires firewall"; + } ]; + + sops.secrets = { + "lldap/password" = { + owner = "lldap"; + group = "lldap"; + }; + "lldap/env_file" = { + owner = "lldap"; + group = "lldap"; + }; + }; + services.lldap = { enable = true; settings = { - ldap_base_dn = "dc=example,dc=com"; - ldap_port = 3890; - http_port = 17170; + ldap_base_dn = computedBaseDN; + http_host = "127.0.0.1"; + http_url = "https://lldap.${masterDomain}"; + ldap_user_email = "adikro@disroot.org"; + ldap_user_pass_file = config.sops.secrets."lldap/password".path; + silenceForceUserPassResetWarning = true; + }; + environmentFile = config.sops.secrets."lldap/env_file".path; + }; + + os.cluster.nginxProxies."lldap.${masterDomain}" = { + enableACME = true; + forceSSL = true; + + locations."/" = { + proxyPass = "http://${config.os.core.network.ips.gateway-vm}:17170"; + extraConfig = securityTemplates.restrictToInternal; }; - environmentFile = config.sops.secrets."lldap/env".path; }; + + networking.firewall.extraInputRules = '' + ip saddr 10.0.0.0/24 tcp dport 3890 accept + ''; }; } diff --git a/os/srv/monero.nix b/os/srv/monero.nix index f00413d..6b50e1d 100644 --- a/os/srv/monero.nix +++ b/os/srv/monero.nix @@ -8,16 +8,28 @@ }: let cfg = config.os.srv.monero; + banlist1 = pkgs.fetchurl { + url = "https://gui.xmr.pm/files/block.txt"; + hash = "sha256-0ik4d66js6wvrvciza0li6bsajj8dvxsqlf09hcz7hg610szdxcw"; + }; + banlist2 = pkgs.fetchurl { + url = "https://raw.githubusercontent.com/Boog900/monero-ban-list/refs/heads/main/ban_list.txt"; + hash = "sh256-01z4wm2mp4z1wq2wdkrm66j50gwk3r82m2ml4n0pwjcbajxkdc87"; + }; + + combinedBanlist = pkgs.writeText "combined-monero-banlist.txt" '' + ${builtins.readFile banlist1} + ${builtins.readFile banlist2} + ''; in { options.os.srv.monero = { wallet.enable = lib.mkEnableOption "enables the monero wallet"; service = { enable = lib.mkEnableOption "enables hosting a monero node"; - proxyConfig = lib.mkOption { - type = lib.types.attrs; - default = { }; - }; + public = lib.mkEnableOption "makes the RPC node public (disables authentication for general wallet syncing)"; + tor.enable = lib.mkEnableOption "exposes monero RPC via Tor Onion Service"; + i2p.enable = lib.mkEnableOption "exposes monero RPC via I2P Tunnel"; }; }; @@ -28,8 +40,16 @@ in (lib.mkIf cfg.service.enable { assertions = [ { - assertion = config.os.srv.sops.enable; - message = "Required for password secure password storing"; + assertion = if (!cfg.service.public) then config.os.srv.sops.enable else true; + message = "sops must be enabled"; + } + { + assertion = if cfg.service.tor.enable then config.os.srv.tor.enable else true; + message = "tor must be enabled"; + } + { + assertion = if cfg.service.i2p.enable then config.os.srv.i2p.enable else true; + message = "i2p must be enabled"; } ]; @@ -41,37 +61,59 @@ in services.monero = { enable = true; prune = true; + banlist = combinedBanlist; + limits = { upload = 1250; download = 12500; threads = 8; }; - banlist = builtins.fetchurl { - url = "https://gui.xmr.pm/files/block.txt"; - hash = "0ik4d66js6wvrvciza0li6bsajj8dvxsqlf09hcz7hg610szdxcw"; - }; + rpc = { + address = "0.0.0.0"; + } + // lib.optionalAttrs (!cfg.service.public) { restricted = true; user = "admin"; password = config.sops.secrets."monero/rpc-password".path; }; + + }; + + services.tor = lib.mkIf cfg.service.tor.enable { + onionServices."xmr-rpc" = { + to = [ + { + port = 18081; + address = config.os.core.network.ips.vm9-relays; + } + ]; + }; + }; + + services.i2pd = lib.mkIf cfg.service.i2p.enable { + tunnels.server."xmr-rpc" = { + port = 18081; + address = config.os.core.network.ips.vm9-relays; + keys = "xmr-rpc-key.dat"; + inbound.length = 3; + outbound.length = 3; + }; }; - os.srv.monero.service.proxyConfig = { - "xmr.${masterDomain}" = { - enableACME = true; - forceSSL = true; + os.cluster.nginxProxies."xmr.${masterDomain}" = { + enableACME = true; + forceSSL = true; - locations."/" = { - proxyPass = "http://${config.os.core.network.ips.vm9-relays}:18081"; - extraConfig = '' - proxy_read_timeout 600s; - proxy_send_timeout 600s; - client_max_body_size 50m; + locations."/" = { + proxyPass = "http://${config.os.core.network.ips.vm9-relays}:18081"; + extraConfig = '' + proxy_read_timeout 600s; + proxy_send_timeout 600s; + client_max_body_size 50m; - ${securityTemplates.restrictToInternal} - ''; - }; + ${securityTemplates.restrictToInternal} + ''; }; }; diff --git a/os/srv/nfs.nix b/os/srv/nfs.nix index 9e5b16f..07f331e 100644 --- a/os/srv/nfs.nix +++ b/os/srv/nfs.nix @@ -7,14 +7,17 @@ in config = lib.mkIf cfg.enable { services.nfs.server = { enable = true; + nproc = 4; # Lowered due to low traffic for a home server + createMountPoints = true; - # TODO exports exports = '' - /data 192.168.1.0/24(ro,fsid=0,no_subtree_check) + /data/media 10.1.0.0/24(rw,all_squash,anonuid=1000,anongid=100,async,insecure,no_subtree_check) \ + 10.3.0.0/24(rw,all_squash,anonuid=1000,anongid=100,async,insecure,no_subtree_check) \ + 10.4.0.0/24(rw,all_squash,anonuid=1000,anongid=100,async,insecure,no_subtree_check) - /data/media 192.168.1.0/24(ro,nohide,insecure,no_subtree_check,async) - - /data/backups 192.168.1.50(rw,nohide,no_subtree_check,sync,no_root_squash) + /data/vault 10.1.0.0/24(rw,all_squash,anonuid=1000,anongid=100,async,insecure,no_subtree_check) \ + 10.3.0.0/24(rw,all_squash,anonuid=1000,anongid=100,async,insecure,no_subtree_check) \ + 10.4.0.0/24(rw,all_squash,anonuid=1000,anongid=100,async,insecure,no_subtree_check) ''; }; diff --git a/os/srv/nginx.nix b/os/srv/nginx.nix index 5161920..2194ecb 100644 --- a/os/srv/nginx.nix +++ b/os/srv/nginx.nix @@ -51,7 +51,7 @@ in locations."/".return = "444"; }; } - config.os.srv.monero.proxyConfig + config.os.cluster.nginxProxies ]; }; diff --git a/os/srv/postgres.nix b/os/srv/postgres.nix new file mode 100644 index 0000000..f669f63 --- /dev/null +++ b/os/srv/postgres.nix @@ -0,0 +1,72 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.os.srv.postgres; +in +{ + options.os.srv.postgres.enable = lib.mkEnableOption ""; + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = config.os.srv.sops.enable; + message = "Required for password secure password storing"; + } + { + assertion = config.os.core.network.enableFirewall; + message = "Requires firewall"; + } + ]; + + sops.secrets."postgres/authelia_password" = { + owner = "postgres"; + group = "postgres"; + restartUnits = [ "postgresql.service" ]; + }; + + services.postgresql = { + enable = true; + package = pkgs.postgresql_18; + + extraPlugins = [ config.services.postgresql.package.pkgs.pgvector ]; + + settings = { + listen_addresses = config.os.core.network.ips.database-vm; + + max_connections = 100; + shared_buffers = "256MB"; + work_mem = "4MB"; + }; + + ensureDatabases = [ "authelia" ]; + ensureUsers = [ + { + name = "authelia"; + ensureDBOwnership = true; + } + ]; + + initialScript = pkgs.writeText "init-postgres-passwords.sql" '' + CREATE USER authelia; + ALTER USER authelia WITH PASSWORD 'scram-sha-256'; + ''; + + authentication = pkgs.lib.mkForce '' + local all all trust + host all all 10.0.0.0/24 scram-sha-256 + ''; + }; + + systemd.services.postgresql.postStart = lib.mkAfter '' + PASS=$(cat ${config.sops.secrets."postgres/authelia_password".path}) + ${config.services.postgresql.package}/bin/psql -tAc "ALTER USER authelia WITH PASSWORD '$PASS';" + ''; + + networking.firewall.extraInputRules = '' + ip saddr 10.0.0.0/24 tcp dport 5432 accept + ''; + }; +} diff --git a/os/srv/redis.nix b/os/srv/redis.nix new file mode 100644 index 0000000..a51f9db --- /dev/null +++ b/os/srv/redis.nix @@ -0,0 +1,37 @@ +{ config, lib, ... }: +let + cfg = config.os.srv.redis; +in +{ + options.os.srv.redis.enable = lib.mkEnableOption ""; + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = config.os.srv.sops.enable; + message = "Required for password secure password storing"; + } + { + assertion = config.os.core.network.enableFirewall; + message = "Requires firewall"; + } + ]; + + sops.secrets."redis/password" = { + owner = "redis-main"; + restartUnits = [ "redis-servers-main.service" ]; + }; + + services.redis.servers."main" = { + enable = true; + bind = config.os.core.network.ips.database-vm; + port = 6379; + + requirePassFile = config.sops.secrets."redis/password".path; + }; + + networking.firewall.extraInputRules = '' + ip saddr 10.0.0.0/24 tcp dport 6379 accept + ''; + + }; +} diff --git a/os/srv/restic.nix b/os/srv/restic.nix new file mode 100644 index 0000000..fb2bd19 --- /dev/null +++ b/os/srv/restic.nix @@ -0,0 +1,12 @@ +{ config, lib, ... }: +let + cfg = config.os.srv.restic; +in +{ + options.os.srv.restic.enable = lib.mkEnableOption "enables restic backups"; + + config = lib.mkIf cfg.enable { + assertions = [ + ]; + }; +} diff --git a/os/srv/wireguard.nix b/os/srv/wireguard.nix index 363ac9f..c758174 100644 --- a/os/srv/wireguard.nix +++ b/os/srv/wireguard.nix @@ -107,13 +107,13 @@ in }; networking.wireguard.interfaces.wg0 = { - ips = [ "10.255.1.1/24" ]; + ips = [ "10.3.0.1/24" ]; listenPort = 51280; privateKeyFile = config.sops.secrets."wg_private_key/${hostname}".path; peers = lib.imap1 (i: peer: { publicKey = peer.publicKey; - allowedIPs = [ "10.255.0.${toString i}/32" ]; + allowedIPs = [ "10.3.0.${toString (i + 1)}/32" ]; persistentKeepalive = 25; }) cfg.server.peers; }; @@ -128,12 +128,12 @@ in ]; networking.nameservers = [ - "10.255.1.1" + config.os.core.network.ips.vm2-gateway "9.9.9.9" ]; networking.wireguard.interfaces.wg0 = { - ips = [ "10.255.0.${toString cfg.client.index}/24" ]; + ips = [ "10.3.0.${toString cfg.client.index + 1}/24" ]; privateKeyFile = config.sops.secrets."wg_private_key/${hostname}".path; peers = [ diff --git a/os/srv/zfs.nix b/os/srv/zfs.nix index fadfd82..3bfd2de 100644 --- a/os/srv/zfs.nix +++ b/os/srv/zfs.nix @@ -10,43 +10,51 @@ in assertion = config.os.core.drivers.kernel == "zfs"; message = "ZFS requires the zfs supported kernel"; } + { + assertion = config.os.srv.sops.enable; + message = "required for storing the ntfy token"; + } ]; + + sops.secrets."ntfy/zed".neededForUsers = false; + boot = { - kernelParams = [ "zfs.zfs_arc_max=34359738368" ]; - supportedFilesystems = [ "zfs" ]; - initrd = { - supportedFilesystems = [ "zfs" ]; - # fileSystems."/mnt" = { - # device = "/dev/disk/by-label/KEYS"; - # fsType = "vfat"; - # options = [ "ro" ]; - # }; + kernelParams = [ "zfs.zfs_arc_max=${toString (32 * 1024 * 1024 * 1024)}" ]; + zfs = { + requestEncryptionCredentials = [ "zroot" ]; + useKeyringForCredentials = true; + extraPools = [ "tank" ]; }; + supportedFilesystems = [ "zfs" ]; + initrd.supportedFilesystems = [ "zfs" ]; }; services.zfs = { - autoScrub = { + expandOnBoot = "all"; + autoScrub.enable = true; + trim.enable = true; + autoSnapshot = { enable = true; - interval = "weekly"; + flags = "-k -p --utc"; }; - trim.enable = true; zed = { - enableMail = true; + enableCustomScripts = true; settings = { ZED_DEBUG_LOG = "/var/log/zed.debug.log"; - ZED_EMAIL_ADDR = [ "adikro@disroot.org" ]; - ZED_EMAIL_PROG = "mail"; - ZED_EMAIL_OPTS = "-s '@SUBJECT@' @ADDRESS@"; - ZED_NOTIFY_INTERVAL_SECS = 3600; - ZED_NOTIFY_VERBOSE = false; + ZED_NOTIFY_VERBOSE = 0; - ZED_USE_ENCLOSURE_LEDS = true; - ZED_SCRUB_AFTER_RESILVER = false; + ZED_USE_ENCLOSURE_LEDS = 1; + ZED_SCRUB_AFTER_RESILVER = 1; + ZED_POWER_OFF_ENCLOSURE_SLOT_ON_FAULT = 1; + ZED_POWER_OFF_ENCLOSURE_SLOT_ON_DEADMAN = 1; + ZED_NTFY_TOPIC = "zed-alerts-bibus-lab"; + ZED_NTFY_URL = "http://${config.os.core.network.ips.monitor-vm}:8085"; }; }; }; + systemd.services.zfs-zed.serviceConfig.EnvironmentFile = config.sops.secrets."ntfy/zed".path; networking.hostId = "4e3e22e1"; }; } |
