Skip to content

Commit

Permalink
ft: add systemd hardening helpers
Browse files Browse the repository at this point in the history
This module adds `systemd.services.<name>.harden` set of options that
helps with setting basic systemd units hardening. That should help with
making more services hardened and responding with better security
analysis grade without too much repetition. Most of the set values are
marked with `mkDefault` to allow explicit opt-out for options that
aren't needed without resolving to `mkForce` or similar.
  • Loading branch information
hauleth committed Feb 12, 2024
1 parent b05b56d commit da8220d
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 0 deletions.
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Expand Up @@ -324,6 +324,7 @@
./security/sudo.nix
./security/sudo-rs.nix
./security/systemd-confinement.nix
./security/systemd-harden.nix
./security/tpm2.nix
./security/wrappers/default.nix
./services/admin/meshcentral.nix
Expand Down
107 changes: 107 additions & 0 deletions nixos/modules/security/systemd-harden.nix
@@ -0,0 +1,107 @@

{config, lib, ...}: let
inherit (lib) types;
in {
options.systemd.services = lib.mkOption {
type = types.attrsOf (types.submodule ({name, config, ...}: {
options.harden = {
basic = lib.mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
Basic restrictions for systemd services
'';
};

execOnlyNix = lib.mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
Mark whole system as non-executable with exception for `/nix/store`.
'';
};

protectKernel = lib.mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
Protect kernel internals from being reachable by the service.
'';
};

proc = lib.mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
Restrict view into `/proc` to only allow access for limited subset.
'';
};

systemCall = lib.mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
Restrict system calls available to the service.
'';
};

onlyLocalhost = lib.mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
Allow listening sockets only on localhost.
'';
};
};
config.serviceConfig = let
inherit (lib) mkDefault;
in {}
// (lib.optionalAttrs config.harden.basic {
NoNewPrivileges = mkDefault true;
LockPersonality = mkDefault true;
RemoveIPC = mkDefault true;

MemoryDenyWriteExecute = mkDefault true;

CapabilityBoundingSet = mkDefault [""];

RestrictNamespaces = mkDefault true;
RestrictRealtime = mkDefault true;
RestrictSUIDSGID = mkDefault true;

ProtectHome = mkDefault true;
ProtectClock = mkDefault true;
ProtectControlGroups = mkDefault true;

RestrictAddressFamilies = mkDefault ["AF_INET" "AF_INET6" "AF_UNIX"];

PrivateDevices = mkDefault true;
PrivateTmp = mkDefault true;
PrivateMounts = mkDefault true;
PrivateUsers = mkDefault true;
})
// (lib.optionalAttrs config.harden.execOnlyNix {
NoExecPaths = ["/"];
ExecPaths = ["/nix/store"];
})
// (lib.optionalAttrs config.harden.protectKernel {
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
})
// (lib.optionalAttrs config.harden.proc {
ProtectProc = mkDefault "invisible";
ProcSubset = "pid";
})
// (lib.optionalAttrs config.harden.systemCall {
SystemCallFilter = mkDefault [ "@system-service" ];
SystemCallArchitectures = [ "native" ];
SystemCallErrorNumber = mkDefault "EPERM";
})
// (lib.optionalAttrs config.harden.onlyLocalhost {
IPAddressAllow = ["localhost"];
IPAddressDeny = ["any"];
});
}));
};
}

0 comments on commit da8220d

Please sign in to comment.