refactor: complete rewrite

This commit is contained in:
ooks-io 2024-10-23 23:46:25 +13:00
parent 19a4bbda3c
commit 8e81943cf9
399 changed files with 3396 additions and 8042 deletions

View file

@ -0,0 +1,49 @@
{
lib,
config,
pkgs,
inputs,
inputs',
self',
self,
keys,
...
}: let
inherit (lib) mkIf;
inherit (config.ooknet.host) role admin;
ifTheyExist = groups: builtins.filter (group: builtins.hasAttr group config.users.groups) groups;
in {
config = {
users.users.${admin.name} = {
isNormalUser = true;
shell = pkgs.${admin.shell};
initialPassword = "password";
openssh.authorizedKeys.keys = [keys.users."${admin.name}"];
extraGroups =
[
"wheel"
"video"
"audio"
]
++ ifTheyExist [
"git"
"media"
"network"
"libvirtd"
"streamer"
"torrenter"
];
};
home-manager = mkIf (role == "workstation" || admin.homeManager) {
useGlobalPkgs = true;
useUserPackages = true;
backupFileExtension = "hm.old";
verbose = true;
extraSpecialArgs = {inherit inputs inputs' self self';};
users.${admin.name} = {
imports = ["${self}/modules/home/base"];
};
};
};
}

View file

@ -0,0 +1,31 @@
{lib, ...}: let
inherit (lib) mkDefault;
in {
boot = {
loader = {
systemd-boot = {
enable = mkDefault true;
consoleMode = "max";
editor = false;
configurationLimit = 5;
};
efi.canTouchEfiVariables = mkDefault true;
};
initrd = {
availableKernelModules = [
"nvme"
"xhci_pci"
"ahci"
"usbhid"
"usb_storage"
"sd_mod"
];
kernelModules = [
"nvme"
"xhci_pci"
"btrfs"
"sd_mod"
];
};
};
}

View file

@ -0,0 +1,14 @@
{
imports = [
./nix.nix
./boot.nix
./admin.nix
./locale.nix
./options.nix
./secrets.nix
./openssh.nix
./tailscale.nix
./networking.nix
./security
];
}

View file

@ -0,0 +1,9 @@
{
time.timeZone = "Pacific/Auckland";
location.provider = "geoclue2";
services.geoclue2.enable = true;
i18n = {
defaultLocale = "en_US.UTF-8";
supportedLocales = ["en_US.UTF-8/UTF-8"];
};
}

View file

@ -0,0 +1,45 @@
{lib, ...}: let
inherit (lib) mkForce mkDefault;
in {
imports = [
./openssh.nix
./tailscale.nix
];
networking = {
enableIPv6 = true;
# disable global dhcp
useDHCP = mkForce false;
usePredictableInterfaceNames = mkDefault true;
nameservers = [
#quad9 IPv6
"2620:fe::fe"
"2620:fe::9"
#quad9 IPv4
"9.9.9.9"
"149.112.112.112"
];
networkmanager = {
enable = true;
dns = "systemd-resolved";
wifi = {
macAddress = "random";
scanRandMacAddress = true;
powersave = true;
};
unmanaged = ["interface-name:tailscale*"];
};
};
services = {
resolved = {
enable = true;
domains = ["~."];
fallbackDns = ["9.9.9.9"]; #quad9
#dnsovertls = "true";
};
};
systemd.services.NetworkManager-wait-online.enable = false;
}

View file

