From baeafe294477b62f75faf23d710b2bc7fd70d72f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20L=C3=B6ser?= Date: Tue, 24 Oct 2023 15:08:14 +0200 Subject: [PATCH] Refs #36885 - Add Clevis/Tang disk encryption template For disk encryption Clevis/Tang is often used. This commit introduces a Kickstart partition template taking care of disk encryption and a snippet responsible for binding the LUKS device via Clevis to a given Tang server. The default partition template encrypts the disk with a passphrase which can be provided via `disk_enc_passphrase` host parameter. If no host parameter is provided, the default passphrase is 'linux'. If, in addition, `disk_enc_tang_servers` host parameter is provided (can be one address as string or multiple addresses as array), the LUKS device will be bind to these Tang servers using Clevis. In this case, the passphrase will be removed. This commit targets mainly all operating systems of the Red Hat family, however the snippet can also be used for Ubuntu operating system. --- .../kickstart_default_encrypted.erb | 18 ++++ .../provision/kickstart_default.erb | 2 + .../snippet/disk_enc_clevis_tang.erb | 87 +++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 app/views/unattended/partition_tables_templates/kickstart_default_encrypted.erb create mode 100644 app/views/unattended/provisioning_templates/snippet/disk_enc_clevis_tang.erb diff --git a/app/views/unattended/partition_tables_templates/kickstart_default_encrypted.erb b/app/views/unattended/partition_tables_templates/kickstart_default_encrypted.erb new file mode 100644 index 000000000000..f4a9aafea3af --- /dev/null +++ b/app/views/unattended/partition_tables_templates/kickstart_default_encrypted.erb @@ -0,0 +1,18 @@ +<%# +kind: ptable +name: Kickstart default encrypted +model: Ptable +oses: +- AlmaLinux +- RedHat +- Rocky +-%> +<% if host_param('driverdisk_source') -%> +driverdisk --source=<%= host_param('driverdisk_source') %> +<% end -%> +<% if host_param('ignoredisk_options') %> +ignoredisk <%= host_param('ignoredisk_options') %> +<% end %> +zerombr +clearpart --all --initlabel +autopart --encrypted --passphrase="<%= host_param('disk_enc_passphrase') ? host_param('disk_enc_passphrase') : 'linux' %>" <%= host_param('autopart_options') %> diff --git a/app/views/unattended/provisioning_templates/provision/kickstart_default.erb b/app/views/unattended/provisioning_templates/provision/kickstart_default.erb index c1848ae24cfd..d73215fbd852 100644 --- a/app/views/unattended/provisioning_templates/provision/kickstart_default.erb +++ b/app/views/unattended/provisioning_templates/provision/kickstart_default.erb @@ -360,6 +360,8 @@ sed -e 's/DEFAULTKERNEL=kernel-uek/DEFAULTKERNEL=kernel/g' -i /etc/sysconfig/ker <%= snippet 'insights' if host_param_true?('host_registration_insights') && os_major < 9 -%> +<%= snippet 'disk_enc_clevis_tang' %> + touch /tmp/foreman_built chvt 1 diff --git a/app/views/unattended/provisioning_templates/snippet/disk_enc_clevis_tang.erb b/app/views/unattended/provisioning_templates/snippet/disk_enc_clevis_tang.erb new file mode 100644 index 000000000000..a2d45b7d4e56 --- /dev/null +++ b/app/views/unattended/provisioning_templates/snippet/disk_enc_clevis_tang.erb @@ -0,0 +1,87 @@ +<%# +kind: snippet +name: disk_enc_clevis_tang +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. + The temporary passphrase will be removed afterwards. Currently, only Red Hat + family and Ubuntu operating systems are supported. +-%> +<% + passphrase = host_param('disk_enc_passphrase') || 'linux' + tang_server_list = [] + packages_redhat = "clevis clevis-luks clevis-systemd clevis-dracut" + packages_ubuntu = "clevis clevis-luks clevis-systemd clevis-initramfs" + + unless host_param('disk_enc_tang_servers').blank? + if host_param('disk_enc_tang_servers').is_a?(String) + tang_server_list = [host_param('disk_enc_tang_servers')] + else + tang_server_list = host_param('disk_enc_tang_servers') + end + end +-%> + +<% if (@host.operatingsystem.family == 'Redhat' or @host.operatingsystem.name == 'Ubuntu') and unless tang_server_list.blank? %> + +cat > /tmp/rootdir-luks-device.sh << "EOF" +#!/bin/sh +# +# Author Jan Löser +# Published under the GNU Public Licence 3 +# +# This scripts tries to find the 1st LUKS device for / (root directory). +# +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 + set -e + slave=$(find /sys/class/block/$(basename $slavedev)/slaves -type l | head -n1) + slavedev=$(find /dev -name "$(basename $slave)" | head -n1) + set +e +done + +exit 1 +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" + +<% if @host.operatingsystem.family == 'Redhat' %> + if [ -f /usr/bin/dnf ]; then + dnf -y install <%= packages_redhat %> + else + yum -t -y install <%= packages_redhat %> + fi +<% elsif @host.operatingsystem.name == 'Ubuntu' %> + apt -y install clevis clevis-luks clevis-initramfs clevis-systemd +<% end %> + +<% for tang_server in tang_server_list %> + echo '<%= passphrase %>' | clevis luks bind -y -k - -d $luksdev tang '{"url": "<%= tang_server %>"}' +<% end %> + echo '<%= passphrase %>' | cryptsetup luksRemoveKey $luksdev + systemctl enable clevis-luks-askpass.path + systemctl enable remote-cryptsetup.target + +<% if @host.operatingsystem.family == 'Redhat' %> + dracut --verbose --force --hostonly-cmdline --regenerate-all +<% elsif @host.operatingsystem.name == 'Ubuntu' %> + update-initramfs -u -k 'all' +<% end %> + +else + echo "No LUKS device found!" +fi + +<% end %>