Skip to content

Commit

Permalink
Fixes #36885 - Add Clevis/Tang disk encryption template
Browse files Browse the repository at this point in the history
For disk encryption Clevis/Tang is often used. This commit introduces
partition templates for Kickstart and Autoinstall 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 the Red Hat family and Ubuntu operating system.
  • Loading branch information
Jan Löser authored and sbernhard committed Apr 15, 2024
1 parent 6924b15 commit 98d3bf5
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -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', 'linux') %>" <%= host_param('autopart_options') %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<%#
kind: ptable
name: Preseed default autoinstall encrypted
model: Ptable
description: |
Preseed Autoinstall default storage snippet configures drives automatically
with LVM and disk encryption.
Requires Ubuntu >= 22.04.3.
The snippet is automatically indented by 2 spaces. For reference:
https://ubuntu.com/server/docs/install/autoinstall-reference
oses:
- Ubuntu
%>
storage:
layout:
name: lvm
password: <%= host_param('disk_enc_passphrase', 'linux') %>
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ sed -e 's/DEFAULTKERNEL=kernel-uek/DEFAULTKERNEL=kernel/g' -i /etc/sysconfig/ker
<%= snippet_if_exists(template_name + " custom post") %>
<%= snippet 'insights' if host_param_true?('host_registration_insights') && os_major < 9 -%>
<%= snippet 'disk_enc_clevis_tang' if host_param('disk_enc_tang_servers') -%>

touch /tmp/foreman_built

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<%#
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' || @host.operatingsystem.name == 'Ubuntu') && unless tang_server_list.blank? -%>

cat > /tmp/rootdir-luks-device.sh << "EOF"
#!/bin/sh
#
# Author Jan Löser <loeser@atix.de>
# 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' -%>
$PKG_MANAGER_INSTALL <%= packages_redhat %>
<% elsif @host.operatingsystem.name == 'Ubuntu' -%>
$PKG_MANAGER_INSTALL <%= packages_ubuntu %>
<% end -%>
<% for tang_server in tang_server_list -%>
echo '<%= passphrase %>' | clevis luks bind -y -k - -d $luksdev tang '{"url": "<%= tang_server %>"}'
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
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 -%>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<%#
kind: snippet
name: preseed_autoinstall_clevis_tang_wrapper
model: ProvisioningTemplate
snippet: true
description: |
Wrapper snippet to set up Clevis/Tang disk encryption.
Requires Ubuntu >= 22.04.3.
The snippet is automatically indented by 2 spaces. For reference:
https://ubuntu.com/server/docs/install/autoinstall-reference
%>
- |
cat > /target/tmp/disk_enc_clevis_tang.sh <<"WRAPPER"
#!/bin/sh
<%= indent(2) { snippet 'disk_enc_clevis_tang' } %>
WRAPPER
- curtin in-target -- bash /tmp/disk_enc_clevis_tang.sh
- curtin in-target -- rm /tmp/disk_enc_clevis_tang.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ username_to_create = host_param('username_to_create', 'root')
realname_to_create = host_param('realname_to_create') || username_to_create
password_to_create = host_param('password_to_create') || @host.root_pass
enable_auto_update = (host_param_true?('package_upgrade') && !host_param('kt_activation_keys'))
os_major = @host.operatingsystem.major.to_i
os_minor = @host.operatingsystem.minor.to_i
-%>
#cloud-config
autoinstall:
Expand Down Expand Up @@ -67,9 +69,10 @@ autoinstall:
allow-pw: true
install-server: true
updates: security
<%= indent(2) { @host.diskLayout } -%>
<%= 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 } %>
- 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
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ autoinstall:
storage:
layout:
name: lvm

late-commands:

- wget -Y off http://foreman.example.com/unattended/finish -O /target/tmp/finish.sh
- curtin in-target -- chmod +x /tmp/finish.sh
- curtin in-target -- /tmp/finish.sh

0 comments on commit 98d3bf5

Please sign in to comment.