Gentoo Encrypted Root, with LUKS and LVM

2009-12-20 11:22 - Linux

I'm upgrading my home server to be a bit beefier, as I've started using it for some video processing and other demanding tasks. Along the way of configuring a new blank machine from scratch, I decided to set up disk encryption (better safe than sorry, eh?), something I've never done for a linux server before. I found it a bit tricky, so here's a log, with some explanations, of what I did. If it's useful to you, great! It's geared towards the Gentoo linux distribution, as that's what I use and love, and generally towards experts. If you don't understand anything below, please research it, before you try to do something like this.

  1. Boot a recent Gentoo Minimal LiveCD. I used install-x86-minimal-20091103.iso. Anything newer than that should probably also work.

  2. Work through the Gentoo Handbook until step 4. Using fdisk as described there, define one small partition (I used 256M) to boot from, and one more taking the rest of the drive. This left me with:

    # fdisk -l /dev/sda
    
    Disk /dev/sda: 640.1 GB, 640135028736 bytes
    255 heads, 63 sectors/track, 77825 cylinders
    Units = cylinders of 16065 * 512 = 8225280 bytes
    Disk identifier: 0x83e6d949
    
       Device Boot      Start         End      Blocks   Id  System
    /dev/sda1               1          34      273073+  83  Linux
    /dev/sda2              35       77825   624856207+  83  Linux

    With that done, format the boot partition:

    # mke2fs /dev/sda1
    mke2fs 1.41.3 (12-Oct-2008)
    Filesystem label=
    OS type: Linux
    Block size=1024 (log=0)
    Fragment size=1024 (log=0)
    68272 inodes, 273072 blocks
    13653 blocks (5.00%) reserved for the super user
    First data block=1
    Maximum filesystem blocks=67633152
    34 block groups
    8192 blocks per group, 8192 fragments per group
    2008 inodes per group
    Superblock backups stored on blocks:
            8193, 24577, 40961, 57345, 73729, 204801, 221185
    
    Writing inode tables: done
    Writing superblocks and filesystem accounting information: done
    
    This filesystem will be automatically checked every 20 mounts or
    180 days, whichever comes first.  Use tune2fs -c or -i to override.

    And the encrypted partition:

    # cryptsetup --verify-passphrase luksFormat /dev/sda2
    WARNING!
    ========
    This will overwrite data on /dev/sda2 irrevocably.
    
    Are you sure? (Type uppercase yes): YES
    Enter LUKS passphrase:
    Verify passphrase:
    Command successful.
  3. At this point we need to set up the encrypted partition layer.

    # cryptsetup luksOpen /dev/sda2 root

    In order to get multiple "partitions" inside the single encrypted layer, we set up LVM. I keep /tmp (nosuid and no execute), as well as /var (in case logs fill it up) and /home, separate from /, so I did:

    # pvcreate /dev/mapper/root
      Physical volume "/dev/mapper/root" successfully created
    # vgcreate vg /dev/mapper/root
      Volume group "vg" successfully created
    # lvcreate --size 1G --name swap vg
      Logical volume "swap" created
    # lvcreate --size 10G --name root vg
      Logical volume "root" created
    # lvcreate --size 1G --name tmp vg
      Logical volume "tmp" created
    # lvcreate --size 10G --name var vg
      Logical volume "var" created
    # lvcreate --extents 100%FREE --name home vg
      Rounding up size to full physical extent 573.90 GB
      Logical volume "home" created
    # vgchange --available y
      5 logical volume(s) in volume group "vg" now active

    Use vgs or vgdisplay to find out how much room you have left for the last logical volume.

    Format these partitions as you like, I did:

    # mkswap /dev/mapper/vg-swap
    Setting up swapspace version 1, size = 1048572 KiB
    no label, UUID=b43468c8-8652-4035-9227-6ef562975dbd
    # mkfs.xfs /dev/mapper/vg-root
    meta-data=/dev/mapper/vg-root    isize=256    agcount=4, agsize=655360 blks
             =                       sectsz=512   attr=2
    ...
    # mkfs.xfs /dev/mapper/vg-tmp
    meta-data=/dev/mapper/vg-tmp     isize=256    agcount=4, agsize=65536 blks
             =                       sectsz=512   attr=2
    ...
    # mkfs.xfs /dev/mapper/vg-var
    meta-data=/dev/mapper/vg-var     isize=256    agcount=4, agsize=655360 blks
             =                       sectsz=512   attr=2
    ...
    # mkfs.xfs /dev/mapper/vg-home
    meta-data=/dev/mapper/vg-home    isize=256    agcount=4, agsize=37611264 blks
             =                       sectsz=512   attr=2
    ...
  4. Continue with the Gentoo Handbook, until step seven. We need cryptsetup installed and configured properly before we build our kernel, so first emerge cryptsetup. Now follow step seven as normal, but be sure to use genkernel. Do not use any splash, vga or framebuffer related options (trying to use these caused me lots of grief).

    # genkernel --menuconfig --install --symlink --lvm --luks all
    * Gentoo Linux Genkernel; Version 3.4.10.904
    * Running with options: --menuconfig --install --symlink --lvm --luks all
    
    * Linux Kernel 2.6.28-hardened-r9 for x86...
    * kernel: >> Running mrproper...
    * config: Using config from /etc/kernels/kernel-config-x86-2.6.28-hardened-r9
    *         Previous config backed up to .config.bak
    *         >> Running oldconfig...
    * kernel: >> Cleaning...
    * config: >> Invoking menuconfig...
    
    *** End of Linux kernel configuration.
    *** Execute 'make' to build the kernel or try 'make help'.
    
    *         >> Compiling 2.6.28-hardened-r9 bzImage...
    *         >> Compiling 2.6.28-hardened-r9 modules...
    * Copying config for successful build to /etc/kernels/kernel-config-x86-2.6.28-hardened-r9
    * busybox: >> Using cache
    * initramfs: >> Initializing...
    *         >> Appending base_layout cpio data...
    *         >> Appending auxilary cpio data...
    *         >> Appending busybox cpio data...
    *         >> Appending lvm cpio data...
    *               LVM: Adding support (compiling binaries)...
    *         >> Appending luks cpio data...
    * Including LUKS support
    *         >> Appending modules cpio data...
    *
    * Kernel compiled successfully!
    ...

    Since you might be running genkernel again in the future, for upgrades, it might be worth looking at /etc/genkernel.conf to set the options passed on the commandline, above. In the config step be sure to include these kernel options statically (not as a module):

        Device Drivers  --->
        [*] Multiple devices driver support (RAID and LVM)  --->
            <*> Device mapper support
            <*> Crypt target support
    -*- Cryptographic API  --->
        *** Digest ***
        -*-   SHA224 and SHA256 digest algorithm
        *** Ciphers ***
        <*> AES cipher algorithms
  5. The machine I'm setting up has some sort of problem with grub. I'm not sure what, but it detects free memory incorrectly, thinks there's 0k available, and refuses to run anything, because 0k is not enough room. So at the bootloader step, this time I'm using LILO. So:

    # echo "sys-boot/lilo device-mapper" >> /etc/portage/package.use
    # emerge lilo

    Then, I need to properly fill out /etc/lilo.conf, based on Handbook step 10c. Note the crypt_root, which is the real device, encrypted with LUKS, and the real_root which is the virtual (LVM) device, under the LUKS encryption layer, that we tell the kernel is the real root, after LUKS and LVM has been set up properly.

    append="init=/linuxrc dolvm crypt_root=/dev/sda2 real_root=/dev/mapper/vg-root"
    boot=/dev/sda
    compact
    default=gentoo
    lba32
    prompt
    read-only
    root=/dev/ram0
    timeout=50
    
    image=/boot/kernel
      initrd=/boot/initramfs
      label=gentoo
    
    image=/boot/kernel.old
      initrd=/boot/initramfs.old
      label=backup
      optional

    Finally, install LILO as the boot loader with:

    # /sbin/lilo
    Added gentoo *
    Added backup
  6. Continue with the Gentoo Handbook, which at this point is basically just rebooting and using the system!

