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

*: add LUKS #960

Merged
merged 3 commits into from
Jul 10, 2020
Merged

*: add LUKS #960

merged 3 commits into from
Jul 10, 2020

Conversation

arithx
Copy link
Contributor

@arithx arithx commented Apr 8, 2020

Still will need some coordination with ignition-dracut to re-open said devices (both on first-boot before Ignition files & on subsequent boots).

Additionally needs a udev rule similar to https://github.com/lucab/bootengine/blob/40a7918874ced2a6a4008dcab556f1eba61309a3/dracut/99cryptsetup/99-xx-coreos-systemd-cryptsetup.rules as systemd ignores unformatted crypto devices.

@cgwalters
Copy link
Member

cgwalters commented Apr 9, 2020

Still will need some coordination with ignition-dracut to re-open said devices (both on first-boot before Ignition files & on subsequent boots).

We could have this inject kernel arguments right? Then we can reuse the standard dracut crypt module.

Basically we just inject the usual root=UUID=<uuid of new rootfs> rd.luks=1 rd.luks.uuid=<uuid of crypt blockdev>.

Though of course this links together Ignition with dracut, but right now ignition-dracut is a separate project. But I don't know of any Ignition users that aren't using dracut today, and in the end any true successor is probably going to need to parse at least a subset of the same kernel arguments anyways to gain adoption.

@cgwalters
Copy link
Member

@cgwalters
Copy link
Member

Though of course this links together Ignition with dracut, but right now ignition-dracut is a separate project

Does anyone oppose merging ignition-dracut into ignition? Today it's pretty weird because the other projects we maintain like ostree and afterburn have them merged, and we really want to be able to do things like "add an ignition stage" as an atomic commit. Plus, in this PR I don't see how to avoid at least somewhat tying Ignition rootfs reprovisioning into dracut logic.

@darkmuggle
Copy link
Contributor

Though of course this links together Ignition with dracut, but right now ignition-dracut is a separate project

Does anyone oppose merging ignition-dracut into ignition? Today it's pretty weird because the other projects we maintain like ostree and afterburn have them merged, and we really want to be able to do things like "add an ignition stage" as an atomic commit. Plus, in this PR I don't see how to avoid at least somewhat tying Ignition rootfs reprovisioning into dracut logic

I am a strong advocate of this idea.

@jlebon
Copy link
Member

jlebon commented Apr 17, 2020

Does anyone oppose merging ignition-dracut into ignition?

This came up a few times already: coreos/fedora-coreos-config#70 (comment). We just didn't have the cycles at the time to weed out the few remaining CoreOS-specific bits from the repo. (To be clear: I do still think this is where we should be heading.)

Copy link
Contributor

@darkmuggle darkmuggle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if I'm following this right, then design is:

  1. Ignition setups the LUKS volumes
  2. The opening will rely on Clevis-Dracut and Dracut to do the opening? Or is there another Ignition-Dracut piece?

Overall this looks goods. I'm just unclear of the mechanics of how the volume gets opened.

internal/exec/stages/disks/luks.go Show resolved Hide resolved
@arithx
Copy link
Contributor Author

arithx commented May 29, 2020

  1. Ignition setups the LUKS volumes
  2. The opening will rely on Clevis-Dracut and Dracut to do the opening? Or is there another Ignition-Dracut piece?

The initramfs on first boot works like so:

  1. Ignition Disks creates the LUKS volumes, formats them, and closes the volumes.
  2. Igniton Mount re-opens the devices (when we have OSTree logic for moving root devices there will be a separate dracut unit that will handle unlocking it and it will stay unlocked).
  3. Ignition Files runs (it writes entries for each LUKS device to /etc/crypttab)
  4. Ignition Umount closes the LUKS devices after umounts.

Inside of the real root non-root devices will be unlocked by clevis-systemd & dm-crypt based on entries in /etc/crypttab.

