Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Optional LUKS encryption of rootfs #948

Merged
merged 7 commits into from May 28, 2018

Conversation

@zciendor
Copy link
Contributor

@zciendor zciendor commented Apr 30, 2018

Initial implementation for feature request #947

This set of changes allows optional encryption of the root filesystem using LUKS when building the Armbian image.
The following 4 advanced build options were added:

  • CRYPTROOT_ENABLE=yes # encrypt the root file system
  • CRYPTROOT_PASSPHRASE="1234" # mandatory passphrase to unlock root file system on boot
  • CRYPTROOT_SSH_UNLOCK=yes # enable ssh (dropbear) during boot to unlock root file system
  • CRYPTROOT_SSH_UNLOCK_PORT=2222 # change the ssh port of the boot system to avoid host key changed conflicts

Implementation details:

lib/configuration.sh

Add the packages cryptsetup and dropbear-initramfs if the respective build options are set.

packages/bsp/common/etc/init.d/resize2fs

Added logic to handle partitions of type crypt (LUKS container) and automatic resizing of the
LUKS container before the root filesystem can be expanded.

/lib/debootstrap-ng.sh

This file needed the most changes (mostly additions).

  1. We need a 2-partition layout when using LUKS encryption (CRYPTROOT_ENABLE=yes)
  2. We need to create the LUKS container before the filesystem can be created (mkfs)
  3. We need to add the file /etc/crypttab with the respective partition mapping
  4. /etc/fstab needs to mount the root filesystem from the LUKS container (crypttab)
  5. /boot/armbian.txt and /boot/boot.ini need to be modified accordingly to be able to boot from a cryptroot
  6. update-initramfs needs to be called, so cryptsetup and dropbear get included in the initramfs
  7. If the build options enable early boot SSH access (CRYPTROOT_SSH_UNLOCK=yes) a SSH keypair needs to be generated for the dropbear SSH daemon. This is needed for boards without a display connector.
  8. If the build options specify a non-default SSH port for the boot system (dropbear) via CRYPTROOT_SSH_UNLOCK_PORT=<PORT>, we need to modify /etc/dropbear-initramfs/config accordingly.
  9. The crypt device (LUKS container) needs to be closed after unmounting root when image creation is complete.
zciendor added 3 commits Apr 30, 2018
Replaced all (5) occurences of `${LOOP}p${rootpart}` with `$rootdevice`. This minor refactoring makes further additions easier to merge. For example using a LUKS mapper device `/dev/mapper/cryptroot` instead of `/dev/loop0p2` as the actual root device can now be handled by just re-assigning the `$rootdevice` variable, while all other related code lines (mkfs, mount, ...) won't need to change.
This set of changes allows optional encryption of the root filesystem using LUKS when building the Armbian image.
The following 4 advanced build options were added:
- CRYPTROOT_ENABLE=yes              # encrypt the root file system
- CRYPTROOT_PASSPHRASE="1234"       # passphrase to unlock root file system on boot
- CRYPTROOT_SSH_UNLOCK=yes  # enable ssh (dropbear) during boot to unlock root file system
- CRYPTROOT_SSH_PORT=2222   # change the ssh port of the root system to avoid host key changed conflicts

Implementation details:

lib/configuration.sh
--------------------
Add the packages `cryptsetup` and `dropbear-initramfs` if the respective build options are set.

packages/bsp/common/etc/init.d/resize2fs
----------------------------------------
Added logic to handle partitions of type `crypt` (LUKS container) and automatic resizing of the
LUKS container before the root filesystem can be expanded.

