nixos/profiles: remove hardened

- It lacks a consistent and transparent baseline or standard,
- It may introduce unexpected breakage or degrade performance without clear benefit,
- It is difficult to manage user expectations, especially since the implications of enabling it are not always obvious,
- and as multiple contributors have noted, it is often more of a “grab bag” of settings than a cohesive security policy.
This commit is contained in:
Nico Felbinger 2025-02-19 18:28:37 +01:00 committed by zowoq
commit 18a45284a2
8 changed files with 16 additions and 271 deletions

View file

@ -24,7 +24,6 @@ profiles/clone-config.section.md
profiles/demo.section.md
profiles/docker-container.section.md
profiles/graphical.section.md
profiles/hardened.section.md
profiles/headless.section.md
profiles/installation-device.section.md
profiles/perlless.section.md

View file

@ -1,20 +0,0 @@
# Hardened {#sec-profile-hardened}
A profile with most (vanilla) hardening options enabled by default,
potentially at the cost of stability, features and performance.
This includes a hardened kernel, and limiting the system information
available to processes through the `/sys` and
`/proc` filesystems. It also disables the User Namespaces
feature of the kernel, which stops Nix from being able to build anything
(this particular setting can be overridden via
[](#opt-security.allowUserNamespaces)). See the
[profile source](https://github.com/nixos/nixpkgs/tree/master/nixos/modules/profiles/hardened.nix)
for further detail on which settings are altered.
::: {.warning}
This profile enables options that are known to affect system
stability. If you experience any stability issues when using the
profile, try disabling it. If you report an issue and use this
profile, always mention that you do.
:::

View file

@ -1680,7 +1680,8 @@
"sec-profile-graphical": [
"index.html#sec-profile-graphical"
],
"sec-profile-hardened": [
"sec-release-26.05-incompatibilities-profiles-hardened-removed": [
"release-notes.html#sec-release-26.05-incompatibilities-profiles-hardened-removed",
"index.html#sec-profile-hardened"
],
"sec-profile-headless": [

View file

@ -86,6 +86,12 @@
- `opentrack`, `slushload`, `synthesia`, `vtfedit`, `winbox`, `wineasio`, and `yabridge` use wineWow64Packages instead of wineWowPackages as wine versions >= 11.0 have deprecated wineWowPackages. As such, the prefixes for these packages are NOT backwards compatible and need to be regenerated with potential for data loss.
- []{#sec-release-26.05-incompatibilities-profiles-hardened-removed} `profiles/hardened` has been removed, because:
- It lacks a consistent and transparent baseline or standard,
- It may introduce unexpected breakage or degrade performance without clear benefit,
- It is difficult to manage user expectations, especially since the implications of enabling it are not always obvious,
- and as multiple contributors have noted, it is often more of a “grab bag” of settings than a cohesive security policy.
- `services.crabfit` was removed because its upstream packages are unmaintained and insecure.
- `sing-box` has been updated to 1.13.0, which has removed some deprecated options. See [upstream documentation](https://sing-box.sagernet.org/configuration/) for details and migration options.

View file

@ -1,136 +1,11 @@
# A profile with most (vanilla) hardening options enabled by default,
# potentially at the cost of stability, features and performance.
#
# This profile enables options that are known to affect system
# stability. If you experience any stability issues when using the
# profile, try disabling it. If you report an issue and use this
# profile, always mention that you do.
# This profile included most standard hardening options enabled by default,
# which may have impacted system stability, feature availability, and performance.
{ lib, ... }:
{
config,
lib,
pkgs,
...
}:
let
inherit (lib)
mkDefault
mkOverride
mkEnableOption
mkIf
maintainers
;
in
{
options.profiles.hardened = mkEnableOption "hardened" // {
default = true;
example = false;
};
config = mkIf config.profiles.hardened {
meta = {
maintainers = [
maintainers.emily
];
};
boot.kernelPackages = mkDefault pkgs.linuxKernel.packages.linux_hardened;
nix.settings.allowed-users = mkDefault [ "@users" ];
environment.memoryAllocator.provider = mkDefault "scudo";
environment.variables.SCUDO_OPTIONS = mkDefault "zero_contents=true";
security.lockKernelModules = mkDefault true;
security.protectKernelImage = mkDefault true;
security.allowSimultaneousMultithreading = mkDefault false;
security.forcePageTableIsolation = mkDefault true;
# This is required by podman to run containers in rootless mode.
security.unprivilegedUsernsClone = mkDefault config.virtualisation.containers.enable;
security.virtualisation.flushL1DataCache = mkDefault "always";
security.apparmor.enable = mkDefault true;
security.apparmor.killUnconfinedConfinables = mkDefault true;
boot.kernelParams = [
# Don't merge slabs
"slab_nomerge"
# Overwrite free'd pages
"page_poison=1"
# Enable page allocator randomization
"page_alloc.shuffle=1"
# Disable debugfs
"debugfs=off"
];
boot.blacklistedKernelModules = [
# Obscure network protocols
"ax25"
"netrom"
"rose"
# Old or rare or insufficiently audited filesystems
"adfs"
"affs"
"bfs"
"befs"
"cramfs"
"efs"
"erofs"
"exofs"
"freevxfs"
"f2fs"
"hfs"
"hpfs"
"jfs"
"minix"
"nilfs2"
"ntfs"
"omfs"
"qnx4"
"qnx6"
"sysv"
"ufs"
];
# Hide kptrs even for processes with CAP_SYSLOG
boot.kernel.sysctl."kernel.kptr_restrict" = mkOverride 500 2;
# Disable bpf() JIT (to eliminate spray attacks)
boot.kernel.sysctl."net.core.bpf_jit_enable" = mkDefault false;
# Disable ftrace debugging
boot.kernel.sysctl."kernel.ftrace_enabled" = mkDefault false;
# Enable strict reverse path filtering (that is, do not attempt to route
# packets that "obviously" do not belong to the iface's network; dropped
# packets are logged as martians).
boot.kernel.sysctl."net.ipv4.conf.all.log_martians" = mkDefault true;
boot.kernel.sysctl."net.ipv4.conf.all.rp_filter" = mkDefault "1";
boot.kernel.sysctl."net.ipv4.conf.default.log_martians" = mkDefault true;
boot.kernel.sysctl."net.ipv4.conf.default.rp_filter" = mkDefault "1";
# Ignore broadcast ICMP (mitigate SMURF)
boot.kernel.sysctl."net.ipv4.icmp_echo_ignore_broadcasts" = mkDefault true;
# Ignore incoming ICMP redirects (note: default is needed to ensure that the
# setting is applied to interfaces added after the sysctls are set)
boot.kernel.sysctl."net.ipv4.conf.all.accept_redirects" = mkDefault false;
boot.kernel.sysctl."net.ipv4.conf.all.secure_redirects" = mkDefault false;
boot.kernel.sysctl."net.ipv4.conf.default.accept_redirects" = mkDefault false;
boot.kernel.sysctl."net.ipv4.conf.default.secure_redirects" = mkDefault false;
boot.kernel.sysctl."net.ipv6.conf.all.accept_redirects" = mkDefault false;
boot.kernel.sysctl."net.ipv6.conf.default.accept_redirects" = mkDefault false;
# Ignore outgoing ICMP redirects (this is ipv4 only)
boot.kernel.sysctl."net.ipv4.conf.all.send_redirects" = mkDefault false;
boot.kernel.sysctl."net.ipv4.conf.default.send_redirects" = mkDefault false;
};
imports = [
(lib.mkRemovedOptionModule [ "profiles" "hardened" ] ''
The hardened profile has been removed, see the backward incompatibilities section of the 26.05 release notes for more information.
'')
];
}

View file

@ -717,7 +717,6 @@ in
package = pkgs.hadoop_3_3;
};
haproxy = runTest ./haproxy.nix;
hardened = runTest ./hardened.nix;
harmonia = runTest ./harmonia.nix;
haste-server = runTest ./haste-server.nix;
hbase2 = runTest {

View file

@ -1,113 +0,0 @@
{ pkgs, ... }:
{
name = "hardened";
meta = {
maintainers = [ ];
};
nodes.machine =
{
lib,
pkgs,
config,
...
}:
{
users.users.alice = {
isNormalUser = true;
extraGroups = [ "proc" ];
};
users.users.sybil = {
isNormalUser = true;
group = "wheel";
};
imports = [ ../modules/profiles/hardened.nix ];
environment.memoryAllocator.provider = "graphene-hardened";
nix.settings.sandbox = false;
virtualisation.emptyDiskImages = [
{
size = 4096;
driveConfig.deviceExtraOpts.serial = "deferred";
}
];
virtualisation.fileSystems = {
"/deferred" = {
device = "/dev/disk/by-id/virtio-deferred";
fsType = "vfat";
autoFormat = true;
options = [ "noauto" ];
};
};
boot.extraModulePackages = pkgs.lib.optional (pkgs.lib.versionOlder config.boot.kernelPackages.kernel.version "5.6") config.boot.kernelPackages.wireguard;
boot.kernelModules = [ "wireguard" ];
};
testScript =
let
hardened-malloc-tests = pkgs.graphene-hardened-malloc.ld-preload-tests;
in
''
machine.wait_for_unit("multi-user.target")
with subtest("AppArmor profiles are loaded"):
machine.succeed("systemctl status apparmor.service")
# AppArmor securityfs
with subtest("AppArmor securityfs is mounted"):
machine.succeed("mountpoint -q /sys/kernel/security")
machine.succeed("cat /sys/kernel/security/apparmor/profiles")
# Test loading out-of-tree modules
with subtest("Out-of-tree modules can be loaded"):
machine.succeed("grep -Fq wireguard /proc/modules")
# Test kernel module hardening
with subtest("No more kernel modules can be loaded"):
# note: this better a be module we normally wouldn't load ...
machine.wait_for_unit("disable-kernel-module-loading.service")
machine.fail("modprobe dccp")
# Test userns
with subtest("User namespaces are restricted"):
machine.succeed("unshare --user true")
machine.fail("su -l alice -c 'unshare --user true'")
# Test dmesg restriction
with subtest("Regular users cannot access dmesg"):
machine.fail("su -l alice -c dmesg")
# Test access to kcore
with subtest("Kcore is inaccessible as root"):
machine.fail("cat /proc/kcore")
# Test deferred mount
with subtest("Deferred mounts work"):
machine.fail("mountpoint -q /deferred") # was deferred
machine.systemctl("start deferred.mount")
machine.succeed("mountpoint -q /deferred") # now mounted
# Test Nix dæmon usage
with subtest("nix-daemon cannot be used by all users"):
machine.fail("su -l nobody -s /bin/sh -c 'nix --extra-experimental-features nix-command ping-store'")
machine.succeed("su -l alice -c 'nix --extra-experimental-features nix-command ping-store'")
# Test kernel image protection
with subtest("The kernel image is protected"):
machine.fail("systemctl hibernate")
machine.fail("systemctl kexec")
with subtest("The hardened memory allocator works"):
machine.succeed("${hardened-malloc-tests}/bin/run-tests")
'';
}

View file

@ -6,8 +6,6 @@
# boot via sysctl or kernel cmdline are left enabled here, for improved
# flexibility.
#
# See also <nixos/modules/profiles/hardened.nix>
{
stdenv,
lib,