diff --git a/flake.nix b/flake.nix index d837910..7e4d743 100644 --- a/flake.nix +++ b/flake.nix @@ -153,6 +153,7 @@ machineVars = ./modules/machineVars.nix; socketActivation = ./modules/socketActivation.nix; duperemove = ./modules/duperemove.nix; + passthruSystemdAnalyze = ./modules/passthruSystemdAnalyze.nix; }; homeModules = { diff --git a/modules/passthruSystemdAnalyze.nix b/modules/passthruSystemdAnalyze.nix new file mode 100644 index 0000000..54dcb76 --- /dev/null +++ b/modules/passthruSystemdAnalyze.nix @@ -0,0 +1,61 @@ +{ config, lib, pkgs, ... }: +{ + passthru = { + systemdAnalyze = lib.mapAttrs (s: _: let + # NOTE: systemd-analyze needs /run/systemd; bubblewrap is used to provide a fake environment. + bwrapFlags = (lib.escapeShellArgs [ + "--dev" "/dev" + "--bind" "/nix" "/nix" + "--tmpfs" "/tmp" + "--tmpfs" "/run/systemd" + "--bind" "/bin" "/bin" + "--bind" "${config.system.build.etc}/etc/systemd/system/${s}.service" "/etc/systemd/system/${s}.service" + ]) + " --tmpfs \"$HOME\""; + in { + security = pkgs.stdenv.mkDerivation (finalAttrs: { + name = "systemd-analyze-security-${s}-output"; + preferLocalBuild = true; + dontUnpack = true; + dontBuild = true; + dontFixup = true; + + installPhase = '' + runHook preInstall + + if [ -f '${config.system.build.etc}/etc/systemd/system/${s}.service' ]; then + mkdir -p "$(dirname "$out")" + ${lib.getExe pkgs.bubblewrap} ${bwrapFlags} ${lib.getExe' pkgs.systemd "systemd-analyze"} security --offline true ${config.system.build.etc}/etc/systemd/system/${s}.service > "$out" || touch "$out" + else + touch "$out" + fi + + runHook postInstall + ''; + + passthru.finalScore = lib.pipe finalAttrs.finalPackage [ + lib.readFile + (x: if x == "" then null else lib.pipe x [ + lib.trim + (lib.splitString "\n") + lib.last + (lib.match ".*([0-9])\\.([0-9]).*") + (digits: (lib.toIntBase10 (lib.head digits)) + (lib.toIntBase10 (lib.last digits)) * 0.1) + ]) + ]; + }); + + verify = pkgs.runCommandLocal "systemd-analyze-verify-${s}-output" { } '' + mkdir -p "$(dirname "$out")" + ${lib.getExe pkgs.bubblewrap} ${bwrapFlags} ${lib.getExe' pkgs.systemd "systemd-analyze"} verify --man=no ${config.system.build.etc}/etc/systemd/system/${s}.service |& tee "$out" + ''; + }) config.systemd.services; + + systemdSecurityScores = + # NOTE: force all 'security' instantiations to build in parallel + builtins.seq + (builtins.readDir + (pkgs.linkFarm "systemd-analyze-security-all-outputs" + (lib.mapAttrs (s: _: config.passthru.systemdAnalyze.${s}.security) config.systemd.services))) + lib.mapAttrs (s: _: config.passthru.systemdAnalyze.${s}.security.finalScore) config.systemd.services; + }; +}