Security Hardening
Quick Reference
# Check encrypted volumes
lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT
dmsetup status
# SSH key types
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_github -C "github"
# Secrets management
gopass list
gopass show path/to/secret
Disk Encryption Strategy
Multi-Volume LUKS Architecture
Separate encrypted volumes provide security segmentation:
| Volume | Size | Contains | Rationale |
|---|---|---|---|
cryptroot |
~250GB |
System files, packages |
OS can be wiped/reinstalled independently |
crypthome |
Remainder |
User data, configs |
Survives OS reinstalls |
cryptdata |
Separate drive |
VMs, large data |
Independent drive, separate passphrase option |
Partition Layout
# Recommended layout (UEFI)
nvme0n1 # System drive
├─nvme0n1p1 512M vfat /boot/efi # EFI System Partition
├─nvme0n1p2 2G ext4 /boot # Unencrypted boot
├─nvme0n1p3 250G LUKS cryptroot # Encrypted root
└─nvme0n1p4 REST LUKS crypthome # Encrypted home
nvme1n1 # Data drive (optional)
└─nvme1n1p1 ALL LUKS cryptdata # Encrypted data
Creating LUKS Volumes
# Create LUKS2 container (root)
cryptsetup luksFormat --type luks2 \
--cipher aes-xts-plain64 \
--key-size 512 \
--hash sha512 \
--iter-time 5000 \
/dev/nvme0n1p3
# Create LUKS2 container (home)
cryptsetup luksFormat --type luks2 /dev/nvme0n1p4
# Open volumes
cryptsetup open /dev/nvme0n1p3 cryptroot
cryptsetup open /dev/nvme0n1p4 crypthome
# Verify
ls /dev/mapper/
# cryptroot crypthome
LUKS Best Practices
# Use strong passphrases (diceware recommended)
# Example: "correct-horse-battery-staple-quantum"
# Backup LUKS header (CRITICAL)
cryptsetup luksHeaderBackup /dev/nvme0n1p3 \
--header-backup-file /secure/location/cryptroot.header
# Add backup key (recovery)
cryptsetup luksAddKey /dev/nvme0n1p3
# Check LUKS status
cryptsetup luksDump /dev/nvme0n1p3
# Benchmark encryption (choose best cipher)
cryptsetup benchmark
Btrfs Subvolume Architecture
Subvolume Strategy
| Subvolume | Mount Point | Purpose |
|---|---|---|
@ |
/ |
Root filesystem |
@home |
/home |
User data (separate LUKS) |
@snapshots |
/.snapshots |
Snapper snapshots |
@var_log |
/var/log |
Logs (exclude from snapshots) |
@data |
/data |
Large files, media |
@vms |
/var/lib/libvirt/images |
VM disk images (CoW disabled) |
Creating Subvolumes
# Mount root volume
mount /dev/mapper/cryptroot /mnt
# Create subvolumes
btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@snapshots
btrfs subvolume create /mnt/@var_log
# Unmount and remount with subvolume
umount /mnt
mount -o subvol=/@ /dev/mapper/cryptroot /mnt
# Create mount points
mkdir -p /mnt/{.snapshots,var/log,home,boot,boot/efi,data}
# Mount other subvolumes
mount -o subvol=/@snapshots /dev/mapper/cryptroot /mnt/.snapshots
mount -o subvol=/@var_log /dev/mapper/cryptroot /mnt/var/log
Optimal Mount Options
# /etc/fstab entries
# Root
UUID=xxxx-xxxx / btrfs rw,noatime,compress=zstd:3,ssd,discard=async,space_cache=v2,subvol=/@ 0 0
# Snapshots
UUID=xxxx-xxxx /.snapshots btrfs rw,noatime,compress=zstd:3,ssd,discard=async,space_cache=v2,subvol=/@snapshots 0 0
# Var log
UUID=xxxx-xxxx /var/log btrfs rw,noatime,compress=zstd:3,ssd,discard=async,space_cache=v2,subvol=/@var_log 0 0
# Home (separate LUKS)
UUID=yyyy-yyyy /home btrfs rw,noatime,compress=zstd:3,ssd,discard=async,space_cache=v2,subvol=/@home 0 0
Mount option explanations:
-
noatime- Don’t update access times (performance) -
compress=zstd:3- Transparent compression (good balance) -
ssd- SSD optimizations -
discard=async- Background TRIM -
space_cache=v2- Improved space allocation tracking
Disable CoW for VMs
# VM images don't benefit from CoW
chattr +C /var/lib/libvirt/images
# Or for existing directory with files
mkdir /var/lib/libvirt/images-new
chattr +C /var/lib/libvirt/images-new
mv /var/lib/libvirt/images/* /var/lib/libvirt/images-new/
rmdir /var/lib/libvirt/images
mv /var/lib/libvirt/images-new /var/lib/libvirt/images
Boot Configuration for Encryption
mkinitcpio Hooks
# /etc/mkinitcpio.conf
HOOKS=(base udev autodetect modconf kms keyboard keymap consolefont block encrypt btrfs filesystems fsck)
Hook order matters:
* keyboard and keymap before encrypt - for password entry
* encrypt before btrfs and filesystems - decrypt before mount
Kernel Parameters
# /boot/loader/entries/arch.conf (systemd-boot)
title Arch Linux
linux /vmlinuz-linux
initrd /initramfs-linux.img
options cryptdevice=UUID=xxxx-xxxx:cryptroot root=/dev/mapper/cryptroot rootflags=subvol=/@ rw
# For multiple encrypted volumes, use /etc/crypttab
# /etc/crypttab
crypthome UUID=yyyy-yyyy none luks
cryptdata UUID=zzzz-zzzz none luks
SSH Hardening
Post-Quantum Key Exchange
Modern SSH supports hybrid post-quantum cryptography:
# ~/.ssh/config (global defaults)
Host *
# Post-quantum + classical hybrid KEX
KexAlgorithms mlkem768x25519-sha256,sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org
# Strong ciphers only
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
# Encrypt-then-MAC only
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com
# Host key algorithms
HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256
PubkeyAcceptedAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256
# Connection settings
AddKeysToAgent yes
IdentitiesOnly yes
ServerAliveInterval 60
ServerAliveCountMax 3
Key exchange algorithms explained:
* mlkem768x25519-sha256 - ML-KEM (Kyber) post-quantum + X25519 hybrid
* sntrup761x25519-sha512 - NTRU Prime post-quantum + X25519 hybrid
* curve25519-sha256 - Classical fallback
Per-Service SSH Keys
Create separate keys for each service:
# Generate keys for each service
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_github -C "github-$(hostname)"
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_gitlab -C "gitlab-$(hostname)"
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_gitea -C "gitea-$(hostname)"
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_codeberg -C "codeberg-$(hostname)"
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_bitbucket -C "bitbucket-$(hostname)"
# Directory structure
~/.ssh/
├── config
├── id_ed25519_github
├── id_ed25519_github.pub
├── id_ed25519_gitlab
├── id_ed25519_gitlab.pub
├── id_ed25519_gitea
├── id_ed25519_gitea.pub
├── id_ed25519_codeberg
├── id_ed25519_codeberg.pub
└── known_hosts
Host-Specific Configuration
# ~/.ssh/config
# === Git Services ===
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_github
Host gitlab.com
HostName gitlab.com
User git
IdentityFile ~/.ssh/id_ed25519_gitlab
Host codeberg.org
HostName codeberg.org
User git
IdentityFile ~/.ssh/id_ed25519_codeberg
Host gitea.example.com
HostName gitea.example.com
User git
IdentityFile ~/.ssh/id_ed25519_gitea
# === Infrastructure ===
Host bastion
HostName bastion.example.com
User admin
IdentityFile ~/.ssh/id_ed25519_infra
ProxyJump none
Host internal-*
User admin
IdentityFile ~/.ssh/id_ed25519_infra
ProxyJump bastion
# === Connection Multiplexing ===
Host *
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 600
# Create socket directory
mkdir -p ~/.ssh/sockets
chmod 700 ~/.ssh/sockets
FIDO2/Hardware Key Support
# Generate resident key (stored on YubiKey)
ssh-keygen -t ed25519-sk -O resident -O verify-required \
-f ~/.ssh/id_ed25519_sk_rk -C "yubikey-$(hostname)"
# Generate non-resident key (faster, key handle on disk)
ssh-keygen -t ed25519-sk -f ~/.ssh/id_ed25519_sk -C "yubikey-$(hostname)"
# Discover resident keys from hardware token
ssh-keygen -K
# Use in config
Host secure-server
IdentityFile ~/.ssh/id_ed25519_sk_rk
Secrets Management
gopass (Password Store)
# Install
sudo pacman -S gopass
# Initialize (uses GPG)
gopass init
# Or with age encryption
gopass init --crypto age
# Clone existing store
gopass clone git@github.com:user/password-store.git
Multi-Store Organization
# Structure secrets by domain
gopass/
├── personal/ # Personal accounts
│ ├── email/
│ ├── banking/
│ └── social/
├── work/ # Work credentials
│ ├── vpn
│ └── servers/
├── infra/ # Infrastructure secrets
│ ├── ssh/
│ ├── api-keys/
│ └── certificates/
└── wifi/ # WiFi passwords
├── home
└── office
gopass Commands
# List all secrets
gopass list
# Show secret (copies to clipboard)
gopass show -c path/to/secret
# Insert new secret
gopass insert path/to/secret
# Generate password
gopass generate path/to/secret 32
gopass generate -s path/to/secret 32 # With symbols
# Edit secret
gopass edit path/to/secret
# Search
gopass find keyword
gopass search keyword
# Sync with git
gopass sync
Multiple Stores (Mounts)
# Add additional store
gopass mounts add work /path/to/work-store
# List mounts
gopass mounts
# Access mounted store
gopass show work/vpn/credentials
File Encryption
age (Simple Encryption)
# Install
sudo pacman -S age
# Generate key
age-keygen -o key.txt
# Encrypt with public key
age -r age1... -o secret.age secret.txt
# Encrypt with passphrase
age -p -o secret.age secret.txt
# Decrypt
age -d -i key.txt -o secret.txt secret.age
age -d -o secret.txt secret.age # Passphrase prompt
Snapshot Security
Snapper for Btrfs
# Install
sudo pacman -S snapper snap-pac
# Create config for root
sudo snapper -c root create-config /
# Configure timeline
sudo nvim /etc/snapper/configs/root
# /etc/snapper/configs/root (key settings)
TIMELINE_CREATE="yes"
TIMELINE_CLEANUP="yes"
TIMELINE_MIN_AGE="1800"
TIMELINE_LIMIT_HOURLY="5"
TIMELINE_LIMIT_DAILY="7"
TIMELINE_LIMIT_WEEKLY="0"
TIMELINE_LIMIT_MONTHLY="0"
TIMELINE_LIMIT_YEARLY="0"
# Enable timers
sudo systemctl enable --now snapper-timeline.timer
sudo systemctl enable --now snapper-cleanup.timer
# List snapshots
sudo snapper -c root list
# Create manual snapshot
sudo snapper -c root create -d "before update"
# Rollback (from live USB)
sudo snapper -c root undochange 1..5
Audit and Monitoring
Quick Reference
# === LUKS ===
cryptsetup luksFormat /dev/sdX # Create
cryptsetup open /dev/sdX name # Open
cryptsetup close name # Close
cryptsetup luksDump /dev/sdX # Info
cryptsetup luksHeaderBackup /dev/sdX --header-backup-file backup.img
# === Btrfs ===
btrfs subvolume list / # List subvolumes
btrfs subvolume create /mnt/@name # Create
btrfs subvolume delete /mnt/@name # Delete
btrfs filesystem df / # Usage
# === SSH ===
ssh-keygen -t ed25519 -f ~/.ssh/key # Generate key
ssh-keygen -t ed25519-sk -O resident # Hardware key
ssh-add -l # List loaded keys
ssh-add ~/.ssh/key # Add key to agent
# === Secrets ===
gopass list # List secrets
gopass show -c path/to/secret # Copy to clipboard
gopass generate path 32 # Generate password
# === Snapshots ===
snapper -c root list # List snapshots
snapper -c root create -d "description" # Create snapshot
snapper -c root delete 5 # Delete snapshot
# === Audit ===
sudo lynis audit system # Security audit
sudo rkhunter --check # Rootkit check