Mounting a whole-disk-encrypted Debian disk on a new computer

So I installed Debian on a new disk, then stuck my old disk into an external USB enclosure to get the files I realized I had forgotten to copy over. But it didn't just mount automatically the way I expected it to, because the disk was encrypted using Debian Etch's automatic LVM-with-LUKS-and-dm-crypt-disk-encryption system, installed with partman-crypto.

How I Figured It Out

I ran dmesg to see where it was:

kragen@thrifty:~/tmp$ dmesg
...
usb 1-1: new full speed USB device using uhci_hcd and address 2
usb 1-1: configuration #1 chosen from 1 choice
SCSI subsystem initialized
Initializing USB Mass Storage driver...
scsi0 : SCSI emulation for USB Mass Storage devices
usbcore: registered new driver usb-storage
USB Mass Storage support registered.
usb-storage: device found at 2
usb-storage: waiting for device to settle before scanning
  Vendor: IC25N040  Model: ATMR04-0          Rev: 0000
  Type:   Direct-Access                      ANSI SCSI revision: 00
usb-storage: device scan complete
SCSI device sda: 78140160 512-byte hdwr sectors (40008 MB)
sda: Write Protect is off
sda: Mode Sense: 27 00 00 00
sda: assuming drive cache: write through
SCSI device sda: 78140160 512-byte hdwr sectors (40008 MB)
sda: Write Protect is off
sda: Mode Sense: 27 00 00 00
sda: assuming drive cache: write through
 sda: sda1 sda2 < sda5 >
sd 0:0:0:0: Attached scsi disk sda
...

So the device was /dev/sda, and I recalled that the encrypted LVM group had been in the first logical partition. In the man page for cryptsetup (the version of cryptsetup that supports LUKS), I found the command luksOpen, so I tried:

kragen@thrifty:~/tmp$ sudo cryptsetup luksOpen /dev/sda5 externaldisk

And I succeeded in entering the key and unlocking the first key slot, so cryptsetup created /dev/mapper/externaldisk. Unfortunately the contents were a logical volume group, not a filesystem by itself. I looked at man lvm and the like for a while without seeing anything relevant to opening up an LVM volume group on an existing device. I did manage to find lvscan:

kragen@thrifty:~/tmp$ sudo lvscan
  ACTIVE            '/dev/Debian/root' [110.45 GB] inherit
  ACTIVE            '/dev/Debian/swap_1' [1.10 GB] inherit

That's the filesystem I'm currently running off of. So LVM is indeed the way to access this stuff (the old setup was set up with the same install CD) and it is not yet opened.

I wonder how it happens at boot-time? I think it comes from some script in some initrd file stored in /boot.

kragen@thrifty:~/tmp$ ls /boot
config-2.6.18-4-686          lost+found
config-2.6.18-5-686          System.map-2.6.18-4-686
config-2.6.18-6-686          System.map-2.6.18-5-686
grub                         System.map-2.6.18-6-686
initrd.img-2.6.18-4-686      vmlinuz-2.6.18-4-686
initrd.img-2.6.18-4-686.bak  vmlinuz-2.6.18-5-686
initrd.img-2.6.18-5-686      vmlinuz-2.6.18-6-686
initrd.img-2.6.18-6-686
kragen@thrifty:~/tmp$ file /boot/initrd.img-2.6.18-6-686 
/boot/initrd.img-2.6.18-6-686: gzip compressed data, from Unix, last 
modified: Tue Feb 19 02:21:30 2008, max compression
kragen@thrifty:~/tmp$ gzip -dc /boot/initrd.img-2.6.18-6-686 > initrd.bin
kragen@thrifty:~/tmp$ file initrd.bin
initrd.bin: ASCII cpio archive (SVR4 with no CRC)

So I successfully ungzipped the initrd --- and it's a cpio file? Being an idiot, I tried extracting it with cpio -o < initrd.bin, but that was unsuccessful. Still being an idiot, I thought that perhaps file was incorrect in its guess that it was a cpio file, and so I tried mounting it as follows:

sudo mount -o loop -t cramfs initrd.bin /mnt
for type in $(ls /lib/modules/2.6.18-6-686/kernel/fs/); do 
    mount -o loop -t "$type" initrd.bin /mnt
done

and that was unsuccessful too. I gave up on trying to figure out what the filesystem was and just grepped it:

kragen@thrifty:~/tmp$ grep -a lvm initrd.bin |less
alias block-major-58-* lvm_mod
alias char-major-109-* lvm_mod
...
PREREQ="mdadm mdrun lvm2"
if [ -e /scripts/local-top/lvm2 ]; then
    cryptlvm=""
        lvm=*)
            cryptlvm=${x#lvm=}
...

Looks like gold!

(It turns out that what I should have done was cpio -i < initrd.bin; -o is for creating cpio archives, not extracting files from them. But I should have made a directory to do it in first. The scripts excerpted above are scripts/local-top/lvm and scripts/local-top/cryptroot.)

kragen@thrifty:~/tmp$ less +/lvm initrd.bin

Navigating around a bit in there eventually finds me this:

FSTYPE=''
eval $(fstype < "$NEWROOT")

# See if we need to setup lvm on the crypto device
if [ "$FSTYPE" = "lvm" ] || [ "$FSTYPE" = "lvm2" ]; then
...
if [ -z "$cryptlvm" ]; then
    ...
elif ! activate_vg "/dev/mapper/$cryptlvm"; then
    echo "cryptsetup: failed to setup lvm device"
    return 1
fi
kragen@thrifty:~/tmp$ locate fstype
/usr/lib/klibc/bin/fstype
kragen@thrifty:~/tmp$ sudo sh -c '/usr/lib/klibc/bin/fstype < /dev/mapper/externaldisk '
FSTYPE=lvm2
FSSIZE=0

Great! I now know that I really do have an LVM volume group to deal with. What does activate_vg do?

activate_vg()
{
    local vg
    vg="${1#/dev/mapper/}"
    ...
    vgchange -ay ${vg}
    return $?
}

Maybe I can do that.

kragen@thrifty:~/tmp$ sudo vgchange -ay externaldisk
  Volume group "externaldisk" not found
kragen@thrifty:~/tmp$ sudo vgchange -ay thrifty
  2 logical volume(s) in volume group "thrifty" now active
kragen@thrifty:~/tmp$ sudo lvscan
  ACTIVE            '/dev/thrifty/root' [35.92 GB] inherit
  ACTIVE            '/dev/thrifty/swap_1' [1.10 GB] inherit
  ACTIVE            '/dev/Debian/root' [110.45 GB] inherit
  ACTIVE            '/dev/Debian/swap_1' [1.10 GB] inherit

Yes! Apparently -ay means --available y --- that is, make it available. Good thing I remembered that the volume group was called thrifty, the hostname of the system it was built for. Is there a way I could have figured that out?

kragen@thrifty:~/tmp$ ls /sbin/vg*
/sbin/vgcfgbackup   /sbin/vgcreate   /sbin/vgmerge    /sbin/vgs
/sbin/vgcfgrestore  /sbin/vgdisplay  /sbin/vgmknodes  /sbin/vgscan
/sbin/vgchange      /sbin/vgexport   /sbin/vgreduce   /sbin/vgsplit
/sbin/vgck          /sbin/vgextend   /sbin/vgremove
/sbin/vgconvert     /sbin/vgimport   /sbin/vgrename

Only vgdisplay looks particularly helpful, and it will only display the volume group after we vgchange -ay it. So I don't know. (vgscan?)

kragen@thrifty:~/tmp$ sudo mount /dev/thrifty/root /mnt
[in dmesg, not shown on my screen]
kjournald starting.  Commit interval 5 seconds
EXT3 FS on dm-4, internal journal
EXT3-fs: recovery complete.
EXT3-fs: mounted filesystem with ordered data mode.
kragen@thrifty:~/tmp$

Summary

kragen@thrifty:~/tmp$ dmesg
...
 sda: sda1 sda2 < sda5 >
...
kragen@thrifty:~/tmp$ sudo cryptsetup luksOpen /dev/sda5 externaldisk
kragen@thrifty:~/tmp$ sudo sh -c '/usr/lib/klibc/bin/fstype < /dev/mapper/externaldisk '
FSTYPE=lvm2
...

(here you magically guess that the volume group name is thrifty)

kragen@thrifty:~/tmp$ sudo vgchange -ay thrifty
  2 logical volume(s) in volume group "thrifty" now active
kragen@thrifty:~/tmp$ sudo lvscan
  ACTIVE            '/dev/thrifty/root' [35.92 GB] inherit
  ACTIVE            '/dev/thrifty/swap_1' [1.10 GB] inherit
  ACTIVE            '/dev/Debian/root' [110.45 GB] inherit
  ACTIVE            '/dev/Debian/swap_1' [1.10 GB] inherit
kragen@thrifty:~/tmp$ sudo mount /dev/thrifty/root /mnt

And then when you're done:

kragen@thrifty:~$ sudo umount /mnt
kragen@thrifty:~$ sudo vgchange -an thrifty
  0 logical volume(s) in volume group "thrifty" now active
kragen@thrifty:~$ sudo cryptsetup luksClose externaldisk