@ -0,0 +1,69 @@
{
inputs,
pkgs,
lib,
config,
...
}: let
inherit (builtins) attrValues;
inherit (lib) mkIf mapAttrsToList;
inherit (config.ooknet.host) admin;
in {
environment = {
# disable default nix packages
# these packages are installed by default [ perl rsync strace ]
defaultPackages = [];
systemPackages = attrValues {
inherit (pkgs) git deadnix statix;
inherit (inputs.agenix.packages.${pkgs.system}) default;
};
};
nix = {
# package = pkgs.lix;
registry = {
nixpkgs.flake = inputs.nixpkgs;
default.flake = inputs.nixpkgs;
};
nixPath = mapAttrsToList (name: _: "${name}=${name}") config.nix.registry;
settings = {
trusted-users = ["@wheel" "root"];
experimental-features = ["nix-command" "flakes"];
accept-flake-config = true;
auto-optimise-store = true;
# cache
substituters = [
"https://cache.nixos.org?priority=10"
"https://nix-community.cachix.org"
"https://neovim-flake.cachix.org"
];
trusted-public-keys = [
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
"neovim-flake.cachix.org-1:iyQ6lHFhnB5UkVpxhQqLJbneWBTzM8LBYOFPLNH4qZw="
];
# TODO: setup builders -- builders-use-substitutes = true;
};
};
nixpkgs = {
config.allowUnfree = true;
# why are we doing this
overlays = [
# zellij status bar plugin
(_final: prev: {
zjstatus = inputs.zjstatus.packages.${prev.system}.default;
})
];
};
# nix rebuild utililty
programs.nh = {
enable = true;
# sets an environment variable FLAKE that nh will refer to by default
flake = mkIf admin.homeManager "/home/${admin.name}/.config/ooknet";
# garbage collect
clean = {
enable = true;
extraArgs = "--keep 5 --keep-since 14d";
};
};
}

View file

@ -0,0 +1,82 @@
{
services.openssh = {
enable = true;
startWhenNeeded = true;
ports = [22];
settings = {
UseDns = true;
PubkeyAuthentication = "yes";
PermitRootLogin = "no";
PermitEmptyPasswords = "no";
PasswordAuthentication = false;
# disable support for .rhost files
IgnoreRhosts = "yes";
# by default openssh uses port 22
# restict key exchange, cipher, and MAC algorithms, as per <https://www.ssh-audit.com>
KexAlgorithms = [
"sntrup761x25519-sha512@openssh.com"
"curve25519-sha256"
"curve25519-sha256@libssh.org"
"diffie-hellman-group18-sha512"
"diffie-hellman-group-exchange-sha256"
"diffie-hellman-group16-sha512"
];
Ciphers = [
"chacha20-poly1305@openssh.com"
"aes256-gcm@openssh.com"
"aes256-ctr"
"aes192-ctr"
"aes128-gcm@openssh.com"
"aes128-ctr"
];
Macs = [
"hmac-sha2-512-etm@openssh.com"
"hmac-sha2-256-etm@openssh.com"
"umac-128-etm@openssh.com"
];
/*
HostKeyAlgorithms = [
"sk-ssh-ed25519-cert-v01@openssh.com"
"ssh-ed25519-cert-v01@openssh.com"
"rsa-sha2-512-cert-v01@openssh.com"
"sk-ssh-ed25519@openssh.com,ssh-ed25519"
"ssh-ed25519"
"rsa-sha2-512"
"rsa-sha2-256"
];
CASignatureAlgorithms = [
"sk-ssh-ed25519@openssh.com"
"ssh-ed25519"
"rsa-sha2-512"
"rsa-sha2-256"
];
GSSAPIKexAlgorithms = [
"gss-curve25519-sha256-"
"gss-group16-sha512"
];
HostbasedAcceptedAlgorithms = [
"sk-ssh-ed25519-cert-v01@openssh.com"
"ssh-ed25519-cert-v01@openssh.com"
"rsa-sha2-512-cert-v01@openssh.com"
"rsa-sha2-256-cert-v01@openssh.com"
"sk-ssh-ed25519@openssh.com"
"ssh-ed25519,rsa-sha2-512"
"rsa-sha2-256"
];
PubkeyAcceptedAlgorithms = [
"sk-ssh-ed25519-cert-v01@openssh.com"
"ssh-ed25519-cert-v01@openssh.com"
"rsa-sha2-512-cert-v01@openssh.com"
"rsa-sha2-256-cert-v01@openssh.com"
"sk-ssh-ed25519@openssh.com"
"ssh-ed25519"
"rsa-sha2-512"
"rsa-sha2-256"
];
*/
};
};
}

View file

@ -0,0 +1,48 @@
{lib, ...}: let
inherit (lib) mkOption;
inherit (lib.types) str enum bool;
in {
options.ooknet.host = {
name = mkOption {
type = str;
default = "ooks-generic";
};
type = mkOption {
type = enum ["desktop" "laptop"];
};
role = mkOption {
type = enum ["workstation" "server"];
};
exitNode = mkOption {
type = bool;
default = false;
};
admin = {
name = mkOption {
type = str;
default = "ooks";
};
shell = mkOption {
type = enum ["bash" "zsh" "fish"];
default = "fish";
};
gitName = mkOption {
type = str;
default = "ooks-io";
};
gitEmail = mkOption {
type = str;
default = "ooks@protonmail.com";
};
homeManager = mkOption {
type = bool;
default = false;
description = ''
Home-manager is enabled if ooknet.host.role == "workstation".
If host is not a workstation and you would like to enable home-manager
enable this option.
'';
};
};
};
}

