Skip to content

Commit

Permalink
Fixes #37857 - Tang support multiple phys. volumes
Browse files Browse the repository at this point in the history
Often there is more than a single disk that gets encrypted during
installation. When multiple disks are available and `autopart` is used
in the kickstart config, all disks get encrypted and put into a volume
group on which a logical volume for the root partition is created.
Another example is when users add a separate disk for directories like
/var to separate application data. This means we need to recursively
resolve all underlying encrypted volumes, not just for the
root partition. To identify these, we take all entries from
/etc/crypttab, which should catch all block devices that were
encrypted in the installation process.

As this feature should also work for Ubuntu, we also address some bugs
with the Ubuntu support:
- disk_enc_clevis_tang.erb needs to work with dash (not just bash)
- the check of the minor version in the autoinstall template is broken,
  recommendation is also to not rely on the minor version for this OS
- PKG_MANAGER_INSTALL is missing in preseed_autoinstall_cloud_init.erb
  • Loading branch information
MartinSpiessl committed Nov 5, 2024
1 parent 27d8e28 commit c80f28b
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ model: ProvisioningTemplate
snippet: true
description: |
Binds encrypted root directory ('/') utilizing Clevis to Tang server(s) for
decryption. The first parent device containing a LUKS container will be used.
decryption. All parent devices containing a LUKS container will be used.
The temporary passphrase will be removed afterwards. Currently, only Red Hat
family and Ubuntu operating systems are supported.
-%>
Expand All @@ -27,52 +27,66 @@ description: |
<% if (@host.operatingsystem.family == 'Redhat' || @host.operatingsystem.name == 'Ubuntu') && tang_server_list.present? -%>

cat > /tmp/rootdir-luks-device.sh << "EOF"
#!/bin/sh
#!/bin/bash
#
# Author Jan Löser <loeser@atix.de>
# Published under the GNU Public Licence 3
# SPDX-FileCopyrightText: 2024 Jan Löser <loeser@atix.de>
# SPDX-FileCopyrightText: 2024 Martin Spiessl <spiessl@atix.de>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This scripts tries to find the 1st LUKS device for / (root directory).
# This script tries to find all LUKS devices mounted in /etc/crypttab.
#
set -o pipefail

rootdev=$(df / --output=source | tail -n1)
targetdev=$(readlink -f $rootdev)
slavedev=$targetdev

while : ; do
/sbin/cryptsetup luksDump $slavedev &>/dev/null && echo $slavedev && exit 0
mapfile -t maybe_luks_devices < <(
awk '{print $1}' /etc/crypttab | \
xargs -rn1 find /dev -name | \
xargs -rn1 readlink -f
)
luks_devices=()
while [[ ${#maybe_luks_devices[@]} -gt 0 ]] ; do
# classify maybe_luks_devices into luks_devices and non_luks_devices
non_luks_devices=()
for dev in "${maybe_luks_devices[@]}" ; do
/sbin/cryptsetup luksDump "$dev" &>/dev/null && luks_devices+=("$dev") || non_luks_devices+=("$dev")
done
# resolve non_luks_devices to discover new maybe_luks_devices
set -e
slave=$(find /sys/class/block/$(basename $slavedev)/slaves -type l | head -n1)
slavedev=$(find /dev -name "$(basename $slave)" | head -n1)
maybe_luks_devices=()
for dev in "${non_luks_devices[@]}" ; do
mapfile -t slaves < <(find "/sys/class/block/$(basename "$dev")/slaves" -type l)
for slave in "${slaves[@]}" ; do
slavedev=$(find /dev -name "$(basename "$slave")" | head -n1)
maybe_luks_devices+=("$slavedev")
done
done
set +e
done

exit 1
printf "%s\n" "${luks_devices[@]}"
EOF

# needs bash here because Ubuntu's sh (dash) doesn't support `-o pipefail` option
luksdev=$(bash /tmp/rootdir-luks-device.sh)

if [[ -n "$luksdev" ]]; then
echo "LUKS device found for '/': $luksdev"
luksdevs=$(bash /tmp/rootdir-luks-device.sh)
if [ -n "$luksdevs" ]; then
echo "LUKS devices found for '/': $luksdevs"

<% if @host.operatingsystem.family == 'Redhat' -%>
$PKG_MANAGER_INSTALL <%= packages_redhat %>
<% elsif @host.operatingsystem.name == 'Ubuntu' -%>
$PKG_MANAGER_INSTALL <%= packages_ubuntu %>
<% end -%>

for luksdev in $luksdevs; do
<% for tang_server in tang_server_list -%>
echo '<%= passphrase %>' | clevis luks bind -y -k - -d $luksdev tang '{"url": "<%= tang_server %>"}'
if [[ $? -ne 0 ]]; then
if [ $? -ne 0 ]; then
echo "---"
echo "There was an error during Clevis LUKS bind of '$luksdev' to Tang server '<%= tang_server %>'."
echo "System halted."
sleep infinity
fi
<% end -%>
echo '<%= passphrase %>' | cryptsetup luksRemoveKey $luksdev
done
systemctl enable clevis-luks-askpass.path
systemctl enable remote-cryptsetup.target

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ description: |
- |
cat > /target/tmp/disk_enc_clevis_tang.sh <<"WRAPPER"
#!/bin/sh
<%= indent(2) { snippet 'pkg_manager' } %>
<%= indent(2) { snippet 'disk_enc_clevis_tang' } %>
WRAPPER
- curtin in-target -- bash /tmp/disk_enc_clevis_tang.sh
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ autoinstall:
<%= indent(2) { @host.diskLayout } %>
<%= indent(2) { snippet_if_exists(template_name + " custom root") } -%>
late-commands:
<%= indent(2) { snippet 'preseed_autoinstall_clevis_tang_wrapper' if host_param('disk_enc_tang_servers') && os_major >= 22 && os_minor >= 3 } %>
<%= indent(2) { snippet 'preseed_autoinstall_clevis_tang_wrapper' if host_param('disk_enc_tang_servers') && os_major >= 22 } %>
- wget -Y off <%= @static ? "'#{foreman_url('finish', static: 'true')}'" : foreman_url('finish') %> -O /target/tmp/finish.sh
- curtin in-target -- chmod +x /tmp/finish.sh
- curtin in-target -- /tmp/finish.sh

0 comments on commit c80f28b

Please sign in to comment.