Root on ZFS with native encryption: Difference between revisions

From Alpine Linux
(replace linux-vanilla with linux-lts)
(update to reflects steps for latest version v3.12)
Line 1: Line 1:
= Introduction =
= Setting up  Alpine Linux using ZFS with a pool that uses ZFS' native encryption capabilities =


This documentation describes how to set up Alpine Linux using ZFS with a pool that uses ZFS' native encryption capabilities, which have been recently introduced in ZFS on Linux (ZoL) 0.8.0.
== Download ==


Note that you must install the <code>/boot/</code> directory on an unencrypted partition (either an unencrypted ZFS pool or any other FS of your choosing, if it's compatible with your bootloader) to boot correctly.
Download the '''extended'' release from https://www.alpinelinux.org/downloads/ as only it contains the zfs kernel mods at the time of this writing (2020.07.10)


== Requirements ==
Write it to a USB and boot from it.


You'll need a medium to put a live image on. You can use any live medium that supports ZoL >=0.8.x, but as of writing this it's easiest to use [https://ubuntu.com/download/desktop Ubuntu 19.10], which comes with ZFS pre-installed.
== Initial setup ==


== Hard Disk Device Name ==
Run the following


The following documentation uses the <code>/dev/sda</code> device as installation destination. If your environment uses a different device name for your hard disk, use the corresponding device names in the examples. It also uses <code>rpool</code> as name of the root pool, you can change this at will, but be sure to change it everywhere it's mentioned.
    setup-alpine


= Setting up Alpine Linux Using ZFS with native encryption =
Answer all the questions, and hit ctrl-c when promted for what disk you'd like to use.


To install Alpine Linux in a ZFS pool with encryption enable, you cannot use the [[Installation|official installation]] procedure, so follow along this guide.
== OPTIONAL ==


== Creating the Partition Layout ==
This section is optional and it assumes internet connectivity. You may enable sshd so you can ssh into the box and copy and paste the rest of the commands into my terminal window from these instructions.


Linux requires an unencrypted <code>/boot/</code> partition to boot. You can assign the remaining space for the encrypted ZFS pool.
Edit `/etc/ssh/sshd_config` and search for `Permit`. Change the value after `PermitRootLogin` to read `yes`


* Start the <code>fdisk</code> utility to set up partitions:
save and exit to shell. Run `service sshd restart`


# fdisk /dev/sda
Now you can ssh in as root. Do not forget to go back and comment this line out when you're done since it will be enabled on your resulting machine. You will be reminded again at the end of this doc.


:* Create the <code>/boot/</code> partition:
== Add needed packages  ==
::* Enter <code>n</code> &rarr; <code>p</code> &rarr; <code>1</code> &rarr; <code>1</code> &rarr; <code>100m</code> to create a new 100 MB primary partition.


:* Set the <code>/boot/</code> partition active:
    apk add zfs sfdisk e2fsprogs syslinux
::* Enter <code>a</code> &rarr; <code>1</code>.


:* Create the ZFS partition:
== Create our partitions ==
::* Enter <code>n</code> &rarr; <code>p</code> &rarr; <code>2</code> to start creating the next partition. Press <code>Enter</code> to select the default start cylinder. Enter the size of partition. For example, <code>512m</code> for 512 MB or <code>5g</code> for 5 GB. Alternatively press <code>Enter</code> to set the maximum available size.


:* To verify the settings, press <code>p</code>. The output shows, for example:
We're assuming `/dev/sda` here and in the rest of the document but you can use whatever you need to. To see a list, type: `sfdisk -l`
<pre>
Device    Boot  Start      End  Sectors  Size Id Type
/dev/sda1  *      2048  206847  204800  100M 83 Linux
/dev/sda2      206848 41943039 41736192 19.9G 83 Linux
</pre>
* Press <code>w</code> to save the changes.


== Setting up the root pool ==
    echo -e "/dev/sda1: start=1M,size=100M,bootable\n/dev/sda2: start=101M" | sfdisk --quiet --label dos /dev/sda


You can create your rootpool with the following command:
== Create device nodes ==


# zpool create -o ashift=12 \
    mdev -s
      -O acltype=posixacl -O canmount=off -O compression=lz4 \
 
      -O dnodesize=auto -O normalization=formD -O relatime=on -O xattr=sa \
== Create the /boot filesystem ==
      -O encryption=aes-256-gcm -O keylocation=prompt -O keyformat=passphrase \
 
      -O mountpoint=/ -R /mnt \
    mkfs.ext4 /dev/sda1
      rpool /dev/sda2
 
== Create the root filesystem using zfs ==
 
    modprobe zfs
    zpool create -f -o ashift=12 \
        -O acltype=posixacl -O canmount=off -O compression=lz4 \
        -O dnodesize=auto -O normalization=formD -O relatime=on -O xattr=sa \
        -O encryption=aes-256-gcm -O keylocation=prompt -O keyformat=passphrase \
        -O mountpoint=/ -R /mnt \
        rpool /dev/sda2


You will have to enter your passphrase at this point. Choose wisely, as your passphrase is most likely [https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions#5-security-aspects the weakest link in this setup].
You will have to enter your passphrase at this point. Choose wisely, as your passphrase is most likely [https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions#5-security-aspects the weakest link in this setup].
Line 57: Line 57:
A few notes on the options supplied to zpool:
A few notes on the options supplied to zpool:


* <code>ashift=12</code> is recommended here because many drives today have 4KiB (or larger) physical sectors, even though they present 512B logical sectors
- `ashift=12` is recommended here because many drives today have 4KiB (or larger) physical sectors, even though they present 512B logical sectors


* <code>acltype=posixacl</code> enables POSIX ACLs globally
- `acltype=posixacl` enables POSIX ACLs globally


* <code>normalization=formD</code> eliminates some corner cases relating to UTF-8 filename normalization. It also enables <code>utf8only=on</code>, meaning that only files with valid UTF-8 filenames will be accepted.
- `normalization=formD` eliminates some corner cases relating to UTF-8 filename normalization. It also enables `utf8only=on`, meaning that only files with valid UTF-8 filenames will be accepted.


* <code>xattr=sa</code> vastly improves the performance of extended attributes, but is Linux-only. If you care about using this pool on other OpenZFS implementation don't specify this option.
- `xattr=sa` vastly improves the performance of extended attributes, but is Linux-only. If you care about using this pool on other OpenZFS implementation don't specify this option.


After completing this, confirm that the pool has been created:
After completing this, confirm that the pool has been created:


# zpool status
    # zpool status


Should return something like:
Should return something like:
<pre>
  pool: rpool
state: ONLINE
  scan: none requested
config:
NAME        STATE    READ WRITE CKSUM
rpool      ONLINE      0    0    0
  sda2  ONLINE      0    0    0
errors: No known data errors
</pre>
=== Creating the required datasets ===
# zfs create -o mountpoint=none -o canmount=off rpool/ROOT
# zfs create -o mountpoint=legacy rpool/ROOT/alpine
# mount -t zfs rpool/ROOT/alpine /mnt/
=== Creating optional datasets (feel free to add your own) ===
# zfs create -o mountpoint=/home rpool/HOME
# zfs create -o mountpoint=/var/log rpool/LOG
== Creating the <code>/boot</code> filesystem ==
# mkfs.ext4 /dev/sda1
== Mounting the <code>/boot</code> filesystem ==
* Create the <code>/mnt/boot/</code> directory and mount the <code>/dev/sda1</code> partition in this directory:
# mkdir /mnt/boot/
# mount -t ext4 /dev/sda1 /mnt/boot/
== Installing Alpine Linux ==
Please follow [[Installing_Alpine_Linux_in_a_chroot|Installing Alpine Linux in a chroot]] to setup a base install of Alpine Linux.
After you've followed that guide, you still have to do some additional setup for ZFS:
* As of the time of writing this ZFS 0.8.x is only available in [[Edge]], so you'll have to enable it in <code>/etc/apk/repositories</code>. Check [https://pkgs.alpinelinux.org/packages?name=zfs pkgs.alpinelinux.org] to see the status of this.
* Install the ZoL and linux-lts package: <code>apk add linux-lts zfs</code>
* Enable ZFS' services:
# rc-update add zfs-import sysinit
# rc-update add zfs-mount sysinit
* Edit the <code>/etc/mkinitfs/mkinitfs.conf</code> file and append <code>zfs</code> module to the <code>features</code> parameter:
features="ata base ide scsi usb virtio ext4 lvm <u>zfs</u>"
Be mindful to also include other modules which may be required for your setup, such as the <code>nvme</code> module.
* Rebuild the initial RAM disk:
# mkinitfs $(ls /lib/modules/)
* Edit the <code>/etc/update-extlinux.conf</code> file, set the root ZFS dataset and append the following kernel options to the <code>default_kernel_opts</code> parameter:
root=rpool/ROOT/alpine
default_kernel_opts="... <u>rootfstype=zfs</u>"
* Update extlinux's config (if you're not using a different bootloader)
# update-extlinux
# exit
: Ignore the errors the <code>update-extlinux</code> utility displays.
* Write the MBR to the <code>/dev/sda</code> device:
# dd bs=440 count=1 conv=notrunc if=/mnt/usr/share/syslinux/mbr.bin of=/dev/sda
== Unmounting the filesystems ==
* Unmount <code>/mnt/boot/</code>:
# umount /mnt/boot/
* Unmount all zfs filesystems:
# zfs unmount -a
* Reboot the system:


# reboot
      pool: rpool
    state: ONLINE
      scan: none requested
    config:


== Booting the system ==
        NAME        STATE    READ WRITE CKSUM
        rpool      ONLINE      0    0    0
          sda2      ONLINE      0    0    0


Right now mkinitfs doesn't support ZFS asking for passwords during boot, so it'll throw you into a rescue shell for you to enter the password during boot. You have to do the following things after pressing enter:
    errors: No known data errors


# zfs load-key -a
== Create the required datasets and mount root ==
# mount -t zfs rpool/ROOT/alpine /sysroot
# exit


And your system should continue booting! :)
    zfs create -o mountpoint=none -o canmount=off rpool/ROOT
    zfs create -o mountpoint=legacy rpool/ROOT/alpine
    mount -t zfs rpool/ROOT/alpine /mnt/


= Troubleshooting =
== Mount the `/boot` filesystem ==


== General Procedure ==
    mkdir /mnt/boot/
    mount -t ext4 /dev/sda1 /mnt/boot/


In case your system fails to boot, you can verify the settings and fix incorrect configurations:
=== Enable ZFS' services ===


* [[#Preparing_the_Installation_Environment|Preparing the Installation Environment]]
    rc-update add zfs-import sysinit
    rc-update add zfs-mount sysinit


* Load the ZFS kernel module:
== Install Alpine Linux ==


# modprobe zfs
    setup-disk /mnt
    dd if=/usr/share/syslinux/mbr.bin of=/dev/sda # write mbr so we can boot


* [[#Mounting_the_File_Systems|Mount the file systems]]


# zpool import -R /mnt rpool
== Reboot and enjoy! ==
# mount -t ext4 /dev/sda1 /mnt/boot


* Verify that you run the steps described in the [[#Installing_Alpine_Linux|Installing Alpine Linux]] section correctly. Update the configuration if necessary.
😉


[[Category:Storage]]
'''NOTE:'''
[[Category:Security]]
If you went with the optional step, be sure to disable root login after you reboot.

Revision as of 22:54, 11 July 2020

Setting up Alpine Linux using ZFS with a pool that uses ZFS' native encryption capabilities

Download

Download the 'extended release from https://www.alpinelinux.org/downloads/ as only it contains the zfs kernel mods at the time of this writing (2020.07.10)

Write it to a USB and boot from it.

Initial setup

Run the following

   setup-alpine

Answer all the questions, and hit ctrl-c when promted for what disk you'd like to use.

OPTIONAL

This section is optional and it assumes internet connectivity. You may enable sshd so you can ssh into the box and copy and paste the rest of the commands into my terminal window from these instructions.

Edit `/etc/ssh/sshd_config` and search for `Permit`. Change the value after `PermitRootLogin` to read `yes`

save and exit to shell. Run `service sshd restart`

Now you can ssh in as root. Do not forget to go back and comment this line out when you're done since it will be enabled on your resulting machine. You will be reminded again at the end of this doc.

Add needed packages

   apk add zfs sfdisk e2fsprogs syslinux

Create our partitions

We're assuming `/dev/sda` here and in the rest of the document but you can use whatever you need to. To see a list, type: `sfdisk -l`

   echo -e "/dev/sda1: start=1M,size=100M,bootable\n/dev/sda2: start=101M" | sfdisk --quiet --label dos /dev/sda

Create device nodes

   mdev -s

Create the /boot filesystem

   mkfs.ext4 /dev/sda1

Create the root filesystem using zfs

   modprobe zfs
   zpool create -f -o ashift=12 \
       -O acltype=posixacl -O canmount=off -O compression=lz4 \
       -O dnodesize=auto -O normalization=formD -O relatime=on -O xattr=sa \
       -O encryption=aes-256-gcm -O keylocation=prompt -O keyformat=passphrase \
       -O mountpoint=/ -R /mnt \
       rpool /dev/sda2

You will have to enter your passphrase at this point. Choose wisely, as your passphrase is most likely the weakest link in this setup.

A few notes on the options supplied to zpool:

- `ashift=12` is recommended here because many drives today have 4KiB (or larger) physical sectors, even though they present 512B logical sectors

- `acltype=posixacl` enables POSIX ACLs globally

- `normalization=formD` eliminates some corner cases relating to UTF-8 filename normalization. It also enables `utf8only=on`, meaning that only files with valid UTF-8 filenames will be accepted.

- `xattr=sa` vastly improves the performance of extended attributes, but is Linux-only. If you care about using this pool on other OpenZFS implementation don't specify this option.

After completing this, confirm that the pool has been created:

   # zpool status

Should return something like:

     pool: rpool
    state: ONLINE
     scan: none requested
   config:
       NAME        STATE     READ WRITE CKSUM
       rpool       ONLINE       0     0     0
         sda2      ONLINE       0     0     0
   errors: No known data errors

Create the required datasets and mount root

   zfs create -o mountpoint=none -o canmount=off rpool/ROOT
   zfs create -o mountpoint=legacy rpool/ROOT/alpine
   mount -t zfs rpool/ROOT/alpine /mnt/

Mount the `/boot` filesystem

   mkdir /mnt/boot/
   mount -t ext4 /dev/sda1 /mnt/boot/

Enable ZFS' services

   rc-update add zfs-import sysinit
   rc-update add zfs-mount sysinit

Install Alpine Linux

   setup-disk /mnt
   dd if=/usr/share/syslinux/mbr.bin of=/dev/sda # write mbr so we can boot


Reboot and enjoy!

😉

NOTE: If you went with the optional step, be sure to disable root login after you reboot.