Closed CMCDragonkai closed 6 years ago
The way I do this, with an encrypted /boot
on the same partition as /
, is as follows:
boot.initrd.luks.devices = [{
name = "cryptlvm"; device = "/dev/disk/by-uuid/<redacted>";
allowDiscards = true;
keyFile = "/crypto_keyfile.bin";
}];
boot.initrd.prepend = ["${/crypto_keyfile.cpio.gz}"];
Works fine on nixos unstable without the errors you're mentioning. You could set up secondary encrypted filesystems with crypttab
if you wanted to.
iirc crypto_keyfile.cpio.gz
is created with
cpio -o -H newc <<< "crypto_keyfile.bin" > crypto_keyfile.cpio
gzip crypto_keyfile.cpio
I think the difference between your method and mine is that I'm also de rypting the keyfile image. That is a single password to unlock the image and then all subsequent drives pointing to the unlocked device. It used to work without those errors, and now it has those errors but still works in the end. That makes me think something changed in the unlocking order. On 29/03/2017 10:25 AM, "Nick Hu" notifications@github.com wrote:
The way I do this, with an encrypted /boot on the same partition as /, is as follows:
boot.initrd.luks.devices = [{ name = "cryptlvm"; device = "/dev/disk/by-uuid/
"; allowDiscards = true; keyFile = "/crypto_keyfile.bin"; }]; boot.initrd.prepend = ["${/crypto_keyfile.cpio.gz}"]; Works fine on nixos unstable without the errors you're mentioning. You could set up secondary encrypted filesystems with crypttab if you wanted to.
iirc crypto_keyfile.cpio.gz is created with
cpio -o -H newc <<< "crypto_keyfile.bin" > crypto_keyfile.cpio gzip crypto_keyfile.cpio
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/NixOS/nixpkgs/issues/24386#issuecomment-289935501, or mute the thread https://github.com/notifications/unsubscribe-auth/AAnHHdSgRQNWF2SGlZWKdzfY-SMjEvaXks5rqZb9gaJpZM4MqSCc .
Yes I have grub prompt me for a password and then unlock my filesystems afterwards - just thought you might like an insight on a different approach to largely achieve the same thing. I don't think it's documented anywhere that nixos is supposed to respect the order of your entries, and it's not evaluated sequentially like a bash script. The standard approach across most Linux distros is that crypttab
is used to unlock dependant/second-stage encrypted drives.
@NickHu Sorry but I don't understand, I'm using boot.initrd.prepend
in the same way you are proposing. Your one is called /crypto_keyfile.bin
and mine is called /luks-key.img
which gets decrypted and mapped to /dev/mapper/luks-key-encrypted
. I noticed that you don't have your keyfile image being part of the Luks devices list, maybe that's the thing I'm missing?
@NickHu How was your /crypto_keyfile.bin
created? My method was through this: https://gist.github.com/CMCDragonkai/6456d974982e09d4fe71f339f9029bd3
There's no need to make the keyfile a block device, a simple file will suffice:
dd bs=512 count=4 if=/dev/urandom of=/crypto_keyfile.bin
cryptsetup luksAddKey /dev/sda1 /crypto_keyfile.bin
chmod 000 /crypto_keyfile.bin
Also, the kernel parameter defaults to look for /crypto_keyfile.bin
in the root if it exists, otherwise it has to be specified with the cryptkey
parameter on the kernel command line.
I didn't know about that feature. That's very useful. What kernel parameter causes a defaulting to /crypto_keyfile.bin
? Just wondering if this is a NixOS thing or a LUKs thing.
It's a Linux default as far as I'm aware.
How is your crypto_keyfile.bin password protected? I didn't see any gpg encryption or luks encryption in your examples.
It's in the root partition which is decrypted by grub at boot time. I have a unified boot/root partition. When grub hands off to the Linux kernel, the partition gets locked again, but as the keyfile is in the initramfs (also on the encrypted partition), it can be unlocked by the kernel without prompting for a password the second time.
My zfs root is composed of several partitions that needs to be decrypted prior to zpool import. I don't know what you mean by "unified boot/root". Are you saying you use grub to unlock something and then it relocks it when in stage 1 boot phase? I'm currently using systemd boot and there's nothing like that.
Also my root and boot can't be unified because of uefi firmware which requires a fat32 boot partition. So that's where my keyfile image and initramfs currently reside.
Yes, as far as I'm aware, this only works with grub. If you don't have an encrypted /boot anyway, there's no need to do this and you can just use crypttab. The crypto keyfile is only useful for unlocking the root partition from the bootloader/initramfs.
I have just discovered why my system still works even when in the presence of the 2 errors.
First I found that my l2arc devices were not working:
♜ sudo zpool status pts/2 19:53:02
[sudo] password for cmcdragonkai:
pool: rpool
state: ONLINE
status: One or more devices could not be used because the label is missing or
invalid. Sufficient replicas exist for the pool to continue
functioning in a degraded state.
action: Replace the device using 'zpool replace'.
see: http://zfsonlinux.org/msg/ZFS-8000-4J
scan: none requested
config:
NAME STATE READ WRITE CKSUM
rpool ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
dm-name-main-encrypted-ata-ST2000LM003_HN-M201RAD_S321J9BFB03122-part1 ONLINE 0 0 0
dm-name-main-encrypted-ata-ST2000LM003_HN-M201RAD_S321J9BFB03123-part1 ONLINE 0 0 0
logs
mirror-1 ONLINE 0 0 0
dm-name-zil-encrypted-ata-PLEXTOR_PX-G128M6e_P02445180196-part2 ONLINE 0 0 0
dm-name-zil-encrypted-ata-PLEXTOR_PX-G128M6e_P02445180209-part2 ONLINE 0 0 0
cache
dm-name-l2arc-encrypted-ata-PLEXTOR_PX-G128M6e_P02445180196-part3 UNAVAIL 0 0 0
dm-name-l2arc-encrypted-ata-PLEXTOR_PX-G128M6e_P02445180209-part3 UNAVAIL 0 0 0
errors: No known data errors
Then I found that the within /dev/mapper
, the l2arc block devices no longer existed:
♖ ls /dev/mapper pts/2 19:59:35
control zil-encrypted-ata-PLEXTOR_PX-G128M6e_P02445180196-part2@
main-encrypted-ata-ST2000LM003_HN-M201RAD_S321J9BFB03122-part1@ zil-encrypted-ata-PLEXTOR_PX-G128M6e_P02445180209-part2@
main-encrypted-ata-ST2000LM003_HN-M201RAD_S321J9BFB03123-part1@
My investigation into dmesg showed no errors, and upon restart, I remembered the 2 messages appearing:
# this happens twice
Waiting 10 seconds for key file /dev/mapper/luks-key-encrypted to appear .....
I tested the actual partitions using:
sudo cryptsetup status l2arc-encrypted-ata-PLEXTOR_PX-G128M6e_P02445180196-part3
sudo cryptsetup --test-passphrase luksOpen /dev/disk/by-id/ata-PLEXTOR_PX-G128M6e_P02445180196-part3
sudo cryptsetup status l2arc-encrypted-ata-PLEXTOR_PX-G128M6e_P02445180209-part3
sudo cryptsetup --test-passphrase luksOpen /dev/disk/by-id/ata-PLEXTOR_PX-G128M6e_P02445180209-part3
And those partitions are working.
Then it occurred to me, that I have 7 luks devices specified under nixos configuration.nix.
luks-key-encrypted
main-encrypted-ata-ST2000LM003_HN-M201RAD_S321J9BFB03123-part1
main-encrypted-ata-ST2000LM003_HN-M201RAD_S321J9BFB03122-part1
zil-encrypted-ata-PLEXTOR_PX-G128M6e_P02445180196-part2
l2arc-encrypted-ata-PLEXTOR_PX-G128M6e_P02445180196-part3
zil-encrypted-ata-PLEXTOR_PX-G128M6e_P02445180209-part2
l2arc-encrypted-ata-PLEXTOR_PX-G128M6e_P02445180209-part3
And it turns out that in alphabetical order, l2arc-...
is ahead of luks...
.
This meant NixOS at stage 1 tried to unlock the 2 l2arc-...
devices, but couldn't because both relied on the existence of the unlocked /dev/mapper/luks-key-encrypted
device. So it showed those 2 failure messages, then it tried to unlock luks-...
device, which unlocked /dev/mapper/luks-key-encrypted
, and then all subsequent drives were automatically unlocked and the system proceeded as normal.
Which all the more points to the comments above mentioning the change in the luks order of operations: https://github.com/NixOS/nixpkgs/issues/24386#issuecomment-289939950
@NickHu it does appear that since UEFI doesn't allow a unified boot and root, then crypttab should be used. I'm still not sure how NixOS will ask for unlocking a password protected /crypto_keyfile.bin
and then feed that result into the subsequent luks devices.
So I looked at crypttab, and it appears that using crypttab is no different from just using NixOS's boot.initrd.luks.devices
specification. Both achieve the same thing. What neither achieves is the usage of a password-protected /crypto_keyfile.bin
. It is trivial to use one that is not password protected, as that is just the a property of keyFile
.
I think that we need a new NixOS luks option, that allows a designation of a primary keyfile device, whether that is /crypto_keyfile.bin
or my own /luks-key.img
, which then gets mapped to a name, and where that name can be used as the keyFile
setting for all other subsequent luks devices. This would achieve a password protected keyfile, that doesn't involve any extra tooling like gnupg, but only using existing luks tools.
Previously I was relying an insertion ordered luks opening operations, but with the new alphabetical ordering, a designated keyfile option should be used instead.
This option could automate a declarative single password unlock for LUKS systems, as upon nixos-rebuild, it could generate the cpio archive, attach it to initrd, and then make it the first LUKS device to be opened. Then it is up to the user to specify the /dev/mapper/...
as the keyfile for luks devices they want opened automatically.
I can try tackling a PR for this, but I would like some feed back on this idea.
My configuration works perfectly fine on my UEFI laptops. What you can do is put just the EFI booting stubs in the FAT32 EFI system partition mounted to /boot/efi
or something, and leave the kernel, initramfs, crypto_keyfile etc. on the /boot
partition unified to /
and use GRUB to boot it. As far as I am aware, GRUB is the only bootloader which supports loading a kernel/initramfs from an encrypted partition.
If I leave crypto_keyfile etc on /boot
unified to /
, this means the key (keys?) required to unlock the devices (listed above in my previous comment) needed for zpool import
will be inside the root zpool. Importing the zpool requires all LUKS devices to be unlocked prior. I don't see how your solution solves the problem?
It's not a good idea to partially import a zpool (which will be degraded because other mirrors will be missing, and you'll need the -f flag) just to get access to the crypto_key, to unlock all subsequent devices and finally reimporting the entire zpool. My zpool consists of 2 drives and 2 ssds, of which the ssds are each split into /boot, zil and l2arc.
Yeah, the way it works for me is that GRUB is able to mount encrypted filesystems - although I don't know if this extends to ZFS. In principle this has nothing to do with /boot
, so what you could do is put a crypto_keyfile.bin
which will unlock your ZFS drives on a partition that is in a LUKS device (could be separate) and have GRUB unlock that and then pass it to the kernel to decrypt your ZFS drives. That LUKS device could contain a tiny ext4
filesystem, and GRUB will prompt for the password when it tries to read from it. In essence, this is a way to emulate a password protected crypto_keyfile.bin
.
Alternatively, there may already be facilities in GRUB to handle password protected crypto_keyfile.bin
files, so switching bootloader might solve your problems.
So I see 3 ways around this:
The main issue, is that there must always be some part of the disk that is unencrypted so the UEFI can load the bootloader. I prefer symmetrical partition layouts, so I had previously researched into soft raid capabilities of UEFI, but it appears it's not recommended, as they only officially support using a FAT32 partition. In my system, I have 2 (refer to my preference for symmetricity) unencrypted boot partitions that are mirrored (but not in soft raid style) manually.
The next issue is that the bootloader can be programmed to do anything, so that's where you need to put the keyfile. If that keyfile is not password protected, it's super easy. Password protecting it requires some crypto system available at stage-1 boot. So that's why I'm suggesting solution 2, since it makes use of existing luks infrastructure, it works and doesn't change the partitioning layouts, it's just a file that exists in the unencrypted boot partition that can be first unlocked and fed into the rest of the partitions that constitute a zpool or lvm setup.
Hi @CMCDragonkai,
I run into the same problem as you but with another use case: LVM on LUKS on multiple disks. It means that all my LUKS partitions have to be unlock before mounting LVM volume group.
Your solution seems very nice and simpler then the GRUB with crypted /boot option option. So, I am really interested in a PR around the solution 2.
Also, I'm trying to find a workaround by prefixing the key name with "aa" but it do not work. Even if the keyfile device is loaded first I have the same error as you: waiting 10 second...
I used the gist you provide (https://gist.github.com/CMCDragonkai/6456d974982e09d4fe71f339f9029bd3) , but I think I am missing the extra steps describe at the end of it:
# prepend the CPIO archive to the initial ramdisk
# it will be available at stage-1 boot as /luks-key.img
How do you prepend the CPIO archive to the initial ramdisk?
Here is my config just in case:
boot.initrd.luks.devices =
let
luks_key_name = "aa-luks-key-encrypted";
luks_key = "/dev/mapper/${luks_key_name}";
in
[
{
name = luks_key_name;
device = "/luks-key.img";
}
{
name = "root";
device = "/dev/disk/by-uuid/c3a6ae03-368b-4877-b8a3-9d02c0a64d47";
keyFile = luks_key;
preLVM = true;
allowDiscards = true;
}
{
name = "home";
device = "/dev/disk/by-uuid/edea857a-8e93-4eaf-b7cd-e94b753cd573";
keyFile = luks_key;
preLVM = true;
allowDiscards = true;
}
];
@CMCDragonkai @mickours you might be able to do something like this:
boot.initrd.luks.devices = [
{
name = "root";
device = "/dev/disk/by-uuid/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
}
{
name = "crypto_zfs_00";
device = "/dev/disk/by-uuid/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
keyFile = "/mnt-root/root/tank.keyfile";
}
{
name = "crypto_zfs_01";
device = "/dev/disk/by-uuid/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
keyFile = "/mnt-root/root/tank.keyfile";
}
];
systemd.generator-packages = [
pkgs.systemd-cryptsetup-generator
];
environment.etc = {
"crypttab" = {
enable = true;
text = ''
crypto_zfs_00 UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /mnt-root/root/tank.keyfile luks
crypto_zfs_01 UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /mnt-root/root/tank.keyfile luks
'';
};
};
I only realised that /mnt-root
was a thing after reading this: https://github.com/NixOS/nixpkgs/pull/29343
What does that systemd generator package do?
@CMCDragonkai it automatically creates unit files from the entries it sees in /etc/crypttab
: https://www.freedesktop.org/software/systemd/man/systemd-cryptsetup-generator.html
@eqyiel Since you're using tank.keyFile as your keyFile, and I'm assuming the combination of crypttab and systemd-cryptsetup-generator will unlock multiple drives. Where do you store the tank.keyFile in the extra initrd?
boot.initrd.prepend = ["${/crypto_keyfile.cpio.gz}"];
What is inside your .cpio.gz
in order to get a /mnt-root/root/tank.keyfile
working?
BTW I want to move to native zfs encryption anyway.
@CMCDragonkai the root partition is on another drive which gets unlocked with a passphrase. I didn't do anything special to .cpio.gz
.
I don't think this will help if you want your root to be on ZFS though. I don't really remember because it was so long ago now, but you can look at my config here: https://github.com/eqyiel/dotfiles/blob/bbb0b195399e084ff0f70200bd7c47d041ba5bb3/nix/.config/nixpkgs/nixos/config/hoshijiro/configuration.nix#L108-L137 (there's a comment about the pitfalls of cryptsetup-generator
)
May I ask why you are using a key file anyways? In my current Gentoo setup I just use the same passphrase for all LUKS devices (the key is derived from header information anyways) and try to unlock all luks devices with the phrase entered once.
In NixOS that might need changes to the initramfs though, but apart from that I see no real downside to your approach.
Since #29441 we have the password reuse feature. I think this should be enough to solve this issue. Using an extra keyfile, depending on its location, doesn't really change any security properties because both the passphrase and key eventually unlock a master key that's stored encrypted in the LUKS header.
Feel free to reopen if you disagree though.
For those looking for a solution in 2021 (this is one of the first results searching for similar terms), a key file can be included in the initrd using boot.initrd.secrets
. This might look something like
{
boot.initrd.luks.devices.root = {
device = "...";
preLVM = true;
allowDiscards = true;
keyFile = "/crypto_keyfile.bin";
};
boot.initrd.secrets = {
"/crypto_keyfile.bin" = "/boot/initrd/crypto_keyfile.bin";
};
}
And, while writing this comment, I found this gist which basically does the same thing.
This issue has been mentioned on NixOS Discourse. There might be relevant details there:
One of the ways to achieve a single password unlock for multiple LUKs encrypted drives is to use a randomly generated keyfile, which is set as a key for each encrypted drive, then encrypt the key itself into an image file, that has to unlocked and mounted prior to unlocking all subsequent drives at stage-1 boot.
I achieved this before using
boot.initrd.luks.devices
with the first submodule set to keyfile image, and subsequent submoduleskeyFile
parameter set to the mounted unlocked keyfile.Since I have upgraded to release-17.03, it still works, but I'm seeing some weird messages on the stage 1 console.
Here is the relevant configuration:
Has something changed in the stage 1 luks booting script so that the device list gets unlocked out of order?
Previously stage 1 will first try to unlock the first submodule, and only then try the next devices, but if there's the
Waiting 10 seconds...
messages, then that seems like it's trying the other devices before finding my keyfile device.I am also perplexed by the
killall: cryptsetup: no process killed
message.