The "Fortress" Architecture: A Reference Implementation
Target Hardware: ThinkPad X1 Carbon Gen 11 (Arch Linux)
Goal: Zero-Trust default posture for Boot, DMA, Peripherals, and Network, in addition to Full Disk Encryption (FDE) for the root filesystem (using LUKS2 automatically unlocked by the TPM cryptoprocessor), along with an extra layer of encryption for user data (using systemd-homed).
1. Boot & Encryption (The Foundation)
- Boot Method: Direct UEFI Boot (No Bootloader).
- Unified Kernel Image (UKI): Kernel, initrd, and cmdline packed into a single signed .efi binary, using kernel-install and ukify.
- Keys are created and enrolled with
sbctl kernel-installinvokesmkinitcpioandukifyvia defaut plugins- Be sure to follow the wiki to mask the mkinitcpio
pacmanhooks so mkinitcpio doesn't try to install or uninstall the kernel!
- Be sure to follow the wiki to mask the mkinitcpio
sbverify(from sbsigntools) should be used to verify the UKI signature, rather thansbctl verify. The latter doesn't handle certain gaps within the signature which don't violate the specification
- Keys are created and enrolled with
- Encryption:
- LUKS2 with TPM2 binding (
systemd-cryptenroll) - systemd-homed
- LUKS2 with TPM2 binding (
- Behavior: The firmware directly launches the kernel from the default fallback path. Silent, password-less boot if the environment is tamper-free. With a completely silent boot, anyone in possession of my X1 Carbon will see the Lenovo logo flash a time or two, then be dropped to the TTY login prompt.
Implementation Details
- Secure Boot: Custom keys created and enrolled via
sbctl. Microsoft Third Party CA certificate keys not enrolled, and not allowed via UEFI BIOS Security/Secure Boot menu (this is an option in this Lenovo BIOS). - Path Management: Custom kernel install plugin 99-fallback.install automatically moves the generated UKI to /efi/EFI/BOOT/BOOTX64.EFI after every kernel update.
#!/bin/bash # /etc/kernel/install.d/99-fallback.install COMMAND="$1" KERNEL_VERSION="$2" ENTRY_DIR_ABS="$3" KERNEL_IMAGE="$4" # Only run on "add" command if [ "$COMMAND" = "add" ]; then TARGET_DIR="/efi/EFI/Linux" # Find the newly generated UKI (sorting by time to get the freshest) SIGNED_UKI=$(find "$TARGET_DIR" -name "*${KERNEL_VERSION}*.efi" -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" ") if [ -f "$SIGNED_UKI" ]; then echo "Found signed UKI: $SIGNED_UKI" [[ -x /efi/EFI/BOOT/BOOTX64.EFI ]] && echo "Backing up existing fallback kernel..." && \ mv /efi/EFI/BOOT/BOOTX64.EFI /efi/EFI/BOOT/BOOTX64.BAK echo "Moving to fallback path: /efi/EFI/BOOT/BOOTX64.EFI" mkdir -p /efi/EFI/BOOT # MOVE instead of COPY to prevent duplicates/scanning mv -f "$SIGNED_UKI" /efi/EFI/BOOT/BOOTX64.EFI # Optional: Clean up the directory if empty so it doesn't leave ghost folders rmdir "$TARGET_DIR" --ignore-fail-on-non-empty 2>/dev/null else echo "Error: Could not find signed UKI for version $KERNEL_VERSION in $TARGET_DIR" exit 1 fi fi # write KERNEL_VERSION to /run/next_kernel, to help detect # when a reboot is necessary after a kernel upgrade echo "${KERNEL_VERSION}" > /run/next_kernel - Benefit: Zero NVRAM writes (avoids efivarfs bloat) and zero bootloader configuration to maintain (thus reducing the attack surface even further).
- TPM Enrollment:
systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 ${device}
2. Kernel & DMA Protection (Memory Isolation)
UEFI BIOS Settings:
- Administrator Password: Set to be required to enter BIOS menu (F1), and to enter boot menu (F12). This prevents local attackers from changing settings or booting off of removable media. Note, REMEMBER THIS PASSWORD!!!! At least with this ThinkPad model, there is no way (according to the Lenovo Linux User Guide) to reset it short of replacing the mainboard.
- Virtualization (VT-d): Enabled (Hardware IOMMU switch).
- Kernel DMA Protection: Enabled (Pre-boot protection).
- Intel Total Memory Encryption: Enabled (deters cryogenic attacks)
- Bottom Cover Tamper Detection: Immediately prompt for administrator password on the next boot if the bottom cover is removed (e.g., to remove or replace the SSD, or any other hardware component).
Kernel Command Line (inside UKI):
NOTE: The kernel parameters are stored in /etc/kernel/cmdline, and cannot be edited when the UKI is booted. This prevents a local attacker from trying to enter single user mode.
intel_iommu=on iommu=pt(Enforce strict IOMMU groups).rd.shell=0(Disable root shell in initramfs for physical security).- Verification: The following command must return non-empty output:
find /sys/kernel/iommu_groups/ -maxdepth 0 -not -empty
3. Thunderbolt/USB4 (The Gatekeeper)
- Strategy: Hybrid Policy. Block strangers by default (Global Manual),
allow specific trusted hardware (Device Auto). - Global Policy: "Manual" (Default Deny). Strangers are blocked until
authorized. - Trusted Dock: "Auto" (Whitelist). Trusted UUIDs get immediate PCIe
access.
Implementation
-
Block Strangers: Ensure global policy is effectively manual.
- Note on modern ThinkPads: Firmware often forces policy:
autofor
IOMMU-safe devices. We override this by controlling the specific device
records.
- Note on modern ThinkPads: Firmware often forces policy:
-
Whitelist Dock: Force the trusted dock to auto-connect,
bypassing manual checks
sudo boltctl enroll --policy auto <UUID>
Status Check
- Stranger: status: connected (PCIe blocked, USB fallback active).
- Trusted Dock: status: authorized (PCIe active).
4. USB Security (The Perimeter)
- Tool: usbguard
- Strategy: "Implicit Block" (Silent Drop).
- Why: Prevents "Rubber Ducky" (also known as BadUSB) attacks and blocks the USB fallback mode of malicious Thunderbolt docks. Block is "silent" in that it gives unauthorized devices no indication that they're blocked, as if the signaling of the physical port is broken. Contrast this with Reject, where the device is told it is unauthorized.
Implementation
- Set "Default Deny":
- Edit /etc/usbguard/usbguard-daemon.conf
- Set
ImplicitPolicyTarget=block
- New Device Routine:
sudo usbguard list-devices | grep block sudo usbguard allow-device <ID> -p - Snapshot Trusted Devices:
sudo usbguard generate-policy > /etc/usbguard/rules.conf
CRITICAL:
Verify your internal keyboard/root hub are in this file!
5. Network Hardening (Hardware-Level Trust)
- Strategy: Move trust from IP subnets (spoofable) to home MACs/BSSIDs (Hardware). Disable Bluetooth discoverability and pairability when away from home; set discoverability and pairing timeouts in case discoverability and pairing is explicitly enabled to pair a new device.
- Tools: firewalld + NetworkManager dispatcher.
A. Create the Trusted Zone:
Check if the fortress zone exists, and create it if it doesn't already exist:
sudo firewall-cmd --get-zones | grep -q fortress || \
sudo firewall-cmd --permanent --new-zone=fortress
Bind to Router MAC (Hardware Trust)
sudo firewall-cmd --permanent --zone=fortress --add-source=AA:BB:CC:DD:EE:FF
sudo firewall-cmd --permanent --zone=fortress --add-service=ssh
sudo firewall-cmd --reload
B. Set default zone to drop
The default policy of the drop zone is DROP, which means it does not respond to even ICMP requests.
sudo firewall-cmd --set-default-zone=drop
C. Ensure WireGuard interfaces are in trusted wireguard zone:
Check if wireguard zone exists and create it if it doesn't. Add the ssh service to it, and then add all WireGuard interfaces to it.
sudo firewall-cmd --get-zones | grep -q wireguard || \
sudo firewall-cmd --permanent --new-zone=wireguard
sudo firewall-cmd --permanent --zone=wireguard --add-service ssh
sudo firewall-cmd --permanent --zone=wireguard --add-interface wg0
sudo firewall-cmd --permanent --zone=wireguard --add-interface wg1
sudo firewall-cmd --permanent --zone=wireguard --add-interface wg2
sudo firewall-cmd --reload
D. Lockdown Bluetooh:
- File: /etc/bluetooth/main.conf
- Logic: Disables always-on discoverability and pairing, and also sets timeouts for both should the admin turn them on to pair a new device (and forget to shutdown pairability and discoverability once the new device is paired).
[General]
# 1. Timed visibility: If you enable scanning, it automatically turns off after 30s.
DiscoverableTimeout = 30
PairableTimeout = 30
# 2. The Big Switch: Disable auto-pairing.
# You MUST run 'pairable on' manually to add new devices.
AlwaysPairable = false
# 3. Privacy: Randomize MAC address during discovery to prevent tracking.
Privacy = device
[Policy]
# 4. Security: Block "Just Works" (no-PIN) repairing attempts.
# Prevents attackers from hijacking an existing pairing.
JustWorksRepairing = never
If you make any changes to main.conf, restart bluetooth.service.
E. The Dispatcher Script:
- File: /etc/NetworkManager/dispatcher.d/99-fortress-barbican
INFO: The barbican was the fortified gate in the outer wall of a castle. It's what had the drawbridge (if the castle had a moat), the portcullis, and the murder holes.
- Logic: Checks WiFi BSSIDs and Gateway ARP MACs before changing zones.
#!/bin/bash
INTERFACE=$1
ACTION=$2
if [ "$ACTION" = "up" ]; then
CURRENT_BSSID=$(nmcli -t -f active,bssid dev wifi | grep '^yes' | cut -d: -f2-8 | tr -d '\\' | tr '[[:upper:]]' '[[:lower:]]')
GATEWAY_IP=$(ip route show default | awk '/default/ {print $3}')
GATEWAY_MAC=$(ip neighbor show "$GATEWAY_IP" | awk '{print $5}' | tr '[[:upper:]]' '[[:lower:]]')
HOME_BSSID="11:22:33:44:55:66"
ROUTER_MAC="aa:bb:cc:dd:ee:ff"
if [ "$CURRENT_BSSID" == "$HOME_BSSID" ] || [ "$GATEWAY_MAC" == "$ROUTER_MAC" ]; then
logger "Fortress: Trusted hardware detected. Switching $INTERFACE to trusted zone 'fortress'."
firewall-cmd --zone=fortress --change-interface="$INTERFACE"
else
logger "Fortress: Unknown environment. Locking down $INTERFACE to public, and locking Bluetooth."
firewall-cmd --zone=public --change-interface="$INTERFACE"
# 1. Force Bluetooth Discoverable OFF (Invisible)
bluetoothctl discoverable off
# 2. Force Bluetooth Pairable OFF (Reject new connections)
bluetoothctl pairable off
fi
fi
6. Implementation Caveats
- Backup UKI: While I don't use a bootloader menu, the install script automatically rotates the previous kernel to /efi/EFI/BOOT/BOOTX64.BAK. If the new kernel fails to boot, I can use the UEFI Shell or a live rescue medium (such as the Arch ISO) to rename this backup file and recover the system.
- UEFI Fallback Path: The file must be named BOOTX64.EFI (case-insensitive usually, but standard spec) and located in esp\EFI\BOOT\ for the BIOS to auto-discover it without an NVRAM entry.
- OptionROMs: If doing this on a different laptop model, disallowing Microsoft Third Party CA certificates may not be wise. If any hardware OptionROM signed by Microsoft is necessary to load before firmware hands control over to the initramfs, you may not be able to boot. Even worse, it could prevent you from getting into the UEFI BIOS menu, thus hardware bricking your laptop.
- Btrfs Swapfiles: Must have +C (No-CoW) attribute set after swapfile is created (and before
swapon), or hibernation will fail/corrupt data. - Thunderbolt Fallback: A blocked Thunderbolt dock (boltd) will fallback to USB mode (Mouse/Video works). You must use usbguard to block the USB functionality if you want a total lockout.
- TPM Updates: Any change to BIOS, Secure Boot keys, or LUKS headers requires re-enrollment (
systemd-cryptenroll).- Firmware Updates: (with LVFS
fwupd)- Disable Secure Boot in UEFI BIOS/Security/Secure Boot. This will retain platform and any other enrolled keys.
a. At least with this ThinkPad, I also need to disable the administrator password for the boot menu (F12); otherwisefwupdwill show warnings and won't be able to update the firmware. - With Secure Boot disabled, TPM will not automatically unlock LUKS2 container. Recovery key or passphrase will be required upon reboot.
- Once booted, start
fwupd. You may also need to startudisks2beforehand if not already started. - Run
sudo fwupdmgr get-updates. - Allow the system to reboot to install firmware updates.
- Re-enable Secure Boot in the UEFI BIOS menu Security/Secure Boot. Also, re-enable the administrator password to reach the BIOS boot menu.
- Upon reboot the TPM may prompt for the recovery key or passphrase; this is your clue the keys need to be re-enrolled.
- Disable Secure Boot in UEFI BIOS/Security/Secure Boot. This will retain platform and any other enrolled keys.
- TPM Re-Enrollment:
I have a Zsh function that I can execute on next login if the TPM slot in the LUKS2 header needs to be wiped and re-enrolled:sudo systemd-cryptenroll --wipe=tpm2 --tpm2-device=auto --tpm2-pcrs=0+7 ${device}fix_tpm () { local device="${1:-/dev/nvme0n1p2}" echo "🔐 Re-enrolling TPM2 for device: $device" if sudo sbctl status | grep --color=auto -q "Setup Mode: Enabled" then echo "⚠️ Secure Boot is in Setup Mode. Enrolling CUSTOM keys only." sudo sbctl enroll-keys fi sudo systemd-cryptenroll "$device" --wipe-slot=tpm2 --tpm2-device=auto --tpm2-pcrs=0+7 if [ $? -eq 0 ] then echo "✅ TPM re-enrollment successful." else echo "❌ TPM re-enrollment failed." fi } - Firmware Updates: (with LVFS
7. TODO
- SELinux: The best defense against malware embedding itself into the OS. Need to learn how to write SELinux policies and adapt the reference policy for Arch Linux Perhaps submit policy to Arch Linux project, for refinement and getting SELinux and all related packages into the core repository.
- Other: Explore modern ways to protect against Linux malware, like cryptominers, rootkits, info stealers, or worms.