/lib/debootstrap-ng.sh
----------------------
This file needed the most changes (mostly additions).
1. We need a 2-partition layout when using LUKS encryption (`CRYPTROOT_ENABLE=yes`)
2. We need to create the LUKS container before the filesystem can be created (mkfs)
3. We need to add the file `/etc/crypttab` with the respective partition mapping
4. `/etc/fstab` needs to mount the root filesystem from the LUKS container (crypttab)
5. `/boot/armbian.txt` and `/boot/boot.ini` need to be modified accordingly to be able to boot from a `cryptroot`
6. `update-initramfs` needs to be called, so `cryptsetup` and `dropbear` get included in the initrmafs
7. If the build options enable early boot SSH access (`CRYPTROOT_SSH_UNLOCK=yes`) a SSH keypair needs to be generated for the `dropbear` SSH daemon. This is needed for boards without a display connector.
8. If the build options specify a non-default SSH port for the root system (OpenSSH) via `CRYPTROOT_SSH_PORT=<PORT>`, we need to modify `/etc/sshd_config` accordingly.
9. The crypt device (LUKS container) needs to be closed after unmounting root when image creation is complete.
@zador-blood-stained
Copy link
Member

@zador-blood-stained zador-blood-stained commented May 1, 2018

The idea and implementation looks good to me, thanks for the work and prior tests, but I think it can (and should be) simplified. Since I'm not sure that we want to build and distribute cryptroot-enabled images by default, some things are not needed IMO.

My current thougts:

CRYPTROOT_PASSPHRASE="1234" # passphrase to unlock root file system on boot

I would make this option mandatory if CRYPTROOT_ENABLE=yes and get rid of the default passphrase and warnings associated with it.

CRYPTROOT_SSH_PORT=2222 # change the ssh port of the root system to avoid host key changed conflicts

I would adjust the dropbear port instead and leave changing /etc/ssh/sshd_config up to the user.

/boot/armbian.txt and /boot/boot.ini need to be modified accordingly to be able to boot from a cryptroot

I believe we also need to add "ip=dhcp" (or the static network config) to the kernel command line in case we want to use the SSH unlock option

If the build options enable early boot SSH access (CRYPTROOT_SSH_UNLOCK=yes) a SSH keypair needs to be generated for the dropbear SSH daemon. This is needed for boards without a display connector.

I looked at the dropbear-initramfs package contents and looks like it will be automatically included in the initramfs and it will generate a host key on first install automatically, so we don't need any additional logic in debootstrap-ng.sh for it.

And I would not dump the contents of armbianEnv.txt or boot.ini to the terminal and instead grep the necessary lones and redirect them to the debootstrap log file.

@zador-blood-stained
Copy link
Member

@zador-blood-stained zador-blood-stained commented May 1, 2018

Please note that you can amend and force-push any changes to your branch so you don't need to close this PR.

@rosbeef
Copy link

@rosbeef rosbeef commented May 13, 2018

as i said in the other post it could be made as a post install script. like nand-sata-install it could be nand-sata-encryptedroot-install

somthing like that is working manually for me with the kernel 4.9 but not for the 4.14 directly on the running odroid

apt update
apt upgrade
apt install lvm2 busybox cryptsetup dropbear rsync
sed -e 's/^#CRYPTSETUP=/CRYPTSETUP=y' -i /etc/cryptsetup-initramfs/conf-hook

cryptsetup luksFormat --type luks2 /dev/sda
cryptsetup luksOpen /dev/sda sdc

pvcreate --dataalignmentoffset 1s /dev/mapper/sdc
vgcreate sdg /dev/mapper/sdc
lvcreate -L 32G /dev/mapper/sdg -n root
lvcreate -l 100%FREE /dev/mapper/sdg -n data

mkfs.ext4 /dev/sdg/root -E discard
mkfs.ext4 /dev/sdg/data -E discard

-----------------------
Copy the root partition to SSD
----------------------- 
mount /dev/sdg/root /mnt 

