// STATUS — OPERATIONAL · rev 2026-06-11 · LIVING BUILD
// Overview — Hardened Fedora workstation built to a defence-in-depth security model.
LUKS2 full-disk encryption requires physical hardware key presence for unlock. If the key is
unavailable, the machine can still be unlocked remotely over SSH from a GrapheneOS mobile
platform — without the initramfs ever trusting a password over the network. WireGuard routes
all external traffic; AdGuard Home filters all DNS to an encrypted upstream before it leaves
the host.
// Living Build — An actively maintained workstation build. The core hardware values were
captured and verified on 2026-06-11; a couple of secondary items (unlock-latency benchmark,
SELinux/seccomp status) remain pending and are labelled as such below.
Threat Model
The build addresses a specific threat model for a security practitioner whose workstation
stores research, tooling, and keys worth protecting against physical access, supply-chain
key compromise, and remote theft. Each component was chosen because it eliminates a
specific attack path — not because it adds capability.
| Threat | Control |
|---|---|
| Offline disk clone and brute-force | LUKS2 aes-xts-plain64/512-bit; Argon2id passphrase slot; hardware key required to unlock |
| Primary hardware key lost or seized | Backup Nitrokey keyslot; passphrase emergency fallback |
| Hardware key cloned without touch | Touch-only FIDO2 enrollment; Nitrokey 3A NFC requires physical presence |
| Remote workstation inaccessible for unlock | dracut-sshd: SSH into the initramfs over the pre-boot network |
| DNS traffic leakage and exfiltration | AdGuard Home → Quad9 DoH over the tunnel; no plaintext query leaves the host |
| Traffic interception and geolocation | WireGuard full-tunnel routing on all external traffic |
Components
LUKS2 Full-Disk Encryption
Encrypted volume: LUKS2 container UUID 6cbc50ba-6f8a-4932-abfc-f2d0504a29b3, mapped as
luks-6cbc50ba-…, cipher aes-xts-plain64, 512-bit key. Three keyslots: Slot 0 (passphrase,
Argon2id — emergency/recovery fallback, stored offline), Slot 1 (primary Nitrokey 3A NFC,
PBKDF2/SHA-512 — daily driver, touch required), Slot 2 (backup Nitrokey 3A NFC — kept offline).
The FIDO2 slots derive their key with the Nitrokey credential; the passphrase is never sent to the
key. crypttab references the volume by UUID with discard,x-initrd.attach,fido2-device=auto.
Nitrokey 3A NFC — FIDO2 Hardware Key
Hardware: Nitrokey 3A NFC · Firmware: 1.8.3 · Two tokens enrolled · Enrollment mode:
touch-only (fido2-up-required=true) with no clientPin (fido2-clientPin-required=false) —
physical presence is required for every unlock event, but no PIN is involved. clientPin is not
supported on this firmware; the touch-only constraint is intentional: a key activatable remotely
would defeat the physical-presence guarantee.
dracut-sshd — Remote Unlock via SSH
The initramfs is built with dracut-sshd (v0.7.1-5.fc44), plus the systemd-networkd and
fido2 modules, so wired networking comes up pre-boot (rd.neednet=1) and a Nitrokey touch can
satisfy the LUKS prompt directly. Unlock flow: machine reaches the initramfs SSH listener → the
GrapheneOS handset (Termux) connects over Tailscale (Tailscale runs on the client, not in the
initramfs — reachability comes from the LAN the pre-boot interface sits on being exposed over the
tailnet) → the embedded ed25519 public key authenticates (host key pinned on the client) →
systemd-tty-ask-password-agent drives the unlock, a Nitrokey present at the machine is touched,
and boot continues. Built on Fedora 44, kernel 7.0.11-200.fc44.x86_64.
WireGuard VPN — wg-CH-FI-2 and wg-SE-FI-1
Two NetworkManager tunnels: wg-CH-FI-2 (endpoint 79.135.104.69:51820) and
wg-SE-FI-1 (185.159.156.27:51820), each with full-tunnel AllowedIPs (0.0.0.0/0, ::/0),
interface address 10.2.0.2/32, and a 25-second keepalive. Activation is manual
(autoconnect=false). The named-tunnel model encodes the endpoint region for multi-tunnel
readability. Kill-switch — honest description: the protection is route-based, not a separate
fail-closed rule — while a tunnel is up, the full-tunnel AllowedIPs makes it the default route, so
traffic is tunnel-bound; there is no nftables/dispatcher rule that drops traffic if the interface
goes down (a hard fail-closed kill-switch is planned).
AdGuard Home DNS Filtering
AdGuard Home (install path /opt/AdGuardHome/) is the system resolver, listening on *:53
(pid 1452). Its only upstream is Quad9 over DNS-over-HTTPS (https://dns10.quad9.net/dns-query,
bootstrap 9.9.9.10 / 149.112.112.10), so every query leaves already encrypted and egresses
through the active WireGuard tunnel. Block list: AdGuard DNS filter. systemd-resolved forwards
all queries to 127.0.0.1 (stub listener off) so AdGuard owns port 53. DNS chain: application →
systemd-resolved (127.0.0.1) → AdGuard Home (:53) → Quad9 DoH → active WireGuard tunnel. The
no-plaintext-egress property rests on the DoH-over-tunnel upstream, not on a loopback bind. (The VPN
provider also pushes 10.2.0.1, but AdGuard overrides it — it is not the effective upstream.)
OpenRGB — Peripheral Configuration
Razer Huntsman V2 (keyboard), Razer Basilisk (mouse), 6× Corsair fans via Commander Pro.
OpenRGB provides vendor-agnostic RGB control without vendor cloud daemons (Razer Synapse,
iCUE). No vendor software installed. Commander Pro detected as USB HID device.
Security Architecture — Defence in Depth
| Layer | Control | Threat addressed |
|---|---|---|
| Physical | Nitrokey 3A NFC FIDO2, touch-only enrollment (fw 1.8.3, no clientPin) | Remote/unattended hardware-key activation |
| Disk | LUKS2 aes-xts-plain64/512-bit (UUID 6cbc50ba-…), Argon2id passphrase slot |
Offline disk clone and brute-force key derivation |
| Boot | dracut-sshd (v0.7.1-5.fc44) pre-boot SSH with pinned ed25519 host key | Unattended unlock; MITM key substitution during unlock |
| Key Custody | Primary Nitrokey, backup Nitrokey offline, offline emergency passphrase | Single point of key failure; primary key loss or seizure |
| Network | WireGuard wg-CH-FI-2 / wg-SE-FI-1 (NetworkManager, manual), full-tunnel routing |
Traffic interception, geolocation, leakage if tunnel drops |
| DNS | AdGuard Home on *:53 → Quad9 DoH over the active tunnel; systemd-resolved forwards to it |
Plaintext DNS leakage; tracker and malicious domain resolution |
Hardening Checklist — Component Status
| Status | Control | Protects against |
|---|---|---|
| Verified | LUKS2 aes-xts-plain64/512-bit, Argon2id + 2× FIDO2 — 3 keyslots active |
Offline disk clone and brute-force key derivation; memory-hard KDF raises GPU/ASIC guessing cost; keyslot custody removes single point of key failure |
| Verified | Nitrokey 3A NFC FIDO2 — 2 tokens, firmware 1.8.3, touch-only, no clientPin | Hardware-key activation without physical presence; touch required for every unlock event |
| Verified | dracut-sshd remote unlock — v0.7.1-5.fc44; systemd-networkd + fido2 modules | Headless machine impossible to unlock remotely; MITM key substitution (host key pinned); passphrase never sent over the network |
| Verified | WireGuard wg-CH-FI-2 + wg-SE-FI-1 — NetworkManager, manual, full-tunnel |
Traffic interception and geolocation; route-based kill-switch while the tunnel is up |
| Verified | AdGuard Home DNS filtering — Quad9 DoH upstream, *:53, AdGuard DNS filter |
Plaintext DNS leakage; tracker / malicious-domain resolution |
| Verified | systemd-resolved → 127.0.0.1 (stub listener off) | Applications bypassing the DNS filter |
| Verified | Build platform — Fedora 44, kernel 7.0.11-200.fc44.x86_64 | Reproducibility / auditability of the build |
| Verified | OpenRGB (Razer + Corsair) — vendor daemons absent | Vendor cloud-daemon telemetry; unnecessary supply-chain surface |
| PENDING | SELinux/seccomp status — getenforce && sestatus |
Reported only as measured on the host, never assumed |
| PENDING | LUKS2 unlock-latency benchmark — hardware key vs passphrase | A usability data point to be measured, not estimated |
PENDING — the two items above are secondary values not captured in the 2026-06-11 hardware
session (see the repo'sMANUAL_INPUTS.md). An honest gap beats invented completeness.
Skills Demonstrated
| Skill | Evidence |
|---|---|
| Linux Hardening | LUKS2 (aes-xts-plain64/512-bit) with keyslot management and Argon2id passphrase slot |
| FIDO2 / Hardware Key Integration | Nitrokey 3A NFC enrolled as LUKS2 keyslots (touch-only, no clientPin); CTAP2 credential flow |
| Initramfs Engineering | dracut-sshd (v0.7.1-5.fc44) pre-boot SSH with systemd-networkd + fido2; pinned ed25519 key |
| Network Security | WireGuard full-tunnel routing via NetworkManager; named-tunnel model for multi-tunnel readability |
| DNS Security | AdGuard Home → Quad9 DoH over the tunnel; encrypted upstream, no plaintext egress |
| Defence in Depth | Each threat mapped to a compensating control across physical, disk, boot, network, and DNS layers |
| Operational Security | Vendor cloud daemons eliminated; RGB peripherals managed via OpenRGB without telemetry |
| Remote Operations | SSH-based unlock from GrapheneOS; IRONVEIL ↔ NULLBYTE integration for remote boot without physical presence |
Repository & Context
// GitHub — Full build documentation, hardening notes, and research references:
github.com/rootdrifter/ironveil — one repository
in the github.com/rootdrifter portfolio.
// Why this matters — IRONVEIL is the operational evidence behind a security-cleared
candidate: a workstation built with the key-custody, least-trust, and defence-in-depth
discipline expected in cleared environments. The clearance is held now, not pending vetting —
deployable to cleared work from day one.