If something goes wrong somewhere in the middle, and you need to re-boot from the LiveCD, and mount your virtual encrypted partitions, it should go something like:

# cryptsetup luksOpen /dev/sda2 sda2
Enter LUKS passphrase:
padlock: VIA PadLock not detected.
padlock: VIA PadLock Hash Engine not detected.
key slot 0 unlocked.
Command successful.
# vgscan
  Reading all physical volumes.  This may take a while ...
  Found volume group "vg" using metadata type lvm2
# vgchange -ay
  5 logical volume(s) in volume group "vg" now active

Then a bunch of mount commands.

It was a bit difficult to find all the right information to make this happen. Some of the references I used:

Comments:

Yes!
2010-01-02 12:35 - tvhwy

Thank you very much for these instructions, which deserve a place in official Gentoo documentation. I had been trying periodically for months to make an encrypted root, using some of the same sources you cited. I knew little about genkernel, luks, or LVM before. Now I feel competent.

It worked almost perfectly. My password would not unlock the key slot at boot time until I compiled some more Cryptographic API features into the kernel. Since cryptsetup luksDump told me my encrypted partition uses an SHA hash, I chose every feature with "SHA" in its description. I also built in every mode of operation not marked EXPERIMENTAL. (I am using kernel 2.6.31-r6 on amd64.)

I wish I had approached the problem more scientifically so I could tell you which change did the trick. But I didn't want to wait for genkernel to compile after each change!

GRUB worked when I had it pass almost the same kernel arguments you did with LILO. I did not try to append a ramdisk argument; there was no ill effect, perhaps because an 8M ramdisk was set as default in my kernel configuration. Framebuffer arguments didn't hurt me, though their effective function continued to elude me!

Last lvcreate ...
2010-08-18 22:33 - arantius

The last lvcreate command there could be simpler:

lvcreate --extents 100%FREE --name home vg

Automatically taking the remaining free space for you.

Changes
2010-10-20 00:04 - arantius

I've set up another machine. Turns out tvhwy is quite right, a non-default SHA related routine is important. So the following changes have been edited in above:

Post a comment:

Username
Password
  If you do not have an account to log in to yet, register your own account. You will not enter any personal info and need not supply an email address.
Subject:
Comment:

You may use Markdown syntax in the comment, but no HTML. Hints:

  • An empty line between text will create a paragraph boundary.
  • Use angle braces around a plain URL to auto-link it: <http://www.example.com/>.
  • Use this format to create a link with different text showing: [An Example](http://www.example.com/).
  • Use backticks (``), not leading spaces to enclose a code block.

If you are attempting to contact me, ask me a question, etc, please send me a message through the contact form rather than posting a comment here. Thank you. (If you post a comment anyway when it should be a message to me, I'll probably just delete your comment. I don't like clutter.)