sudo rsync -ahPHAXx --delete --exclude={/dev/*,/proc/*,/sys/*,/tmp/*,/run/*,/mnt/*,/media/*,/lost+found} / /mnt
touch /mnt/root/.no_rootfs_resize

-----------------------
prepare the root partition
-----------------------
mount -o rbind /dev/mmcblk1p1 /mnt/boot
mount -o rbind /dev /mnt/dev
mount -t proc proc /mnt/proc
mount -t sysfs sys /mnt/sys

rm /mnt/etc/resolv.conf
cp /etc/resolv.conf /mnt/etc

chroot .

apt update
apt upgrade
apt install lvm2 busybox cryptsetup dropbear

#here maybe asked for username and remote machine ip
rsync yourusername@remote_machine:.ssh/id_*.pub /etc/dropbear-initramfs/authorized_keys

sed -e 's/^#CRYPTSETUP=/CRYPTSETUP=y/' -i /etc/cryptsetup-initramfs/conf-hook
cat /etc/cryptsetup-initramfs/conf-hook

sed -e 's/^DROPBEAR_OPTIONS=/DROPBEAR_OPTIONS=\"-p 22222\"/' -i /etc/dropbear-initramfs/config
cat /etc/dropbear-initramfs/config

echo 'sdc /dev/sda none luks,initramfs,discard' >> /etc/crypttab 
cat /etc/crypttab 

echo '/dev/sdg/root / ext4 defaults,noatime,nodiratime,commit=600,errors=remount-ro 0 1' >> /etc/fstab
#echo '/dev/sdg/data /home ext4 defaults,noatime,nodiratime,commit=600,errors=remount-ro 0 2' >> /etc/fstab
echo 'tmpfs /tmp tmpfs defaults,nosuid 0 0' >> /etc/fstab
cat /etc/fstab

exit
umount /mnt/boot
umount /mnt/proc
umount /mnt/sys
umount /mnt/dev/mqueue
umount /mnt/dev/shm
umount -l /mnt/dev/pts
umount /mnt/dev

#one more time
rsync yourusername@remote_machine:.ssh/id_*.pub /etc/dropbear-initramfs/authorized_keys

sed -e 's/root=\/dev\/sdg\/root cryptopts=source=\/dev\/sda,target=sdc,lvm=sdg/' -i /media/boot/boot.ini.default
update-initramfs -u
mkimage -C none -A arm -T script -d /boot/boot.ini /boot/boot.scr

@rosbeef
Copy link

@rosbeef rosbeef commented May 14, 2018

the working script on Armbian_5.44.180510_Odroidxu4_Debian_stretch_dev_4.14.40 image

apt update
apt upgrade
apt install rsync
mkdir /etc/dropbear-initramfs/
rsync yourusername@your_laptop_ip:.ssh/id_*.pub /etc/dropbear-initramfs/authorized_keys

apt install lvm2 cryptsetup dropbear-initramfs
sed -e 's/^#CRYPTSETUP=/CRYPTSETUP=y/' -i /etc/cryptsetup-initramfs/conf-hook
cat /etc/cryptsetup-initramfs/conf-hook
sed -e 's/^#DROPBEAR_OPTIONS=/DROPBEAR_OPTIONS="-p 22222"/' -i /etc/dropbear-initramfs/config
cat /etc/dropbear-initramfs/config

cryptsetup luksFormat /dev/sda
cryptsetup luksOpen /dev/sda sdc

pvcreate --dataalignmentoffset 1s /dev/mapper/sdc
vgcreate sdg /dev/mapper/sdc
lvcreate -L 32G /dev/mapper/sdg -n root
lvcreate -l 100%FREE /dev/mapper/sdg -n data

mkfs.ext4 /dev/sdg/root -E discard
mkfs.ext4 /dev/sdg/data -E discard


Copy the root partition to SSD

mount /dev/sdg/root /mnt

sudo rsync -ahPHAXx --delete --exclude={/boot/,/dev/,/proc/,/sys/,/tmp/,/run/,/mnt/,/media/,/lost+found} / /mnt
touch /mnt/root/.no_rootfs_resize

CRYPTTAB

echo 'sdc /dev/sda none luks,initramfs,discard' >> /mnt/etc/crypttab
cat /mnt/etc/crypttab

FSTAB

echo '/dev/sdg/root / ext4 defaults,noatime,nodiratime,commit=600,errors=remount-ro 0 1' >> /mnt/etc/fstab
echo '/dev/sdg/data /home ext4 defaults,noatime,nodiratime,commit=600,errors=remount-ro 0 2' >> /mnt/etc/fstab
#echo 'tmpfs /tmp tmpfs defaults,nosuid 0 0' >> /mnt/etc/fstab
cat /mnt/etc/fstab

BOOTINI

cp /boot/boot.ini /boot/boot.ori

sed -e 's/root=.*"/root=/dev/sdg/root cryptopts=source=/dev/sda,target=sdc,lvm=sdg"/' -i /media/boot/boot.ini.default

update-initramfs -u

mkimage -C none -A arm -T script -d /boot/boot.ini /boot/boot.s

@zciendor
Copy link
Contributor Author

@zciendor zciendor commented May 14, 2018

@zador-blood-stained

If the build options enable early boot SSH access (CRYPTROOT_SSH_UNLOCK=yes) a SSH keypair needs to be generated for the dropbear SSH daemon. This is needed for boards without a display connector.

I looked at the dropbear-initramfs package contents and looks like it will be automatically included in the initramfs and it will generate a host key on first install automatically, so we don't need any additional logic in debootstrap-ng.sh for it.

It's not the host key which is generated here! It's the public/private key pair you need to connect to dropbear using public key authentication. dropbear-initramfs doesn't create one automatically, also not on first start.

@zciendor
Copy link
Contributor Author

@zciendor zciendor commented May 14, 2018

@zador-blood-stained

/boot/armbian.txt and /boot/boot.ini need to be modified accordingly to be able to boot from a cryptroot

I believe we also need to add "ip=dhcp" (or the static network config) to the kernel command line in case we want to use the SSH unlock option

ip=dhcp is not needed. This seems to be the default. But I can add it if you prefer for clarity?

@zciendor
Copy link
Contributor Author

@zciendor zciendor commented May 14, 2018

@zador-blood-stained

I would make this option mandatory if CRYPTROOT_ENABLE=yes and get rid of the default passphrase and warnings associated with it.

OK. I'll fix that.

I would adjust the dropbear port instead and leave changing /etc/ssh/sshd_config up to the user.

OK. I'll check if the dropbear port can be configured and fix that.

@zciendor
Copy link
Contributor Author

@zciendor zciendor commented May 14, 2018

@rosbeef

Using a post-install script is possible if you have a board like the Odroid HC1/HC2 where you can attach another disk which you use to temporarily copy the root system to while preparing the root partition on the SD card. However, I thought my approach is more generic as it works for boards which don't have a second disk. I guess both approaches are valid and have their pros & cons.

Question: If I read your script correctly, you are using the SD card only for the boot partition, right? The actual root system is on the SATA disk and you use LVM to have 2 partitions there... one for root and one for data. Any specific reason, why you move the root system to the SATA disk? Better performance?

@zador-blood-stained
Copy link
Member

@zador-blood-stained zador-blood-stained commented May 14, 2018

ip=dhcp is not needed. This seems to be the default.

It is not the default option, but I looked through dropbear-initramfs scripts after my comment and the init-premount script tries to configure networking explicitly even if the kernel parameter is missing.

    # always run configure_networking() before dropbear(8); on NFS
    # mounts this has been done already
    [ "$boot" = nfs ] || configure_networking

Though dropbear-initramfs postinstall script still outputs this

	 Dropbear has been added to the initramfs. Don't forget to check
	your "ip=" kernel bootparameter to match your desired initramfs
	ip configuration.

But I can add it if you prefer for clarity?

No, don't think that is necessary for now, but it will require documentation for manual network configuration (w/o DHCP, yes, some people may want this for some reason) and a clarification that wireless network is not supported in this scenario.

It's not the host key which is generated here! It's the public/private key pair you need to connect to dropbear using public key authentication. dropbear-initramfs doesn't create one automatically, also not on first start.

I see. I expected authorized_keys being the only possible file for storing the public key. Though IMO storing an unencrypted private key in /etc is not a good idea even with disk encryption, so I may rework this later to copy an existing authorized_keys file from userpatches in the build script directory and skipping generation of a new key pair in this case.

OK. I'll check if the dropbear port can be configured and fix that.

Something like

sed -i 's/#DROPBEAR_OPTIONS=.*/DROPBEAR_OPTIONS="-p 2022"/' /etc/dropbear-initramfs/config

should work

zciendor added 3 commits May 14, 2018
According to upstream feedback:
armbian#948 (comment)

Removed default passphrase when LUKS encryption is enabled and the related warnings. Also made `CRYPTROOT_PASSPHRASE` mandatory along with `CRYPTROOT_ENABLE=YES` and abort if missing.
According to upstream feedback:
armbian#948 (comment)

Allow configuration of the dropbear SSH port instead of the sshd port of the root system. This leaves `/etc/ssh/sshd_config` unchanged. Renamed the configuration variable to `CRYPTROOT_SSH_UNLOCK_PORT`.
According to upstream feedback:
armbian#948 (comment)

Don't dump the contents of armbianEnv.txt or boot.ini to the terminal.
@zciendor
Copy link
Contributor Author

@zciendor zciendor commented May 14, 2018

@zador-blood-stained

Please note that you can amend and force-push any changes to your branch so you don't need to close this PR.

I pushed all requested changes to my development branch. However, I did a regular push and don't know what you mean by amend and force-push to update this pull request. Please give me a little advice/instructions.

@zciendor
Copy link
Contributor Author

@zciendor zciendor commented May 14, 2018

@zador-blood-stained

No, don't think that is necessary for now, but it will require documentation for manual network configuration (w/o DHCP, yes, some people may want this for some reason) and a clarification that wireless network is not supported in this scenario.

OK. I only tested with Ethernet (LAN) of the Odroid HC1 and there it works with DHCP without adding the ip= kernel boot parameter. I see that some users might want to configure a static IP where this is necessary. Haven't tested with wireless yet!

Were should the documentation for this be done? Do you want me to take care of that and mention the limitations as of now?

@rosbeef
Copy link

@rosbeef rosbeef commented May 15, 2018

@zciendor
Hi yes i would both :

  • use an old small 2G sd card sleeping in my drawer.
  • improve performances

zador-blood-stained added a commit that referenced this issue May 28, 2018
[WIP] Feature: Optional LUKS encryption of rootfs
@zador-blood-stained zador-blood-stained merged commit b905fbc into armbian:development May 28, 2018
zciendor added a commit to zhiverbox/armbian-build that referenced this issue Jul 31, 2018
This was already implemented with armbian#948,
before but never made it into the master branch yet. Probably because the
development branch has been abandoned in the meantime and it is to much effort
now to merge it into master.

It includes all the cleanup changes from commit 08743d3 and has been successfully
tested on an Odroid HC1.

In addition to what is currently in the `luks` branch the following improvments
where done/added:

1. update_initramfs() function in debbootstrap-ng.sh, which needs to be invoked
   after the partition layout and /etc/crypttab was created. Else `cryptroot-unlock`
   won't work and you'll run into:
   https://serverfault.com/questions/907254/cryproot-unlock-with-dropbear-timeout-while-waiting-for-askpass

   Apart from that it might be useful to always run `update-initramfs` at the end
   of the build process anyway, in case customize_image (userpatches) made some
   changes to the initramfs tools configs.

2. CRYPTROOT_SSH_UNLOCK=yes/no config option. It's by default set to yes, but it
   might be desired by some users to disable enable SSH/dropbear access while
   still having LUKS support. E.g. if they have a device that has a display
   and keyboard.

3. If no `authorized_keys` file is provided via userpatches, a new SSH key pair
   is generated and for convenience copied to the output directory along with
   the final image.
@s-unger
Copy link

@s-unger s-unger commented Sep 5, 2019

sed -e 's/root=.*"/root=/dev/sdg/root cryptopts=source=/dev/sda,target=sdc,lvm=sdg"/' -i /media/boot/boot.ini.default

I had an issue with that command, so I changed it with some help to this one:

sed -e 's!root=.*"!root=/dev/sdg/root cryptopts=source=/dev/sda,target=sdc,lvm=sdg"!' -i /media/boot/boot.ini.default

Which is working but could not find the file - so there is still work for me to search this file.


Okay, I crashed my System with this ( No init found. Try passing init= bootarg.). Thankfully I did an SD Card Backup so I could revert. Is anyone still here to tell me what I am doing wrong?

I changed the init.d file on the standard root partition. Maby it was the wrong one?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

4 participants