Automating LUKS Encrypted Volume Mapping: How to Use /etc/crypttab for Manual cryptsetup luksOpen Operations


3 views

When managing multiple LUKS-encrypted volumes on headless servers, manually executing cryptsetup luksOpen for each device after every reboot becomes tedious. The standard approach requires remembering UUID-device mappings:

# Typical manual process
cryptsetup luksOpen /dev/sdb1 db_encrypted
cryptsetup luksOpen /dev/nvme0n1p2 logs_encrypted

While /etc/crypttab is commonly associated with automatic boot decryption, its noauto option makes it perfect for manual scenarios:

# /etc/crypttab example configuration
db_crypt UUID=1234-5678 none noauto
logs_crypt /dev/nvme0n1p2 none noauto
backup_crypt /dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_3 none noauto

Here's a bash script that parses /etc/crypttab to simplify LUKS operations:

#!/bin/bash
# crypttab-helper: Wrapper for cryptsetup using /etc/crypttab

if [ $# -ne 1 ]; then
    echo "Usage: ${0##*/} <mapping_name>"
    exit 1
fi

mapping_name=$1
found=0

while read -r name device keyfile options; do
    # Skip comments and empty lines
    [[ "$name" =~ ^# ]] || [[ -z "$name" ]] && continue
    
    if [[ "$name" == "$mapping_name" ]]; then
        found=1
        # Handle UUID= format
        if [[ "$device" =~ ^UUID= ]]; then
            uuid=${device#UUID=}
            device="/dev/disk/by-uuid/$uuid"
        fi
        
        echo "Opening LUKS device $device as $name"
        cryptsetup luksOpen "$device" "$name"
        
        # Check if the open operation succeeded
        if [ $? -eq 0 ]; then
            echo "Successfully mapped $name"
        else
            echo "Failed to open $name" >&2
            exit 2
        fi
    fi
done < /etc/crypttab

if [ $found -eq 0 ]; then
    echo "Mapping name $mapping_name not found in /etc/crypttab" >&2
    exit 3
fi

For more complex scenarios, consider these enhancements:

# Batch processing all noauto volumes
grep 'noauto' /etc/crypttab | awk '{print $1}' | xargs -n1 crypttab-helper

# Systemd service unit for delayed decryption
[Unit]
Description=Decrypt LUKS volumes marked noauto
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/crypttab-helper db_crypt
ExecStart=/usr/local/bin/crypttab-helper logs_crypt
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

When implementing this solution:

  • Set strict permissions on the helper script (chmod 700)
  • Consider using key files instead of interactive passwords
  • Audit /etc/crypttab permissions (should be 0600 root:root)
  • For sensitive systems, implement additional authentication before running the script

If the wrapper script doesn't meet your needs:

  1. Network-Based Decryption: Configure dropbear-initramfs for SSH during boot
  2. Tang Binding: Use Clevis with Tang servers for automated network-based decryption
  3. TPM Integration: Modern systems can use TPM2 for sealed key release

When managing encrypted volumes on headless servers or virtual machines, manually executing cryptsetup luksOpen for each device after every reboot becomes tedious. The standard boot-time decryption process fails when:

  • No console access exists during boot
  • Automated password entry isn't feasible
  • You need selective device mapping

The crypttab format contains four fields per entry:

<name> <device> <password> <options>

For our use case, a typical entry would look like:

data_crypt UUID=12345678-9abc-def0-1234-56789abcdef0 none noauto

Unlike mount which reads /etc/fstab, cryptsetup lacks direct crypttab parsing. We need to bridge this gap with automation.

Create /usr/local/bin/crypttab-open:

#!/bin/bash
# Read crypttab and open specified mapping
name=$1
while read -r m_name m_device m_password m_options; do
    [[ "$m_name" == "$name" ]] || continue
    [[ "$m_device" =~ ^UUID= ]] && m_device="/dev/disk/by-uuid/${m_device#UUID=}"
    cryptsetup luksOpen "$m_device" "$m_name"
    exit $?
done < /etc/crypttab
exit 1

Make it executable:

chmod +x /usr/local/bin/crypttab-open

Single device mapping:

crypttab-open data_crypt

Batch mapping all noauto devices:

awk '/noauto/ {print $1}' /etc/crypttab | xargs -n1 crypttab-open

For systems with complex requirements, consider this enhanced version:

#!/bin/bash
# Enhanced crypttab opener with error handling
set -e

CRYPTTAB=${CRYPTTAB:-/etc/crypttab}

open_mapping() {
    local name=$1
    local found=0
    
    while IFS=" " read -r m_name m_device m_password m_options; do
        [[ "$m_name" == "$name" ]] || continue
        found=1
        
        # Skip commented lines
        [[ "$m_name" =~ ^# ]] && continue
        
        # Handle UUID devices
        if [[ "$m_device" =~ ^UUID= ]]; then
            m_device="/dev/disk/by-uuid/${m_device#UUID=}"
        fi
        
        # Skip already active mappings
        if cryptsetup status "$m_name" &>/dev/null; then
            echo "Mapping $m_name already active"
            return 0
        fi
        
        # Execute the open command
        echo "Opening $m_name ($m_device)"
        cryptsetup luksOpen "$m_device" "$m_name"
        return $?
    done < "$CRYPTTAB"
    
    [[ $found -eq 0 ]] && echo "Error: Mapping $name not found in $CRYPTTAB" >&2
    return 1
}

# Main execution
for name in "$@"; do
    open_mapping "$name"
done

Create /etc/systemd/system/crypttab-open@.service:

[Unit]
Description=Open LUKS mapping %i from crypttab

[Service]
Type=oneshot
ExecStart=/usr/local/bin/crypttab-open %i

Now you can trigger mappings via:

systemctl start crypttab-open@data_crypt.service