Inside of the initramfs on subsequent boots the real root will be unlocked before sysroot is mounted. Only clevis devices would really make sense here (as non-clevis would imply that we're storing a key-file in non-encrypted /boot).

@darkmuggle
Copy link
Contributor

darkmuggle commented May 29, 2020

Inside of the real root non-root devices will be unlocked by clevis-systemd & dm-crypt based on entries in /etc/crypttab.

Inside of the initramfs on subsequent boots the real root will be unlocked before sysroot is mounted. Only clevis devices would really make sense here (as non-clevis would imply that we're storing a key-file in non-encrypted /boot).

Okay, that's what I was afraid of. I think we need to be very explicit about the Clevis path here.

clevis-dracut uses the initique:

    inst_hook initqueue/online 60 "$moddir/clevis-hook.sh"                      
    inst_hook initqueue/settled 60 "$moddir/clevis-hook.sh" 

So the boot path is:

  • Ignition Disks writes an /etc/crypttab
  • https://www.freedesktop.org/software/systemd/man/systemd-cryptsetup-generator.html creates a the udev rules for prompting on the console for a passphrase. We need to make sure that systemcd-cryptsetup-generator runs after Igniton Disks (or at least have Ignition Disks run it)
  • The hook then runs /usr/libexec/clevis-luks-askpass in an infinite loop waiting for either a Clevis Pin to unlock (network or TPM2) or a passphrase.

So that means that we are going to implicitly allow user-input on boot. During the RHCOS implementation of LUKs, the group decided that this path was not desirable. I'm not saying that its not the path that we should take, just making the point. My concern to this point is that the failure of LUKS to open will have users asking "what is the passphrase?" (And why the RHCOS implementation just used its own util to open up the device.

I think that we'll need to make sure that ignition-disks.service runs before cryptsetup-pre.target and before the dracut-iniqueue.service in order to avoid racing conditions for /sysroot rewrites (when we get there).

@arithx
Copy link
Contributor Author

arithx commented May 29, 2020

From OOB discussions it sounds like the plan going forward for real root clevis based unlocks will be something like:

  1. drop clevis-systemd
  2. make sure that we're not writing udev rules requiring user input automatically
  3. write a real root systemd generator that looks for entries in /etc/crypttab that are in the form of %name UUID=%UUID none luks (this format implies they are clevis based devices) which will run clevis luks unlock

Some additional clarifications about /sysroot unlocks that came up in the OOB discussion:

First boot, there will likely be a new unit in ignition-dracut that runs sandwiched in between Ignition disks & the new ostree unit that would do the rootfs move.
Subsequent boots will be most likely be done inside of ignition-ostree-mount-sysroot

@cgwalters
Copy link
Member

I don't think in any cases with this we should support prompting for a traditional LUKS passphrase. It basically just doesn't make sense for servers.

The MVP here is binding to a TPM 2 device right? Clevis/Tang/NBDE is definitely a very nice to have too.

@arithx
Copy link
Contributor Author

arithx commented Jun 3, 2020

I don't think in any cases with this we should support prompting for a traditional LUKS passphrase. It basically just doesn't make sense for servers.

Yeah, this implementation won't have any prompting.

The MVP here is binding to a TPM 2 device right? Clevis/Tang/NBDE is definitely a very nice to have too.

The MVP here is key-file based devices & TPM/Tang (via clevis).

Copy link
Member

@cgwalters cgwalters left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall is looking sane! Thanks so much for working on this.

internal/exec/stages/disks/luks.go Outdated Show resolved Hide resolved
internal/exec/stages/disks/luks.go Outdated Show resolved Hide resolved
internal/exec/stages/files/filesystemEntries.go Outdated Show resolved Hide resolved
* **device** (string): the absolute path to the device. Devices are typically referenced by the `/dev/disk/by-*` symlinks.
* **_cipher_** (string): the cipher specification string.
* **_hash_** (string): the hash used in LUKS key setup scheme & volume key digest.
* **_keyFile_** (string): the contents to use as a key file.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably needs some warnings/docs. For the root volume, it really doesn't make sense right? For non-root volumes...hmm, I guess one could store key files in e.g. /etc/luks/$volumename or so, i.e. unlocking subsequent volumes is bound to the rootfs binding. That could be nicer than binding each volume to the tpm2 maybe in that if e.g. one chooses to later add a passphrase in addition to the tpm2 binding to allow moving the disk later, one would only need to do it for the root?

(There may be a "how to use keyfiles well" doc upstream but I didn't see one in a brief search)

@arithx arithx force-pushed the luks branch 5 times, most recently from cdd77ce to 9402c81 Compare June 10, 2020 06:14
@arithx arithx marked this pull request as ready for review June 10, 2020 06:18
@arithx
Copy link
Contributor Author

arithx commented Jun 10, 2020

Ignition LUKS Overview:

PR Links:
Ignition
Ignition-Dracut
fedora-coreos-config

Ignition now supports configuring LUKS devices that can be unlocked via either key-files, TPM2, or tang. TPM2 & tang based devices are handled internally via clevis while key-file based devices are entirely handled via cryptsetup.

First boot workflow:

  1. Ignition Disks creates LUKS devices
    • Every device has a key-file, if one was not provided to Ignition then one will be created (NOTE: this can only happen for clevis based devices). If the key-file was created via Ignition it will be removed, provided key-files will be persisted to the real root at /etc/luks/<device_name>
    • Devices are closed when the Disks stage ends
  2. A new script ignition-copy-keyfiles runs copying the key-files to the real root
  3. Ignition Mount unlocks all LUKS devices before attempting mounts
  4. Ignition Files runs, appends content based on LUKS devices into /etc/crypttab (for key-file based devices) & /etc/clevistab (for clevis based devices).
    • /etc/crypttab format: <name> UUID=<device_uuid> <key_file_path> luks
    • /etc/clevistab format: <name> UUID=<device_uuid> <is_net>, if <is_net> is _netdev then the resulting unlock unit will be generated targeting running before remote-cryptsetup.target instead of the default cryptsetup.target (NOTE: the mount unit for the filesystem will also need to contain Before=remote-fs.target, After=network-online.target and DefaultDependencies=no)
  5. Ignition Umount runs and closes LUKS devices after unmounting filesystems

This set of changes will require updates to the Ignition specfile. In the ignition-dracut change set the ignition-firstboot-complete unit has it's directory moved (from systemd/ to systemd/system/) and a new generator unit ignition-clevis-generator (in systemd/system-generators/). Example change from my local setup:

%files
%license LICENSE LICENSE.dracut
%doc README.md doc/
%{dracutlibdir}/modules.d/*
%{_prefix}/lib/systemd/system/*.service
%{_prefix}/lib/systemd/system-generators/*

&

%install
# ignition-dracut
install -d -p %{buildroot}/%{dracutlibdir}/modules.d
install -d -p %{buildroot}/%{_prefix}/lib/systemd/system
install -d -p %{buildroot}/%{_prefix}/lib/systemd/system-generators
pushd %{dracutrepo}-%{dracutcommit} >/dev/null
cp -r dracut/* %{buildroot}/%{dracutlibdir}/modules.d/
install -m 0644 -t %{buildroot}/%{_prefix}/lib/systemd/system/ systemd/system/*
install -m 0755 -t %{buildroot}/%{_prefix}/lib/systemd/system-generators/ systemd/system-generators/*
popd >/dev/null

@arithx
Copy link
Contributor Author

arithx commented Jun 10, 2020

Updates pushed, marked ready for review.

@arithx
Copy link
Contributor Author

arithx commented Jul 8, 2020

Yeah, I think all testing should probably be in kola to avoid having to require a ton of crypto binaries on the blackbox host and we'll be blocked until either 3.2 stabilizes or we land experiemental Ignition versions into kola.

Copy link
Contributor

@bgilbert bgilbert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

doc/configuration-v3_2_experimental.md Outdated Show resolved Hide resolved
doc/configuration-v3_2_experimental.md Outdated Show resolved Hide resolved
doc/configuration-v3_2_experimental.md Outdated Show resolved Hide resolved
doc/configuration-v3_2_experimental.md Outdated Show resolved Hide resolved
config/v3_2_experimental/schema/ignition.json Outdated Show resolved Hide resolved
config/v3_2_experimental/schema/ignition.json Outdated Show resolved Hide resolved
config/v3_2_experimental/schema/ignition.json Outdated Show resolved Hide resolved
doc/configuration-v3_2_experimental.md Outdated Show resolved Hide resolved
doc/configuration-v3_2_experimental.md Outdated Show resolved Hide resolved
Copy link
Contributor Author

@arithx arithx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update pushed.

config/v3_2_experimental/schema/ignition.json Outdated Show resolved Hide resolved
internal/exec/stages/disks/luks.go Show resolved Hide resolved
args = append(args, luks.Device)

if _, err := s.Logger.LogCmd(
exec.Command(distro.CryptsetupCmd(), args...),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, at the moment it does not re-use devices. My thought was to add that in a follow-up.

For keyfile based devices it should be pretty simple to unlock the device and check it, would need to dive further in for clevis based devices.

doc/configuration-v3_2_experimental.md Outdated Show resolved Hide resolved
config/v3_2_experimental/types/luks.go Outdated Show resolved Hide resolved
doc/configuration-v3_2_experimental.md Outdated Show resolved Hide resolved
doc/configuration-v3_2_experimental.md Outdated Show resolved Hide resolved
internal/distro/distro.go Outdated Show resolved Hide resolved
internal/exec/stages/disks/luks.go Show resolved Hide resolved
internal/exec/stages/disks/luks.go Outdated Show resolved Hide resolved
internal/exec/stages/disks/luks.go Show resolved Hide resolved
internal/exec/stages/disks/luks.go Outdated Show resolved Hide resolved
config/v3_2_experimental/types/luks.go Outdated Show resolved Hide resolved
internal/exec/stages/files/filesystemEntries.go Outdated Show resolved Hide resolved
@arithx
Copy link
Contributor Author

arithx commented Jul 10, 2020

Updated!

config/shared/errors/errors.go Outdated Show resolved Hide resolved
Copy link
Member

@jlebon jlebon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, nice work!

@@ -2,6 +2,12 @@ package types

// generated by "schematyper --package=types config/v3_2_experimental/schema/ignition.json -o config/v3_2_experimental/types/schema.go --root-type=Config" -- DO NOT EDIT

type Clevis struct {
Tang []Tang `json:"tang,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not block on this, but I think fetch-offline should probably also check whether any Tang pins are present and SignalNeedNet() in that case. We can do that in a follow-up though!

Hmm, and then the rootmap code could also check if LUKS devices in the root block device tree are Tang-pinned and adds rd.neednet=1 to the BLS for subsequent boots.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, yeah, forgot about fetch-offline.

@arithx arithx merged commit ff94f87 into coreos:master Jul 10, 2020
jlebon added a commit to jlebon/coreos-assembler that referenced this pull request Jul 13, 2020
The `platform.Conf` type allows abstracting over the different Ignition
versions so that different tests can use different versions. Using it
instead of the Ignition type directly means that we can now use the
3.2-experimental spec in external tests.

This is needed for testing the new LUKS support in Ignition[1] and the
related rootfs-on-complex-devices work[2].

[1] coreos/ignition#960
[2] coreos/fedora-coreos-config#503
jlebon added a commit to jlebon/coreos-assembler that referenced this pull request Jul 13, 2020
The `platform.Conf` type allows abstracting over the different Ignition
versions so that different tests can use different versions. Using it
instead of the Ignition type directly means that we can now use the
3.2-experimental spec in external tests.

This is needed for testing the new LUKS support in Ignition[1] and the
related rootfs-on-complex-devices work[2].

[1] coreos/ignition#960
[2] coreos/fedora-coreos-config#503

Closes: coreos#1589
jlebon added a commit to jlebon/coreos-assembler that referenced this pull request Jul 13, 2020
The `platform.Conf` type allows abstracting over the different Ignition
versions so that different tests can use different versions. Using it
instead of the Ignition type directly means that we can now use the
3.2-experimental spec in external tests.

This is needed for testing the new LUKS support in Ignition[1] and the
related rootfs-on-complex-devices work[2].

[1] coreos/ignition#960
[2] coreos/fedora-coreos-config#503

Closes: coreos#1589
jlebon added a commit to jlebon/coreos-assembler that referenced this pull request Jul 17, 2020
The `platform.Conf` type allows abstracting over the different Ignition
versions so that different tests can use different versions. Using it
instead of the Ignition type directly means that we can now use the
3.2-experimental spec in external tests.

This is needed for testing the new LUKS support in Ignition[1] and the
related rootfs-on-complex-devices work[2].

[1] coreos/ignition#960
[2] coreos/fedora-coreos-config#503

Closes: coreos#1589
jlebon added a commit to jlebon/coreos-assembler that referenced this pull request Jul 18, 2020
The `platform.Conf` type allows abstracting over the different Ignition
versions so that different tests can use different versions. Using it
instead of the Ignition type directly means that we can now use the
3.2-experimental spec in external tests.

This is needed for testing the new LUKS support in Ignition[1] and the
related rootfs-on-complex-devices work[2].

[1] coreos/ignition#960
[2] coreos/fedora-coreos-config#503

Closes: coreos#1589
openshift-merge-robot pushed a commit to coreos/coreos-assembler that referenced this pull request Jul 20, 2020
The `platform.Conf` type allows abstracting over the different Ignition
versions so that different tests can use different versions. Using it
instead of the Ignition type directly means that we can now use the
3.2-experimental spec in external tests.

This is needed for testing the new LUKS support in Ignition[1] and the
related rootfs-on-complex-devices work[2].

[1] coreos/ignition#960
[2] coreos/fedora-coreos-config#503

Closes: #1589
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants