From 75f8189c0e731340a9ccc51f06afd0cc5dacf45d Mon Sep 17 00:00:00 2001 From: hektor Date: Sun, 11 Oct 2026 12:41:52 +0200 Subject: [PATCH] feat(hardening): declare hardening module using 'nix-mineral' --- flake.lock | 72 +++++++++++++++++++++- flake.nix | 4 ++ hosts/andromache/default.nix | 1 + hosts/hecuba/default.nix | 4 ++ modules/hardening/default.nix | 111 ++++++++++++++++++++++++++++++++++ 5 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 modules/hardening/default.nix diff --git a/flake.lock b/flake.lock index f50768e..00f885d 100644 --- a/flake.lock +++ b/flake.lock @@ -226,6 +226,20 @@ "type": "github" } }, + "flake-compat_3": { + "locked": { + "lastModified": 1733328505, + "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", + "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", + "revCount": 69, + "type": "tarball", + "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.1.0/01948eb7-9cba-704f-bbf3-3fa956735b52/source.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz" + } + }, "flake-parts": { "inputs": { "nixpkgs-lib": [ @@ -248,6 +262,24 @@ } }, "flake-parts_2": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1778716662, + "narHash": "sha256-m1Yf0wZ8j1OHjTc2UwHwyQRSnNeSgLJOd7q5Y45hzi4=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "f7c1a2d347e4c52d5fb8d10cb4d94b5884e546fb", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_3": { "inputs": { "nixpkgs-lib": [ "stylix", @@ -417,6 +449,28 @@ "type": "github" } }, + "nix-mineral": { + "inputs": { + "flake-compat": "flake-compat_3", + "flake-parts": "flake-parts_2", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1792339378, + "narHash": "sha256-2GSp02yOdG9BSvb0c9SW1nsMnUpjR1/WBKskGz0D+8g=", + "owner": "cynicsketch", + "repo": "nix-mineral", + "rev": "bcd361bb18fccc4297d668aa5e0d5e4ebd4918ce", + "type": "github" + }, + "original": { + "owner": "cynicsketch", + "repo": "nix-mineral", + "type": "github" + } + }, "nix-secrets": { "flake": false, "locked": { @@ -503,6 +557,21 @@ "url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz" } }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1777168982, + "narHash": "sha256-GOkGPcboWE9BmGCRMLX3worL4EMnsnG8MyKmXNeYuhQ=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "f5901329dade4a6ea039af1433fb087bd9c1fe14", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, "nixpkgs_2": { "locked": { "lastModified": 1792210252, @@ -639,6 +708,7 @@ "git-hooks": "git-hooks", "hecuba-services": "hecuba-services", "home-manager": "home-manager", + "nix-mineral": "nix-mineral", "nix-secrets": "nix-secrets", "nixgl": "nixgl", "nixos-hardware": "nixos-hardware", @@ -714,7 +784,7 @@ "base16-helix": "base16-helix", "base16-vim": "base16-vim", "firefox-gnome-theme": "firefox-gnome-theme", - "flake-parts": "flake-parts_2", + "flake-parts": "flake-parts_3", "gnome-shell": "gnome-shell", "nixpkgs": [ "nixpkgs" diff --git a/flake.nix b/flake.nix index 66fb2e6..19a2bc7 100644 --- a/flake.nix +++ b/flake.nix @@ -6,6 +6,10 @@ nixos-hardware = { url = "github:NixOS/nixos-hardware/master"; }; + nix-mineral = { + url = "github:cynicsketch/nix-mineral"; + inputs.nixpkgs.follows = "nixpkgs"; + }; disko = { url = "github:nix-community/disko/latest"; inputs.nixpkgs.follows = "nixpkgs"; diff --git a/hosts/andromache/default.nix b/hosts/andromache/default.nix index 3de4e53..40a3489 100644 --- a/hosts/andromache/default.nix +++ b/hosts/andromache/default.nix @@ -56,6 +56,7 @@ in desktop.ly.enable = true; docker.enable = true; k8s.enable = true; + hardening.enable = true; hcloud.enable = true; networking = { enable = true; diff --git a/hosts/hecuba/default.nix b/hosts/hecuba/default.nix index 43b2512..7283948 100644 --- a/hosts/hecuba/default.nix +++ b/hosts/hecuba/default.nix @@ -24,6 +24,10 @@ in hardware.facter.reportPath = ./facter.json; docker.enable = true; + hardening = { + enable = true; + profile = "server"; + }; secrets.enable = true; ssh.enable = true; tailscale.enable = true; diff --git a/modules/hardening/default.nix b/modules/hardening/default.nix new file mode 100644 index 0000000..069984f --- /dev/null +++ b/modules/hardening/default.nix @@ -0,0 +1,111 @@ +{ + inputs, + config, + lib, + ... +}: + +let + cfg = config.hardening; + wakeOnLan = lib.any (iface: iface.wakeOnLan.enable) (lib.attrValues config.networking.interfaces); + randomMac = config.host.role == "laptop" && !wakeOnLan; + profiles = { + workstation = { + preset = [ + "compatibility" + ] + ++ lib.optional config.gaming.enable "performance"; # prioritized (order matters) + settings = { + kernel.cpu-mitigations = "smt-on"; + debug.debugfs = true; + etc = { + harden-bluetooth = false; + harden-gitconfig = false; + }; + network = { + router-advertisements = "on"; + tcp-sack = true; + }; + }; + }; + + server = { + preset = [ + "compatibility" + "maximum" # prioritized (order matters) + ]; + settings = { + etc = { + harden-gitconfig = false; + }; + debug.quiet-boot = false; + kernel.cpu-mitigations = "smt-on"; + network = { + ipv6-tempaddr = false; + max-addresses = false; + neighbor-solicitations = false; + router-advertisements = "on"; + router-solicitations = false; + tcp-sack = true; + }; + system = { + lower-address-mmap = false; + multilib = false; + yama = "admin-only"; + }; + }; + extras = { + kernel.warn-panic = false; + system.secure-chrony = null; + network = { + tcp-window-scaling = true; + }; + }; + }; + }; +in +{ + imports = [ inputs.nix-mineral.nixosModules.nix-mineral ]; + + options.hardening = { + enable = lib.mkEnableOption "hardening"; + profile = lib.mkOption { + type = lib.types.enum [ + "workstation" + "server" + ]; + default = "workstation"; + }; + }; + + config = lib.mkIf cfg.enable { + boot.blacklistedKernelModules = [ + "dccp" + "sctp" + "rds" + "tipc" + ]; + networking.wireless.iwd.settings.General.AddressRandomization = lib.mkIf randomMac "network"; + nix-mineral = lib.mkMerge [ + { + enable = true; + filesystems.normal = { + "/tmp".enable = !config.boot.tmp.useTmpfs; + # only needed for FAT + "/boot".options.umask = lib.mkIf ( + !lib.elem (config.fileSystems."/boot".fsType or null) [ + "vfat" + "msdos" + "exfat" + ] + ) (lib.mkForce false); + }; + settings.network = { + ip-forwarding = config.virtualisation.docker.enable || config.services.k3s.enable; + random-mac = randomMac; + }; + } + profiles.${cfg.profile} + ]; + }; +}