View file

@ -0,0 +1,31 @@
{
config,
lib,
self,
...
}: let
inherit (lib) mkIf;
inherit (config.ooknet) host;
inherit (host) admin;
inherit (config.services) tailscale;
in {
age.identityPaths = [
"/home/${admin.name}/.ssh/id_ed25519"
];
age.secrets = {
tailscale-auth = mkIf tailscale.enable {
file = "${self}/secrets/tailscale-auth.age";
owner = "${admin.name}";
group = "users";
mode = "400";
};
github_key = mkIf admin.homeManager {
file = "${self}/secrets/github_key.age";
path = "/home/${admin.name}/.ssh/github_key";
owner = "${admin.name}";
group = "users";
};
};
}

View file

@ -0,0 +1,68 @@
{
pkgs,
config,
lib,
...
}: let
inherit (builtins) attrValues;
inherit (lib) getExe;
in {
security = {
apparmor = {
enable = true;
# packages to include with apparmors path
packages = [pkgs.apparmor-profiles];
# kill any process that does not have a apparmor profile enabled
killUnconfinedConfinables = true;
# apparmor policies
# FIXME
policies = {
"default_deny" = {
enforce = false;
enable = false;
profile = ''
profile default_deny /** { }
'';
};
"nix" = {
enforce = false;
enable = false;
profile = ''
${getExe config.nix.package} {
unconfined,
}
'';
};
"sudo" = {
enforce = false;
enable = false;
profile = ''
${getExe pkgs.sudo} {
file /** rwlkUx,
}
'';
};
};
};
};
# enable apparmor mode for dbus
services.dbus.apparmor = "enabled";
# apparmor packages to add to path
environment.systemPackages = attrValues {
inherit
(pkgs)
apparmor-utils
apparmor-bin-utils
apparmor-kernel-patches
apparmor-parser
apparmor-profiles
apparmor-pam
libapparmor
;
};
}

View file

@ -0,0 +1,9 @@
{pkgs, ...}: {
security = {
audit = {
enable = true;
rules = ["-a exit, always -F arch=b64 -s execve"];
};
};
environment.systemPackages = [pkgs.lynis];
}

View file

@ -0,0 +1,10 @@
{
imports = [
./tcp.nix
./sudo.nix
./kernel.nix
./firewall.nix
./auditing.nix
./apparmor.nix
];
}

View file

@ -0,0 +1,8 @@
{
networking.firewall = {
enable = true;
# dont respond to icmpv4 pings.
allowPing = false;
};
}

View file

@ -0,0 +1,198 @@
{
lib,
config,
...
}: let
inherit (lib) optionals mkForce concatLists;
inherit (builtins) elem;
inherit (config.ooknet.hardware) features;
in {
# see:
# <https://madaidans-insecurities.github.io/guides/linux-hardening.html>
# github:notashelf/nyx
security = {
# Protects the kernel from being tampered with at runtime. prevents the ability to hibernate.
protectKernelImage = true;
# page table isolation (PTI) is a kernel option designed to protect against
# side-channel attacks, including Meltdown & Spectre vunerabilities.
forcePageTableIsolation = true;
# locking kernel modules during runtime breaks certain services by stopping them from being
# loaded at runtime. we use some of these services, so we disable this kernel option.
lockKernelModules = false;
# we enable simultaneous multithreading (SMT) because while it increases our attack surface
# disabling it comes at a large perfomance loss.
allowSimultaneousMultithreading = true;
# slight increase in attack surface, but allows for sandboxing
allowUserNamespaces = true;
# we don't need unpivileged user namespaces unless we are messing with containers so we disable
unprivilegedUsernsClone = false;
};
boot = {
kernel = {
sysctl = {
# obfuscate kernel pointers to protect against attacks that rely on memory layout of the kernel
"kernel.kptr_restrict" = 2;
# we don't make use of sysrq so we disable it to protect ourselves against potential physical attacks
"kernel.sysrq" = mkForce 0;
# limits the exposer of the kernel memory address via dmesg
"kernel.dmesg_restrict" = 1;
# we are not a kernel developer so we disable this to prevent potential information leaks & attacks
"kernel.ftrace_enabled" = false;
# disables performance events for all non-root users, root can only acess events that are explicitly
# enabled.
"kernel.perf_event_paranoid" = 3;
# disables the use of berkeley packet filter (BPF) to unpriviliged users.
"kernel.unprivileged_bpf_disabled" = 1;
# prevents potentially leaking sensitive information from the boot console kernel log.
"kernel.printk" = "3 3 3 3";
# just-in-time (JIT) compiler for the berkeley packet filter (BPF). disable this as we dont make use
# of it and reduces potential security risks.
"net.core.bpf_jit_enable" = false;
# disables core dumps for SUID and SGID this reduces the risk of exposing sensitive information
# that might reside in the memory at the time of a crash
"fs.suid_dumpable" = 0;
# enforces strict access to files only allows the user or root to write regular files
"fs.protected_regular" = 2;
"fs.protected_fifos" = 2;
# disables the automatic loading of TTY line disciplines
"dev.tty.ldisc_autoload" = "0";
};
};
# https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html
kernelParams = [
# kernel errors can trigger something known as an "oops", by settings oops=panic we add a fail-safe
# mechanism to ensure that in the advent of an oops the system reboots, preventing the system from running
# in a potentially compromised state.
"oops=panic"
# enforces signature checking on all kernel modules before they are loaded.
"module.sig_enforce=1"
# enables memory page poisoning, increasing the difficulty for attackers to exploit
# use-after-free vulnerabillities.
"page_poison=on"
# enables kernel adress space layout randomization (KASLR) which mitigates memory exploits
# & increases system entropy.
"page_alloc.shuffle=1"
# randomizes the kernel stack offset, mitigating stack-based attacks.
"randomize_kstack_offset=on"
# lockdown aims to restrict certain kernel functionality that could be exploited by an attacker with
# user space code.
"lockdown=confidentiality"
# disables a common interface that contains sensitive info on the kernel
"debugfs=off"
# prevent kernel from blanking plymouth out of the frame buffer console
"fbcon=nodefer"
# enables auditing of integrity measurement events
"integrity_audit=1"
# increases memory safety by modifying the state of the memory objects more closely & helps detecting
# & identifying bugs
"slub_debug=FZP"
# disables the legacy vyscall mechanism, reducing attack surface.
"vsyscall=none"
# reduce exposure to heap attacks by preventing different slab caches from being merged.
"slab_nomerge"
"rootflags=noatime"
"lsm=landlock,lockdown,yama,integrity,apparmor,bpf,tomoyo,selinux"
];
blacklistedKernelModules = 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"
]
# if bluetooth is enabled, whitelist the module
# necessary for bluetooth dongles to work
(optionals (! (elem "bluetooth" features)) [
"bluetooth" # let bluetooth work
"btusb" # let bluetooth dongles work
])
];
};
}

View file

@ -0,0 +1,15 @@
{
security = {
sudo = {
# allow wheel user to execute sudo without a password
wheelNeedsPassword = false;
# only allow users in the wheel access to sudo
execWheelOnly = true;
extraConfig = ''
Defaults pwfeedback # password feedback
Defaults lecture = never # disable warning message
Defaults timestamp_timeout=10 # set sudo timeout to 10 minutes
'';
};
};
}

View file

@ -0,0 +1,76 @@
{
# this is a collection of tcp related sysctl commands that are floating around,
# unsure who the original author is
# see:
# <https://madaidans-insecurities.github.io/guides/linux-hardening.html>
# github:fort-nix/nix-bitcoin
# github:hlissner/dotfiles
# github:notashelf/nyx
boot = {
kernel.sysctl = {
# TCP hardening
# Prevent bogus ICMP errors from filling up logs.
"net.ipv4.icmp_ignore_bogus_error_responses" = 1;
# Reverse path filtering causes the kernel to do source validation of
# packets received from all interfaces. This can mitigate IP spoofing.
"net.ipv4.conf.default.rp_filter" = 1;
"net.ipv4.conf.all.rp_filter" = 1;
# Do not accept IP source route packets (we're not a router)
"net.ipv4.conf.all.accept_source_route" = 0;
"net.ipv6.conf.all.accept_source_route" = 0;
# Don't send ICMP redirects (again, we're on a router)
"net.ipv4.conf.all.send_redirects" = 0;
"net.ipv4.conf.default.send_redirects" = 0;
# Refuse ICMP redirects (MITM mitigations)
"net.ipv4.conf.all.accept_redirects" = 0;
"net.ipv4.conf.default.accept_redirects" = 0;
"net.ipv4.conf.all.secure_redirects" = 0;
"net.ipv4.conf.default.secure_redirects" = 0;
"net.ipv6.conf.all.accept_redirects" = 0;
"net.ipv6.conf.default.accept_redirects" = 0;
# Protects against SYN flood attacks
"net.ipv4.tcp_syncookies" = 1;
# Incomplete protection again TIME-WAIT assassination
"net.ipv4.tcp_rfc1337" = 1;
# And other stuff
"net.ipv4.conf.all.log_martians" = true;
"net.ipv4.conf.default.log_martians" = true;
"net.ipv4.icmp_echo_ignore_broadcasts" = true;
"net.ipv6.conf.default.accept_ra" = 0;
"net.ipv6.conf.all.accept_ra" = 0;
"net.ipv4.tcp_timestamps" = 0;
# TCP optimization
# TCP Fast Open is a TCP extension that reduces network latency by packing
# data in the senders initial TCP SYN. Setting 3 = enable TCP Fast Open for
# both incoming and outgoing connections:
"net.ipv4.tcp_fastopen" = 3;
# Bufferbloat mitigations + slight improvement in throughput & latency
"net.ipv4.tcp_congestion_control" = "bbr";
"net.core.default_qdisc" = "cake";
# Other stuff that I am too lazy to document
"net.core.optmem_max" = 65536;
"net.core.rmem_default" = 1048576;
"net.core.rmem_max" = 16777216;
"net.core.somaxconn" = 8192;
"net.core.wmem_default" = 1048576;
"net.core.wmem_max" = 16777216;
"net.ipv4.ip_local_port_range" = "16384 65535";
"net.ipv4.tcp_max_syn_backlog" = 8192;
"net.ipv4.tcp_max_tw_buckets" = 2000000;
"net.ipv4.tcp_mtu_probing" = 1;
"net.ipv4.tcp_rmem" = "4096 1048576 2097152";
"net.ipv4.tcp_slow_start_after_idle" = 0;
"net.ipv4.tcp_tw_reuse" = 1;
"net.ipv4.tcp_wmem" = "4096 65536 16777216";
"net.ipv4.udp_rmem_min" = 8192;
"net.ipv4.udp_wmem_min" = 8192;
"net.netfilter.nf_conntrack_generic_timeout" = 60;
"net.netfilter.nf_conntrack_max" = 1048576;
"net.netfilter.nf_conntrack_tcp_timeout_established" = 600;
"net.netfilter.nf_conntrack_tcp_timeout_time_wait" = 1;
};
};
}

View file

@ -0,0 +1,50 @@
{
config,
lib,
...
}: let
inherit (lib.lists) concatLists optionals;
inherit (config.ooknet) host;
inherit (config.ooknet.host) admin;
inherit (config.services) tailscale;
in {
services.tailscale = {
enable = true;
# "client"/"both" - reverce path filtering will be set to loose instead of strict
# "server"/"both" - ip forwarding will be enabled
useRoutingFeatures = "both";
# user that can fetch tailscale tls certs
permitCertUid = "root";
# authentication key for auto connect service
authKeyFile = config.age.secrets.tailscale-auth.path;
# flags to pass to the auto-connect service
extraUpFlags = concatLists [
["--ssh"]
(optionals (admin.name != null) ["--opterator ${admin.name}"])
(optionals host.exitNode ["--advertise-exit-node"])
];
# opens relevant tailscale ports over UDP
openFirewall = true;
};
# trust tailscale default interface
networking.firewall.trustedInterfaces = ["${tailscale.interfaceName}"];
# credit github:notashelf/nyx
systemd = {
# ignore tailscale interface for wait-online service
network.wait-online.ignoredInterfaces = ["${tailscale.interfaceName}"];
# only start tailscale daemon after network-online and systemd-resolved services
# are up
services.tailscaled = {
after = ["network-online.target" "systemd-resolved.service"];
wants = ["network-online.target" "systemd-resolved.service"];
};
};
}