From eed20cf2d6eeb6644dbd9b9c89a66225586e3f6c Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 18 Apr 2024 14:35:45 -0400 Subject: [PATCH] install: tpm2-luks: Do not bind to any PCRs with cryptenroll The default binding to PCR7 just causes problems without adding much value in reality. With a generic OS/distribution being installed (i.e. no custom Secure Boot chain) a malicious actor who managers to get access to a disk outside of a machine can usually arrange to boot using the same PCR7 state. The problem it causes is it creates a hard version locking requirement between the host system running `bootc install` and the target OS. A related, but opposite problem in a way is that today we don't update shim by default, except when opted-in via `bootupctl update`; to do so while doing PCR 7 locking will require e.g. bootupd to learn how to re-enroll with new shim's PCR7 state. Signed-off-by: Colin Walters --- .github/workflows/ci.yml | 26 +++++++++++++++++++++++++ docs/src/man-md/bootc-install-config.md | 16 +++++++++++++++ lib/src/install/baseline.rs | 20 ++++++++++++++++--- tests/50-enable-tpm2-luks.toml | 2 ++ 4 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 tests/50-enable-tpm2-luks.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9f8d4466..828e73d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -187,3 +187,29 @@ jobs: truncate -s 20G ${tmpdisk} sudo podman run --rm -ti --privileged --env RUST_LOG=debug -v /dev:/dev -v /:/target -v /var/lib/containers:/var/lib/containers -v ./usr/bin/bootc:/usr/bin/bootc --pid=host --security-opt label=disable \ -v ${tmpdisk}:/disk ${image} bootc install to-disk --via-loopback /disk + install-tpm2-luks: + name: "Test install to-disk --via-loopback tpm2-luks" + needs: [build-c9s] + runs-on: ubuntu-latest + steps: + - name: Download + uses: actions/download-artifact@v4 + with: + name: bootc-c9s.tar.zst + - name: Install + run: tar -xvf bootc.tar.zst + - name: Checkout repository + uses: actions/checkout@v4 + - name: Integration tests + run: | + set -xeuo pipefail + cat > Containerfile << 'EOF' + FROM quay.io/centos-bootc/centos-bootc-dev:stream9 + COPY tests/50-enable-tpm2-luks.toml /usr/lib/bootc/install + EOF + image=localhost/test + sudo podman build -t "${image}" . + tmpdisk=$(mktemp -p /var/tmp) + truncate -s 20G ${tmpdisk} + sudo podman run --rm -ti --privileged --env RUST_LOG=debug -v /dev:/dev -v /:/target -v /var/lib/containers:/var/lib/containers -v ./usr/bin/bootc:/usr/bin/bootc --pid=host --security-opt label=disable \ + -v ${tmpdisk}:/disk ${image} bootc install to-disk --block-setup tpm2-luks --via-loopback /disk diff --git a/docs/src/man-md/bootc-install-config.md b/docs/src/man-md/bootc-install-config.md index 9fd4e515..50a6d97d 100644 --- a/docs/src/man-md/bootc-install-config.md +++ b/docs/src/man-md/bootc-install-config.md @@ -26,6 +26,22 @@ The `install`` section supports two subfields: - `filesystem`: See below. - `kargs`: An array of strings; this will be appended to the set of kernel arguments. +## block: direct + +This configuration will use a "plain" layout with the default filesystem configured +in the image for `/`, alongside a separate `/boot` partition and other platform +state such as an EFI System Partition (if applicable), etc. + +## block: tpm2-luks + +Bind unlock of filesystem to presence of the default TPM2 device. +This is implemented using a hardcoded invocation of `systemd-cryptenroll` +that does not do any PCR binding, and does not enable a password or recovery +key. This is suitable as a basic default for for e.g. headless cloud environments. +More sophisticated use cases will currently most likely want to use `bootc install to-filesystem` +and explicitly invoke `systemd-cryptenroll` or other tools to set up +the desired encryption state. + # filesystem There is one valid field: diff --git a/lib/src/install/baseline.rs b/lib/src/install/baseline.rs index 2b01f71b..c8279514 100644 --- a/lib/src/install/baseline.rs +++ b/lib/src/install/baseline.rs @@ -77,8 +77,17 @@ pub(crate) struct InstallBlockDeviceOpts { /// Target root block device setup. /// - /// direct: Filesystem written directly to block device - /// tpm2-luks: Bind unlock of filesystem to presence of the default tpm2 device. + /// - direct: Filesystem written directly to block device + /// - tpm2-luks: Bind unlock of filesystem to presence of the default TPM2 device. + /// This is implemented using a hardcoded invocation of `systemd-cryptenroll` + /// that does not do any PCR binding, and does not enable a password or recovery + /// key. Effectively this just guards the encryption state to the disk being "physically" + /// connected to the same machine. This is a very simple model + /// that can serve as a basic default for for e.g. headless cloud environments. + /// More sophisticated use cases will most likely want to use `bootc install to-filesystem` + /// and explicitly invoke `systemd-cryptenroll` or other tools to set up + /// the desired encryption state. + /// #[clap(long, value_enum)] pub(crate) block_setup: Option, @@ -336,7 +345,12 @@ pub(crate) fn install_create_rootfs( .run()?; // The --wipe-slot=all removes our temporary passphrase, and binds to the local TPM device. Task::new("Enrolling root device with TPM", "systemd-cryptenroll") - .args(["--wipe-slot=all", "--tpm2-device=auto", "--unlock-key-file"]) + .args([ + "--wipe-slot=all", + "--tpm2-pcrs=", + "--tpm2-device=auto", + "--unlock-key-file", + ]) .args([tmp_keyfile]) .args([base_rootdev.as_str()]) .run_with_stdin_buf(dummy_passphrase_input)?; diff --git a/tests/50-enable-tpm2-luks.toml b/tests/50-enable-tpm2-luks.toml new file mode 100644 index 00000000..38e22b8d --- /dev/null +++ b/tests/50-enable-tpm2-luks.toml @@ -0,0 +1,2 @@ +[install] +block = ["direct", "tpm2-luks"]