Skip to content

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

ThreatMitigation
Remote code execution via exposed serviceAll services run in NixOS containers with separate network namespaces; host kernel is hardened
Kernel exploitationlockdown=confidentiality, module signature enforcement, blacklisted attack surface, restricted sysctls
Lateral movement after container compromiseContainers run in user namespaces, no host network access, minimal bind mounts
Credential theftSecrets decrypted at activation via agenix, never in the Nix store, file permissions restricted per-service
Network-level attacksICMP disabled, IPv6 disabled, TCP hardened, BPF JIT hardened, no redirects/source routing
SSH brute forceKey-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 lossDaily restic backups with max compression, 7d/2w/1m retention
Stale softwareServer auto-upgrades weekly; laptop uses nh for manual upgrades

Attack Surface

Server

The server exposes exactly three ports to the LAN:

PortProtocolService
22TCPOpenSSH (key-only, post-quantum KEX)
53TCP/UDPAdGuard Home (DNS)
80, 443TCPTraefik (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

PageScope
Kernel HardeningBoot parameters, blacklisted modules, sysctl protections
Network HardeningIPv4/TCP/ICMP hardening, BPF, firewall rules
SSH HardeningPost-quantum KEX, cipher suite, session limits
Secrets Managementagenix workflow, identity paths, secret ownership
Systemd SandboxingCloudflared sandboxing, journald hardening, emergency mode

Laptop vs Server Hardening

The server applies significantly more hardening than the laptop because it runs internet-facing services:

FeatureLaptopServer
Kernel lockdownNoconfidentiality
Module signature enforcementNoYes
Blacklisted modulesNo30+ modules
Sysctl hardeningBasic (CachyOS defaults)Comprehensive (kernel, network, VM)
Secure BootYes (Lanzaboote)No (headless, LUKS is primary)
ImpermanenceNoYes (root wiped every boot)
FirewallEnabled, no open portsEnabled, 3 ports open
SSHNot runningHardened with post-quantum KEX
Secrets managementNot usedagenix with per-service permissions
Systemd sandboxingDefaultCustom (Cloudflared, journald)

Built with VitePress