# Host-Level Disk Encryption Guide

Kubernetes encryption at rest (EncryptionConfiguration) only protects data
inside etcd. Persistent volumes, container image layers, and temporary files
on the node filesystem remain unencrypted unless the host disk itself is
encrypted.

This guide covers host-level full disk encryption options for Citadel
nodes.

## Why Host-Level Encryption Matters

| Layer | What It Protects | Citadel File |
|-------|-----------------|------------|
| etcd encryption | Secrets, ConfigMaps, CRDs in etcd | `encryption-config.yaml` |
| Storage encryption | Object storage (MinIO SSE-S3) | `storage-encryption.yaml` |
| **Host disk encryption** | **Everything on the node filesystem** | **This guide** |

Without host-level disk encryption, an attacker with physical access to the
disk (stolen drive, decommissioned hardware, cloud snapshot) can read:

- Container image layers (may contain embedded secrets)
- Kubelet credential files
- etcd data files (bypassing API-level encryption if raw files are accessed)
- Temporary files, logs, and core dumps
- Persistent volume data

## Option 1: LUKS (Linux Unified Key Setup)

LUKS is the standard for Linux disk encryption. It encrypts entire block
devices using dm-crypt with AES-XTS-256.

### Setup During OS Installation (Recommended)

Most Linux installers support LUKS natively:

```bash
# Ubuntu/Debian: Select "Encrypt the new Ubuntu installation" during install
# RHEL/CentOS: Select "Encrypt my data" in the installation disk config
# SUSE: Enable LUKS in the YaST partitioner
```

### Setup on Existing System

```bash
# WARNING: This will DESTROY all data on the target device.
# Back up everything first.

# Install cryptsetup
sudo apt install cryptsetup  # Debian/Ubuntu
sudo yum install cryptsetup  # RHEL/CentOS

# Create LUKS partition (example: /dev/sdb for data volume)
sudo cryptsetup luksFormat --type luks2 \
  --cipher aes-xts-plain64 \
  --key-size 512 \
  --hash sha256 \
  --iter-time 2000 \
  /dev/sdb

# Open the encrypted volume
sudo cryptsetup luksOpen /dev/sdb citadel-data

# Create filesystem
sudo mkfs.ext4 /dev/mapper/citadel-data

# Mount
sudo mkdir -p /var/lib/citadel/encrypted-volumes
sudo mount /dev/mapper/citadel-data /var/lib/citadel/encrypted-volumes
```

### Auto-Unlock at Boot (via TPM2 or Key File)

For unattended boot (required for Kubernetes nodes):

```bash
# Option A: TPM2 auto-unlock (recommended for physical servers)
sudo systemd-cryptenroll --tpm2-device=auto /dev/sdb

# Option B: Key file auto-unlock (for VMs with secure key storage)
sudo dd if=/dev/urandom of=/root/.luks-keyfile bs=4096 count=1
sudo chmod 400 /root/.luks-keyfile
sudo cryptsetup luksAddKey /dev/sdb /root/.luks-keyfile

# Add to /etc/crypttab for auto-mount:
echo "citadel-data /dev/sdb /root/.luks-keyfile luks" | sudo tee -a /etc/crypttab

# Add to /etc/fstab:
echo "/dev/mapper/citadel-data /var/lib/citadel/encrypted-volumes ext4 defaults 0 2" \
  | sudo tee -a /etc/fstab
```

### Verify LUKS Encryption

```bash
# Check LUKS status
sudo cryptsetup luksDump /dev/sdb

# Verify dm-crypt is active
sudo dmsetup status citadel-data
# Expected output: 0 <size> crypt
```

## Option 2: dm-crypt (Lower Level)

dm-crypt is the kernel-level block device encryption that LUKS builds on.
Use dm-crypt directly only when LUKS overhead is unacceptable or you need
custom key management.

```bash
# Create dm-crypt volume without LUKS header
echo -n "your-encryption-key" | sudo cryptsetup open \
  --type plain \
  --cipher aes-xts-plain64 \
  --key-size 256 \
  /dev/sdb citadel-data-plain

# The rest (mkfs, mount) is the same as LUKS
```

## Option 3: Cloud Provider Encryption

For cloud-hosted Citadel nodes, use the provider's native volume encryption:

### AWS (EBS)

```bash
# Enable default encryption for all new EBS volumes in the region
aws ec2 enable-ebs-encryption-by-default --region us-east-1

# Or specify per-volume with a CMK
aws ec2 create-volume \
  --volume-type gp3 \
  --size 100 \
  --encrypted \
  --kms-key-id alias/citadel-node-key \
  --availability-zone us-east-1a
```

### GCP (Persistent Disk)

GCP encrypts all persistent disks by default with Google-managed keys.
For customer-managed keys (CMEK):

```bash
gcloud compute disks create citadel-data \
  --size=100GB \
  --type=pd-ssd \
  --kms-key=projects/my-project/locations/us-central1/keyRings/citadel/cryptoKeys/node-key
```

### Azure (Managed Disk)

Azure encrypts all managed disks by default with platform-managed keys.
For customer-managed keys:

```bash
az disk create \
  --resource-group citadel-rg \
  --name citadel-data \
  --size-gb 100 \
  --encryption-type EncryptionAtRestWithCustomerKey \
  --disk-encryption-set /subscriptions/.../diskEncryptionSets/citadel-des
```

## Citadel Node Provisioning

When provisioning new Citadel nodes, include disk encryption in the
node image or cloud-init configuration:

```yaml
# cloud-init example for encrypted data volume
disk_setup:
  /dev/sdb:
    table_type: gpt
    layout: true

fs_setup:
  - label: citadel-data
    device: /dev/sdb1
    filesystem: ext4
    cmd: "cryptsetup luksFormat --batch-mode /dev/sdb1 /root/.luks-keyfile && cryptsetup luksOpen /dev/sdb1 citadel-data --key-file /root/.luks-keyfile && mkfs.ext4 /dev/mapper/citadel-data"

mounts:
  - ["/dev/mapper/citadel-data", "/var/lib/citadel/encrypted-volumes", "ext4", "defaults", "0", "2"]
```

## Verification Checklist

After setting up host-level encryption, verify:

```bash
# 1. Check that the data partition is encrypted
lsblk -o NAME,FSTYPE,SIZE,MOUNTPOINT,CRYPT
# Should show "crypt" in the CRYPT column for citadel-data

# 2. Verify encryption algorithm
sudo cryptsetup status citadel-data
# Should show: cipher: aes-xts-plain64, keysize: 512 bits

# 3. Confirm K3s data directory is on encrypted volume
df /var/lib/rancher/k3s
# Should show /dev/mapper/citadel-data (or encrypted cloud volume)

# 4. Confirm etcd data is on encrypted volume
df /var/lib/rancher/k3s/server/db
# Should be on an encrypted filesystem

# 5. Test: cold read of raw disk should show only encrypted data
sudo dd if=/dev/sdb bs=1M count=1 | hexdump -C | head
# Should show random-looking data, not plaintext
```

## Recommendations

| Environment | Recommendation |
|-------------|---------------|
| Development (local/VM) | LUKS2 with key file or passphrase |
| Production (cloud) | Cloud provider encryption with CMK |
| Production (bare metal) | LUKS2 with TPM2 auto-unlock |
| Air-gapped / high-security | LUKS2 + TPM2 + Secure Boot chain |

For all environments, combine host-level encryption with:
- etcd encryption (`security/encryption-config.yaml`)
- Storage encryption (`security/storage-encryption.yaml`)
- WireGuard in-transit encryption (`scripts/06-enable-wireguard.sh`)
