Security Overview
This section documents every hardening measure applied across both systems, with a focus on the server where the threat model is more demanding.
Threat Model
| Threat | Mitigation |
|---|---|
| Remote code execution via exposed service | All services run in NixOS containers with separate network namespaces; host kernel is hardened |
| Kernel exploitation | lockdown=confidentiality, module signature enforcement, blacklisted attack surface, restricted sysctls |
| Lateral movement after container compromise | Containers run in user namespaces, no host network access, minimal bind mounts |
| Credential theft | Secrets decrypted at activation via agenix, never in the Nix store, file permissions restricted per-service |
| Network-level attacks | ICMP disabled, IPv6 disabled, TCP hardened, BPF JIT hardened, no redirects/source routing |
| SSH brute force | Key-only auth, post-quantum KEX, 3 max auth tries, 2 max sessions |
| Physical access (server) | LUKS full-disk encryption, remote unlock via initrd SSH |
| Physical access (laptop) | LUKS + Secure Boot via Lanzaboote with auto-enrolled keys |
| Data loss | Daily restic backups with max compression, 7d/2w/1m retention |
| Stale software | Server auto-upgrades weekly; laptop uses nh for manual upgrades |
Attack Surface
Server
The server exposes exactly three ports to the LAN:
| Port | Protocol | Service |
|---|---|---|
| 22 | TCP | OpenSSH (key-only, post-quantum KEX) |
| 53 | TCP/UDP | AdGuard Home (DNS) |
| 80, 443 | TCP | Traefik (reverse proxy) |
No ports are forwarded from the internet. All external access flows through the Cloudflare Tunnel (outbound-only connection from the server to Cloudflare's edge).
Laptop
The laptop exposes no listening ports. The firewall is enabled with no allowed ports. WiFi uses iwd with MAC address randomisation.
Defence in Depth
Security is applied at every layer:
┌─────────────────────────────────────────────────┐
│ Layer 7 — Application │
│ Authelia (forward auth), Vaultwarden (no admin) │
├─────────────────────────────────────────────────┤
│ Layer 4 — Transport │
│ Cloudflare Tunnel, Traefik TLS termination │
├─────────────────────────────────────────────────┤
│ Layer 3 — Network │
│ nftables firewall, NAT for containers, │
│ ICMP disabled, IPv6 disabled │
├─────────────────────────────────────────────────┤
│ Process isolation │
│ NixOS containers (systemd-nspawn), │
│ user namespaces, systemd sandboxing │
├─────────────────────────────────────────────────┤
│ Kernel │
│ lockdown=confidentiality, module signing, │
│ slab_nomerge, init_on_alloc, ASLR 32-bit │
├─────────────────────────────────────────────────┤
│ Disk │
│ LUKS encryption, impermanence (root wiped), │
│ mount options (noexec, nosuid, nodev) │
└─────────────────────────────────────────────────┘Security Pages
| Page | Scope |
|---|---|
| Kernel Hardening | Boot parameters, blacklisted modules, sysctl protections |
| Network Hardening | IPv4/TCP/ICMP hardening, BPF, firewall rules |
| SSH Hardening | Post-quantum KEX, cipher suite, session limits |
| Secrets Management | agenix workflow, identity paths, secret ownership |
| Systemd Sandboxing | Cloudflared sandboxing, journald hardening, emergency mode |
Laptop vs Server Hardening
The server applies significantly more hardening than the laptop because it runs internet-facing services:
| Feature | Laptop | Server |
|---|---|---|
| Kernel lockdown | No | confidentiality |
| Module signature enforcement | No | Yes |
| Blacklisted modules | No | 30+ modules |
| Sysctl hardening | Basic (CachyOS defaults) | Comprehensive (kernel, network, VM) |
| Secure Boot | Yes (Lanzaboote) | No (headless, LUKS is primary) |
| Impermanence | No | Yes (root wiped every boot) |
| Firewall | Enabled, no open ports | Enabled, 3 ports open |
| SSH | Not running | Hardened with post-quantum KEX |
| Secrets management | Not used | agenix with per-service permissions |
| Systemd sandboxing | Default | Custom (Cloudflared, journald) |