Files
docudjeex/content/5.nonsense/2.bash/2.luks- backup.md
2025-07-20 17:49:48 +00:00

3.1 KiB
Raw Blame History

navigation, title, main
navigation title main
true LUKS Backup
fluid
false

:ellipsis{left=0px width=40rem top=10rem blur=140px}

Backup of LUKS Headers for Encrypted Disks/Volumes


I recently realized that having just the password is not enough to unlock a LUKS volume after a failure or corruption. I learned how to dump the LUKS headers from disks/volumes and to use the serial numbers along with partition names to accurately identify which header corresponds to which disk/partition (I have 10 of them!).

After struggling to do this manually, I asked Qwen3 (an LLM running on my RTX 5090) to create a script that automates the listing and identification of disks, dumps the headers, and stores them in an encrypted archive ready to be backed up on my backup server.

This script:

  • Lists and identifies disks with their serial numbers
  • Lists partitions
  • Dumps headers into a secured folder under /root
  • Creates a temporary archive
  • Prompts for a password
  • Encrypts the archive with that password
  • Deletes the unencrypted archive
#!/bin/bash

# Directory where LUKS headers will be backed up
DEST="/root/luks-headers-backup"
mkdir -p "$DEST"

echo "🔍 Searching for LUKS containers on all partitions..."

# Loop through all possible disk partitions (including NVMe and SATA)
for part in /dev/sd? /dev/sd?? /dev/nvme?n?p?; do
    # Skip if the device doesn't exist
    if [ ! -b "$part" ]; then
        continue
    fi

    # Check if the partition is a LUKS encrypted volume
    if cryptsetup isLuks "$part"; then
        # Find the parent disk device (e.g. nvme0n1p4 → nvme0n1)
        disk=$(lsblk -no pkname "$part" | head -n 1)
        full_disk="/dev/$disk"

        # Get the serial number of the parent disk
        SERIAL=$(udevadm info --query=all --name="$full_disk" | grep ID_SERIAL= | cut -d= -f2)
        if [ -z "$SERIAL" ]; then
            SERIAL="unknown"
        fi

        # Extract the partition name (e.g. nvme0n1p4)
        PART_NAME=$(basename "$part")

        # Build the output filename with partition name and disk serial
        OUTPUT="$DEST/luks-header-${PART_NAME}__${SERIAL}.img"

        echo "🔐 Backing up LUKS header of $part (Serial: $SERIAL)..."

        # Backup the LUKS header to the output file
        cryptsetup luksHeaderBackup "$part" --header-backup-file "$OUTPUT"
        if [[ $? -eq 0 ]]; then
            echo "✅ Backup successful → $OUTPUT"
        else
            echo "❌ Backup failed for $part"
        fi
    fi
done

# Create a timestamped compressed tar archive of all header backups
ARCHIVE_NAME="/root/luks-headers-$(date +%Y%m%d_%H%M%S).tar.gz"
echo "📦 Creating archive $ARCHIVE_NAME..."
tar -czf "$ARCHIVE_NAME" -C "$DEST" .

# Encrypt the archive symmetrically using GPG with AES256 cipher
echo "🔐 Encrypting the archive with GPG..."
gpg --symmetric --cipher-algo AES256 "$ARCHIVE_NAME"
if [[ $? -eq 0 ]]; then
    echo "✅ Encrypted archive created: ${ARCHIVE_NAME}.gpg"
    # Remove the unencrypted archive for security
    rm -f "$ARCHIVE_NAME"
else
    echo "❌ Encryption failed"
fi

Dont forget to back up /etc/fstab and /etc/crypttab as well!