added stuff

This commit is contained in:
Charlie Root 2024-04-09 23:11:33 +02:00
commit 9d0ebdfbd0
907 changed files with 70990 additions and 0 deletions

View file

@ -0,0 +1,71 @@
{
config,
pkgs,
lib,
...
}: let
inherit (lib.modules) mkIf;
in {
config = mkIf (lib.isx86Linux pkgs) {
services.dbus.apparmor = "enabled";
environment.systemPackages = with pkgs; [
apparmor-pam
apparmor-utils
apparmor-parser
apparmor-profiles
apparmor-bin-utils
apparmor-kernel-patches
libapparmor
];
# apparmor configuration
security.apparmor = {
enable = true;
# whether to enable the AppArmor cache
# in /var/cache/apparmore
enableCache = true;
# whether to kill processes which have an AppArmor profile enabled
# but are not confined (AppArmor can only confine new processes)
killUnconfinedConfinables = true;
# packages to be added to AppArmors include path
packages = [pkgs.apparmor-profiles];
# apparmor policies
policies = {
"default_deny" = {
enforce = false;
enable = false;
profile = ''
profile default_deny /** { }
'';
};
"sudo" = {
enforce = false;
enable = false;
profile = ''
${pkgs.sudo}/bin/sudo {
file /** rwlkUx,
}
'';
};
"nix" = {
enforce = false;
enable = false;
profile = ''
${config.nix.package}/bin/nix {
unconfined,
}
'';
};
};
# TODO: includes
};
};
}

View file

@ -0,0 +1,56 @@
{
config,
lib,
...
}: let
inherit (lib) mkIf;
sys = config.modules.system;
auditEnabled = sys.security.auditd.enable;
in {
config = mkIf auditEnabled {
security = {
# system audit
auditd.enable = true;
audit = {
enable = true;
backlogLimit = 8192;
failureMode = "printk";
rules = [
"-a exit,always -F arch=b64 -S execve"
];
};
};
systemd = {
# a systemd timer to clean /var/log/audit.log daily
# this can probably be weekly, but daily means we get to clean it every 2-3 days instead of once a week
timers."clean-audit-log" = {
description = "Periodically clean audit log";
wantedBy = ["timers.target"];
timerConfig = {
OnCalendar = "daily";
Persistent = true;
};
};
# clean audit log if it's more than 524,288,000 bytes, which is roughly 500 megabytes
# it can grow MASSIVE in size if left unchecked
services."clean-audit-log" = {
script = ''
set -eu
if [[ $(stat -c "%s" /var/log/audit/audit.log) -gt 524288000 ]]; then
echo "Clearing Audit Log";
rm -rvf /var/log/audit/audit.log;
echo "Done!"
fi
'';
serviceConfig = {
Type = "oneshot";
User = "root";
};
};
};
};
}

View file

@ -0,0 +1,77 @@
{
config,
lib,
pkgs,
...
}: let
inherit (lib) mkIf optionalString;
sys = config.modules.system;
in {
config = mkIf sys.security.clamav.enable {
services.clamav = {
daemon = {enable = true;} // sys.security.clamav.daemon;
updater = {enable = true;} // sys.security.clamav.updater;
};
systemd = {
tmpfiles.rules = [
"D /var/lib/clamav 755 clamav clamav"
];
services = {
clamav-daemon = {
serviceConfig = {
PrivateTmp = lib.mkForce "no";
PrivateNetwork = lib.mkForce "no";
Restart = "always";
};
unitConfig = {
# only start clamav when required database files are present
# especially useful if you are deploying headlessly and don't want a service fail instantly
ConditionPathExistsGlob = [
"/var/lib/clamav/main.{c[vl]d,inc}"
"/var/lib/clamav/daily.{c[vl]d,inc}"
];
};
};
clamav-init-database = {
wantedBy = ["clamav-daemon.service"];
before = ["clamav-daemon.service"];
serviceConfig.ExecStart = "systemctl start clamav-freshclam";
unitConfig = {
# opposite condition of clamav-daemon: only run this service if
# database files are not present in the database directory
ConditionPathExistsGlob = [
"!/var/lib/clamav/main.{c[vl]d,inc}"
"!/var/lib/clamav/daily.{c[vl]d,inc}"
];
};
};
clamav-freshclam = {
wants = ["clamav-daemon.service"];
serviceConfig = {
ExecStart = let
message = "Updating ClamAV database";
in ''
${pkgs.coreutils}/bin/echo -en ${message}
'';
SuccessExitStatus = lib.mkForce [11 40 50 51 52 53 54 55 56 57 58 59 60 61 62];
};
};
};
timers.clamav-freshclam.timerConfig = {
# the default is to run the timer hourly but we do not want our entire infra to be overloaded
# trying to run clamscan at the same time. randomize the timer to something around an hour
# so that the window is consistent, but the load is not
RandomizedDelaySec = "60m";
FixedRandomDelay = true;
Persistent = true;
};
};
};
}

View file

@ -0,0 +1,25 @@
{
# This is the entry point of the security module.
# This makes our system generally more secure as opposed to having nothing
# but keep in mind that certain things (e.g. webcam) might be broken
# as a result of the configurations provided below. Exercise caution and common sense.
# DO NOT COPY BLINDLY
# Also see:
# <https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/hardened.nix>
# <https://github.com/fort-nix/nix-bitcoin/blob/master/modules/presets/hardened-extended.nix>
imports = [
./apparmor.nix # apparmor configuration and policies
./auditd.nix # auditd
./clamav.nix # clamav antivirus
./fprint.nix # fingerprint driver and login support
./kernel.nix # kernel hardening
./memalloc.nix # memory allocator hardening
./pam.nix # pam configuration
./pki.nix # pki certificate bundles
./polkit.nix # polkit configuration
./selinux.nix # selinux support + kernel patches
./sudo.nix # sudo rules and configuration
./virtualization.nix # hypervisor hardening
./usbguard.nix # usbguard
];
}

View file

@ -0,0 +1,25 @@
{
config,
pkgs,
lib,
...
}: let
inherit (lib) mkIf;
sys = config.modules.system;
in {
config = mkIf sys.security.fprint.enable {
# fingerprint login
# doesn't work because thanks drivers
services.fprintd = {
enable = false;
tod.enable = true;
tod.driver = pkgs.libfprint-2-tod1-goodix;
};
security.pam.services = {
login.fprintAuth = true;
swaylock.fprintAuth = true;
};
};
}

View file

@ -0,0 +1,287 @@
{
config,
lib,
...
}: let
inherit (lib) optionals versionOlder mkForce;
mitigationFlags =
(
optionals (versionOlder config.boot.kernelPackages.kernel.version "5.1.13")
[
# we don't need restricted indirect branch speculation
"noibrs"
# we don't need no indirect branch prediction barrier either, it sounds funny
"noibpb"
# allow programs to get data from some other program when they shouldn't be able to - maybe they need it!
"nospectre_v1"
"nospectre_v2"
# why flush the L1 cache? what if we need it later. anyone being able to get it is a small consequence, I think
"l1tf=off"
# of course we want to use, not bypass, the stored data
"nospec_store_bypass_disable"
"no_stf_barrier" # We don't need no barriers between software, they could be friends
"mds=off" # Zombieload attacks are fine
]
)
++ [
"mitigations=off" # Of course we don't want no mitigations
];
sys = config.modules.system;
cfg = sys.security;
in {
config = {
# failsafe for idiots, god knows there are plenty
assertions =
optionals cfg.mitigations.disable
[
{
assertion = cfg.mitigations.acceptRisk;
message = ''
You have enabled `config.modules.system.security.mitigations`.
To make sure you are not doing this out of sheer idiocy, you must explicitly
accept the risk of running your kernel without Spectre or Meltdown mitigations.
Set `config.modules.system.security.mitigations.acceptRisk` to `true` only if you know what your doing!
If you don't know what you are doing, but still insist on disabling mitigations; perish on your own accord.
'';
}
];
security = {
protectKernelImage = true; # disables hibernation
# Breaks virtd, wireguard and iptables by disallowing them from loading
# modules during runtime. You may enable this module if you wish, but do
# make sure that the necessary modules are loaded declaratively before
# doing so. Failing to add those modules may result in an unbootable system!
lockKernelModules = false;
# Force-enable the Page Table Isolation (PTI) Linux kernel feature
# helps mitigate Meltdown and prevent some KASLR bypasses.
forcePageTableIsolation = true;
# User namespaces are required for sandboxing. Better than nothing imo.
allowUserNamespaces = true;
# Disable unprivileged user namespaces, unless containers are enabled
# required by podman to run containers in rootless mode.
unprivilegedUsernsClone = config.virtualisation.containers.enable;
allowSimultaneousMultithreading = true;
};
boot = {
kernel = {
sysctl = {
# The Magic SysRq key is a key combo that allows users connected to the
# system console of a Linux kernel to perform some low-level commands.
# Disable it, since we don't need it, and is a potential security concern.
"kernel.sysrq" = mkForce 0;
# Restrict ptrace() usage to processes with a pre-defined relationship
# (e.g., parent/child)
# FIXME: this breaks game launchers, find a way to launch them with privileges (steam)
# gamescope wrapped with the capabilities *might* solve the issue
# spoiler: it didn't
# "kernel.yama.ptrace_scope" = 2;
# Hide kptrs even for processes with CAP_SYSLOG
# also prevents printing kernel pointers
"kernel.kptr_restrict" = 2;
# Disable bpf() JIT (to eliminate spray attacks)
"net.core.bpf_jit_enable" = false;
# Disable ftrace debugging
"kernel.ftrace_enabled" = false;
# Avoid kernel memory address exposures via dmesg (this value can also be set by CONFIG_SECURITY_DMESG_RESTRICT).
"kernel.dmesg_restrict" = 1;
# Prevent creating files in potentially attacker-controlled environments such
# as world-writable directories to make data spoofing attacks more difficult
"fs.protected_fifos" = 2;
# Prevent unintended writes to already-created files
"fs.protected_regular" = 2;
# Disable SUID binary dump
"fs.suid_dumpable" = 0;
# Disable late module loading
# "kernel.modules_disabled" = 1;
# Disallow profiling at all levels without CAP_SYS_ADMIN
"kernel.perf_event_paranoid" = 3;
# Require CAP_BPF to use bpf
"kernel.unprvileged_bpf_disabled" = 1;
# Prevent boot console kernel log information leaks
"kernel.printk" = "3 3 3 3";
# Restrict loading TTY line disciplines to the CAP_SYS_MODULE capability to
# prevent unprivileged attackers from loading vulnerable line disciplines with
# the TIOCSETD ioctl
"dev.tty.ldisc_autoload" = "0";
};
};
# https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html
kernelParams =
[
# make stack-based attacks on the kernel harder
"randomize_kstack_offset=on"
# Disable vsyscalls as they are obsolete and have been replaced with vDSO.
# vsyscalls are also at fixed addresses in memory, making them a potential
# target for ROP attacks
# this breaks really old binaries for security
"vsyscall=none"
# reduce most of the exposure of a heap attack to a single cache
# Disable slab merging which significantly increases the difficulty of heap
# exploitation by preventing overwriting objects from merged caches and by
# making it harder to influence slab cache layout
"slab_nomerge"
# Disable debugfs which exposes a lot of sensitive information about the
# kernel. Some programs, such as powertop, use this interface to gather
# information about the system, but it is not necessary for the system to
# actually publish those. I can live without it.
"debugfs=off"
# Sometimes certain kernel exploits will cause what is known as an "oops".
# This parameter will cause the kernel to panic on such oopses, thereby
# preventing those exploits
"oops=panic"
# Only allow kernel modules that have been signed with a valid key to be
# loaded, which increases security by making it much harder to load a
# malicious kernel module
"module.sig_enforce=1"
# The kernel lockdown LSM can eliminate many methods that user space code
# could abuse to escalate to kernel privileges and extract sensitive
# information. This LSM is necessary to implement a clear security boundary
# between user space and the kernel
# integrity: kernel features that allow userland to modify the running kernel
# are disabled
# confidentiality: kernel features that allow userland to extract confidential
# information from the kernel are also disabled
"lockdown=confidentiality"
# enable buddy allocator free poisoning
# on: memory will befilled with a specific byte pattern
# that is unlikely to occur in normal operation.
# off (default): page poisoning will be disabled
"page_poison=on"
# performance improvement for direct-mapped memory-side-cache utilization
# reduces the predictability of page allocations
"page_alloc.shuffle=1"
# for debugging kernel-level slab issues
"slub_debug=FZP"
# ignore access time (atime) updates on files
# except when they coincide with updates to the ctime or mtime
"rootflags=noatime"
# linux security modules
"lsm=landlock,lockdown,yama,integrity,apparmor,bpf,tomoyo,selinux"
# prevent the kernel from blanking plymouth out of the fb
"fbcon=nodefer"
# the format that will be used for integrity audit logs
# 0 (default): basic integrity auditing messages
# 1: additional integrity auditing messages
"integrity_audit=1"
]
++ optionals cfg.mitigations.disable mitigationFlags;
blacklistedKernelModules = lib.concatLists [
# Obscure network protocols
[
"dccp" # Datagram Congestion Control Protocol
"sctp" # Stream Control Transmission Protocol
"rds" # Reliable Datagram Sockets
"tipc" # Transparent Inter-Process Communication
"n-hdlc" # High-level Data Link Control
"netrom" # NetRom
"x25" # X.25
"ax25" # Amatuer X.25
"rose" # ROSE
"decnet" # DECnet
"econet" # Econet
"af_802154" # IEEE 802.15.4
"ipx" # Internetwork Packet Exchange
"appletalk" # Appletalk
"psnap" # SubnetworkAccess Protocol
"p8022" # IEEE 802.3
"p8023" # Novell raw IEEE 802.3
"can" # Controller Area Network
"atm" # ATM
]
# Old or rare or insufficiently audited filesystems
[
"adfs" # Active Directory Federation Services
"affs" # Amiga Fast File System
"befs" # "Be File System"
"bfs" # BFS, used by SCO UnixWare OS for the /stand slice
"cifs" # Common Internet File System
"cramfs" # compressed ROM/RAM file system
"efs" # Extent File System
"erofs" # Enhanced Read-Only File System
"exofs" # EXtended Object File System
"freevxfs" # Veritas filesystem driver
"f2fs" # Flash-Friendly File System
"vivid" # Virtual Video Test Driver (unnecessary, and a historical cause of escalation issues)
"gfs2" # Global File System 2
"hpfs" # High Performance File System (used by OS/2)
"hfs" # Hierarchical File System (Macintosh)
"hfsplus" # " same as above, but with extended attributes
"jffs2" # Journalling Flash File System (v2)
"jfs" # Journaled File System - only useful for VMWare sessions
"ksmbd" # SMB3 Kernel Server
"minix" # minix fs - used by the minix OS
"nfsv3" # " (v3)
"nfsv4" # Network File System (v4)
"nfs" # Network File System
"nilfs2" # New Implementation of a Log-structured File System
"omfs" # Optimized MPEG Filesystem
"qnx4" # extent-based file system used by the QNX4 and QNX6 OSes
"qnx6" # "
"squashfs" # compressed read-only file system (used by live CDs)
"sysv" # implements all of Xenix FS, SystemV/386 FS and Coherent FS.
"udf" # https://docs.kernel.org/5.15/filesystems/udf.html
]
# Disable Thunderbolt and FireWire to prevent DMA attacks
[
"thunderbolt"
"firewire-core"
]
# you might possibly want your webcam to work
# we whitelsit the module if the system wants
# webcam to work
(optionals (!sys.security.fixWebcam) [
"uvcvideo" # this is why your webcam no worky
])
# if bluetooth is enabled, whitelist the module
# necessary for bluetooth dongles to work
(optionals (!sys.bluetooth.enable) [
"bluetooth" # let bluetooth work
"btusb" # let bluetooth dongles work
])
];
};
};
}

View file

@ -0,0 +1,18 @@
{
config,
lib,
...
}: let
inherit (lib) mkDefault optionals;
in {
# FIXME: causes a mass rebuild
# scudo memalloc is unstable
# environment.memoryAllocator.provider = mkDefault "scudo"; # "graphene-hardened";
# dhcpcd broken with scudo or graphene malloc
nixpkgs.overlays = optionals (config.environment.memoryAllocator.provider != "libc") [
(_final: prev: {
dhcpcd = prev.dhcpcd.override {enablePrivSep = false;};
})
];
}

View file

@ -0,0 +1,30 @@
{
security = {
pam = {
# fix "too many files open" errors while writing a lot of data at once
# (e.g. when building a large package)
# if this, somehow, doesn't meet your requirements you may just bump the numbers up
loginLimits = [
{
domain = "@wheel";
item = "nofile";
type = "soft";
value = "524288";
}
{
domain = "@wheel";
item = "nofile";
type = "hard";
value = "1048576";
}
];
# allow screen lockers to also unlock the screen
# (e.g. swaylock, gtklock)
services = {
swaylock.text = "auth include login";
gtklock.text = "auth include login";
};
};
};
}

View file

@ -0,0 +1,41 @@
{lib, ...}: {
security.pki = {
certificates = lib.mkForce [];
caCertificateBlacklist = [
#
"AC RAIZ FNMT-RCM SERVIDORES SEGUROS"
"Autoridad de Certificacion Firmaprofesional CIF A62634068"
# China Financial Certification Authority
"CFCA EV ROOT"
# Chunghwa Telecom Co., Ltd
"ePKI Root Certification Authority"
"HiPKI Root CA - G1"
# Dhimyotis
"Certigna"
"Certigna Root CA"
# GUANG DONG CERTIFICATE AUTHORITY
"GDCA TrustAUTH R5 ROOT"
# Hongkong Post
"Hongkong Post Root CA 3"
# iTrusChina Co.,Ltd.
"vTrus ECC Root CA"
"vTrus Root CA"
# Krajowa Izba Rozliczeniowa S.A.
"SZAFIR ROOT CA2"
# NetLock Kft.
"NetLock Arany (Class Gold) Főtanúsítvány"
# TAIWAN-CA
"TWCA Root Certification Authority"
"TWCA Global Root CA"
];
};
}

View file

@ -0,0 +1,20 @@
{
config,
lib,
...
}: {
# have polkit log all actions
security.polkit = {
enable = true;
debug = lib.mkDefault true;
# the below configuration depends on security.polkit.debug being set to true
# so we have it written only if debugging is enabled
extraConfig = lib.mkIf config.security.polkit.debug ''
/* Log authorization checks. */
polkit.addRule(function(action, subject) {
polkit.log("user " + subject.user + " is attempting action " + action.id + " from PID " + subject.pid);
});
'';
};
}

View file

@ -0,0 +1,62 @@
{
config,
pkgs,
lib,
...
}: let
inherit (lib) mkIf;
sys = config.modules.system;
cfg = sys.security.selinux;
in {
config = mkIf cfg.enable {
# build systemd with SE Linux support so it loads policy at boot and supports file labelling
systemd.package = pkgs.systemd.override {withSelinux = true;};
# we cannot have apparmor and security together. disable apparmor
security.apparmor.enable = lib.mkForce false;
boot = {
# tell kernel to use SE Linux by adding necessary parameters
kernelParams = ["security=selinux" "selinux=1"];
# compile kernel with SE Linux support
# with additional support for other LSM modules
kernelPatches = [
{
name = "selinux-config";
patch = null;
extraConfig = ''
SECURITY_SELINUX y
SECURITY_SELINUX_BOOTPARAM n
SECURITY_SELINUX_DISABLE n
SECURITY_SELINUX_DEVELOP y
SECURITY_SELINUX_AVC_STATS y
SECURITY_SELINUX_CHECKREQPROT_VALUE 0
DEFAULT_SECURITY_SELINUX n
'';
}
];
};
environment = {
systemPackages = with pkgs; [policycoreutils]; # for load_policy, fixfiles, setfiles, setsebool, semodile, and sestatus.
# write selinux config to /etc/selinux
etc."selinux/config".text = ''
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=${cfg.state}
# SELINUXTYPE= can take one of three two values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE=${cfg.type}
'';
};
};
}

View file

@ -0,0 +1,79 @@
{lib, ...}: let
inherit (lib) mkForce mkDefault;
in {
security = {
# https://github.com/NixOS/nixpkgs/pull/256491
# no nixpkgs, you are not breaking my system because of "muh rust" delusions again
# sudo-rs is still a feature-incomplete sudo fork that can and will mess things up
# also for the love of god stop rewriting things in rust
sudo-rs.enable = mkForce false;
# the ol' reliable
sudo = {
enable = true;
# WARNING: wheelNeedsPassword = false means wheel group can execute commands without a password
# this is especially useful if you are using --target-host option in nixos-rebuild switch
# however it's also a massive security flaw - which is why it should be replaced with the
# extraRules you will see below
wheelNeedsPassword = mkDefault false;
# only allow members of the wheel group to execute sudo
# by setting the executables permissions accordingly
execWheelOnly = mkForce true;
# additional sudo configuration
extraConfig = ''
Defaults lecture = never # rollback results in sudo lectures after each reboot, it's somewhat useless anyway
Defaults pwfeedback # password input feedback - makes typed password visible as asterisks
Defaults env_keep += "EDITOR PATH DISPLAY" # variables that will be passed to the root account
Defaults timestamp_timeout = 300 # makes sudo ask for password less often
'';
# additional sudo rules
# this is a better approach for making certain commands sudo-less instead of
# allowing the wheel users to run *anything* without password
# FIXME: something is missing, causing the rebuilds to ask for sudo regardless
extraRules = [
{
# allow wheel group to run nixos-rebuild without password
# this is a less vulnerable alternative to having wheelNeedsPassword = false
# whitelist switch-to-configuration, allows --target-host option
# to deploy to remote servers without reading password from STDIN
groups = ["wheel"];
commands = let
currentSystem = "/run/current-system/";
storePath = "/nix/store/";
in [
{
command = "${storePath}/*/bin/switch-to-configuration";
options = ["SETENV" "NOPASSWD"];
}
{
command = "${currentSystem}/sw/bin/nix-store";
options = ["SETENV" "NOPASSWD"];
}
{
command = "${currentSystem}/sw/bin/nix-env";
options = ["SETENV" "NOPASSWD"];
}
{
command = "${currentSystem}/sw/bin/nixos-rebuild";
options = ["NOPASSWD"];
}
{
# let wheel group collect garbage without password
command = "${currentSystem}/sw/bin/nix-collect-garbage";
options = ["SETENV" "NOPASSWD"];
}
{
# let wheel group interact with systemd without password
command = "${currentSystem}/sw/bin/systemctl";
options = ["NOPASSWD"];
}
];
}
];
};
};
}

View file

@ -0,0 +1,29 @@
{
config,
pkgs,
lib,
...
}: let
inherit (lib) mkIf;
sys = config.modules.system;
env = config.modules.usrEnv;
in {
config = mkIf sys.security.usbguard.enable {
services.usbguard = {
IPCAllowedUsers = ["root" "${env.mainUser}"];
presentDevicePolicy = "allow";
rules = ''
allow with-interface equals { 08:*:* }
# Reject devices with suspicious combination of interfaces
reject with-interface all-of { 08:*:* 03:00:* }
reject with-interface all-of { 08:*:* 03:01:* }
reject with-interface all-of { 08:*:* e0:*:* }
reject with-interface all-of { 08:*:* 02:*:* }
'';
};
environment.systemPackages = [pkgs.usbguard];
};
}

View file

@ -0,0 +1,6 @@
{
security.virtualisation = {
# flush the L1 data cache before entering guests
flushL1DataCache = "always";
};
}