From 29dfe047f78499a03990dcbfc7f711c1b6ecb35d Mon Sep 17 00:00:00 2001 From: Someone Date: Fri, 4 Oct 2024 13:42:33 +0200 Subject: [PATCH] [roles/base/cryptsetup-helper] setup cryptsetup helpers --- .../base/cryptsetup-helper/defaults/main.yml | 12 + roles/base/cryptsetup-helper/files/cryptroot | 260 ++++++++++++++++++ .../files/systemd-cryptsetup@DEVICE.service | 31 +++ .../base/cryptsetup-helper/handlers/main.yml | 10 + roles/base/cryptsetup-helper/tasks/main.yml | 43 +++ 5 files changed, 356 insertions(+) create mode 100644 roles/base/cryptsetup-helper/defaults/main.yml create mode 100644 roles/base/cryptsetup-helper/files/cryptroot create mode 100644 roles/base/cryptsetup-helper/files/systemd-cryptsetup@DEVICE.service create mode 100644 roles/base/cryptsetup-helper/handlers/main.yml create mode 100644 roles/base/cryptsetup-helper/tasks/main.yml diff --git a/roles/base/cryptsetup-helper/defaults/main.yml b/roles/base/cryptsetup-helper/defaults/main.yml new file mode 100644 index 0000000..140f06b --- /dev/null +++ b/roles/base/cryptsetup-helper/defaults/main.yml @@ -0,0 +1,12 @@ +##################################### +### someone's ansible provisioner ### +##################################### +# Part of: https://git.somenet.org/root/pub/somesible.git +# 2017-2024 by someone +# +# If not overridden in inventory or as a parameter, this is the value that will be used +# +--- +# define to enable. +#cryptsetup_devices: +# - "/dev/mapper/md1_crypt" diff --git a/roles/base/cryptsetup-helper/files/cryptroot b/roles/base/cryptsetup-helper/files/cryptroot new file mode 100644 index 0000000..e56221d --- /dev/null +++ b/roles/base/cryptsetup-helper/files/cryptroot @@ -0,0 +1,260 @@ +#!/bin/sh +# +################################################ +### Managed by someone's ansible provisioner ### +################################################ +# Part of: https://git.somenet.org/root/pub/somesible.git +# 2017-2024 by someone +# + +PREREQ="cryptroot-prepare" + +# +# Standard initramfs preamble +# +prereqs() +{ + # Make sure that cryptroot is run last in local-top + local req + for req in "${0%/*}"/*; do + script="${req##*/}" + if [ "$script" != "${0##*/}" ]; then + printf '%s\n' "$script" + fi + done +} + +case $1 in +prereqs) + prereqs + exit 0 + ;; +esac + +. /scripts/functions + +[ -f /lib/cryptsetup/functions ] || return 0 +. /lib/cryptsetup/functions + + +# wait_for_source() +# Wait for encrypted $CRYPTTAB_SOURCE . Set $CRYPTTAB_SOURCE +# to its normalized device name when it shows up; +# return 1 if timeout. +wait_for_source() { + wait_for_udev 10 + + if crypttab_resolve_source; then + # the device is here already, no need to loop + return 0 + fi + + # If the source device hasn't shown up yet, give it a little while + # to allow for asynchronous device discovery (e.g. USB). + # + # We also need to take into account RAID or other devices that may + # only be available on local-block stage. So, wait 5 seconds upfront, + # in local-top; if that fails, end execution relying on local-block + # invocations. Allow $ROOTDELAY/4 invocations with 1s sleep times (with + # a minimum of 20 invocations), and if after that we still fail, then it's + # really time to give-up. Variable $initrd_cnt tracks the re-invocations. + # + # Part of the lines below has been taken from initramfs-tools + # scripts/local's local_device_setup(), as suggested per + # https://launchpad.net/bugs/164044 . + + local slumber=5 + if [ "${CRYPTROOT_STAGE-}" = "local-block" ]; then + slumber=1 + fi + + cryptsetup_message "Waiting for encrypted source device $CRYPTTAB_SOURCE..." + + while [ $slumber -gt 0 ]; do + sleep 1 + + if crypttab_resolve_source; then + wait_for_udev 10 + return 0 + fi + + slumber=$(( $slumber - 1 )) + done + return 1 +} + +# setup_mapping() +# Set up a crypttab(5) mapping defined by $CRYPTTAB_NAME, +# $CRYPTTAB_SOURCE, $CRYPTTAB_KEY, $CRYPTTAB_OPTIONS. +setup_mapping() { + local dev initrd_cnt + + # We control here the number of re-invocations of this script from + # local-block - the heuristic is $ROOTDELAY/4, with a minimum of 20. + + if [ -f "$CRYPTROOT_COUNT_FILE" ]; then + initrd_cnt="$(cat <"$CRYPTROOT_COUNT_FILE")" + else + initrd_cnt="${ROOTDELAY:-180}" + initrd_cnt=$(( initrd_cnt/4 )) + if [ $initrd_cnt -lt 20 ]; then + initrd_cnt=20 + fi + echo "$initrd_cnt" >"$CRYPTROOT_COUNT_FILE" + fi + + # The same target can be specified multiple times + # e.g. root and resume lvs-on-lvm-on-crypto + if dm_blkdevname "$CRYPTTAB_NAME" >/dev/null; then + return 0 + fi + + crypttab_parse_options --export --missing-path=fail || return 1 + + if ! wait_for_source; then + if [ $initrd_cnt -eq 0 ]; then + # we've given up + if [ -n "$panic" ]; then + panic "ALERT! encrypted source device $CRYPTTAB_SOURCE does not exist, can't unlock $CRYPTTAB_NAME." + else + # let the user fix matters if they can + echo " ALERT! encrypted source device $CRYPTTAB_SOURCE does not exist, can't unlock $CRYPTTAB_NAME." + echo " Check cryptopts=source= bootarg: cat /proc/cmdline" + echo " or missing modules, devices: cat /proc/modules; ls /dev" + panic "Dropping to a shell." + fi + return 1 # can't continue because environment is lost + else + initrd_cnt=$(( initrd_cnt - 1 )) + echo "$initrd_cnt" >"$CRYPTROOT_COUNT_FILE" + return 0 # allow some attempts on local-block stage + fi + fi + + # our `cryptroot-unlock` script searches for cryptsetup processes + # with a given CRYPTTAB_NAME it their environment + export CRYPTTAB_NAME + + if [ -z "${CRYPTTAB_OPTION_keyscript+x}" ]; then + # no keyscript: interactive unlocking, or key file + + if [ "${CRYPTTAB_KEY#/FIXME-initramfs-rootmnt/}" != "$CRYPTTAB_KEY" ]; then + # skip the mapping for now if the root FS is not mounted yet + sed -rn 's/^\s*[^#[:blank:]]\S*\s+(\S+)\s.*/\1/p' /proc/mounts | grep -Fxq -- "$rootmnt" || return 1 + # substitute the "/FIXME-initramfs-rootmnt/" prefix by the real root FS mountpoint otherwise + CRYPTTAB_KEY="$rootmnt/${CRYPTTAB_KEY#/FIXME-initramfs-rootmnt/}" + fi + + if [ "$CRYPTTAB_KEY" != "none" ]; then + if [ ! -e "$CRYPTTAB_KEY" ]; then + cryptsetup_message "ERROR: Skipping target $CRYPTTAB_NAME: non-existing key file $CRYPTTAB_KEY" + return 1 + fi + # try only once if we have a key file + CRYPTTAB_OPTION_tries=1 + fi + fi + + local count=0 maxtries="${CRYPTTAB_OPTION_tries:-3}" fstype vg rv + while [ $maxtries -le 0 ] || [ $count -lt $maxtries ]; do + if [ -z "${CRYPTTAB_OPTION_keyscript+x}" ] && [ "$CRYPTTAB_KEY" != "none" ]; then + # unlock via keyfile + unlock_mapping "$CRYPTTAB_KEY" + # added by + urv=$? + if [ $urv -ne 0 ]; then + cryptsetup_message "ERROR: Failed to unlock $CRYPTTAB_NAME with $CRYPTTAB_KEY" + /lib/cryptsetup/askpass "Try interactively. Passphrase: " | unlock_mapping + fi + # / added by + else + # unlock interactively or via keyscript + run_keyscript "$count" | unlock_mapping + # added by + urv=$? + if [ $urv -ne 0 ]; then + cryptsetup_message "ERROR: Failed to unlock $CRYPTTAB_NAME with $CRYPTTAB_KEY" + /lib/cryptsetup/askpass "Try interactively. Passphrase: " | unlock_mapping + fi + # / added by + fi + rv=$? + count=$(( $count + 1 )) + + if [ $rv -ne 0 ]; then + cryptsetup_message "ERROR: $CRYPTTAB_NAME: cryptsetup failed, bad password or options?" + sleep 1 + continue + elif ! dev="$(dm_blkdevname "$CRYPTTAB_NAME")"; then + cryptsetup_message "ERROR: $CRYPTTAB_NAME: unknown error setting up device mapping" + return 1 + fi + + if ! fstype="$(get_fstype "$dev")" || [ "$fstype" = "unknown" ]; then + if [ "$CRYPTTAB_TYPE" != "luks" ]; then + # bad password for plain dm-crypt device? or mkfs not run yet? + cryptsetup_message "ERROR: $CRYPTTAB_NAME: unknown fstype, bad password or options?" + wait_for_udev 10 + /sbin/cryptsetup remove -- "$CRYPTTAB_NAME" + sleep 1 + continue + fi + fi + + cryptsetup_message "$CRYPTTAB_NAME: set up successfully" + wait_for_udev 10 + return 0 + done + + cryptsetup_message "ERROR: $CRYPTTAB_NAME: maximum number of tries exceeded" + exit 1 +} + + +####################################################################### +# Begin real processing + +mkdir -p /cryptroot # might not exist yet if the main system has no crypttab(5) + +# Do we have any kernel boot arguments? +if ! grep -qE '^(.*\s)?cryptopts=' /proc/cmdline; then + # ensure $TABFILE exists and has a mtime greater than the boot time + # (existing $TABFILE is preserved) + touch -- "$TABFILE" +else + # let the read builtin unescape the '\' as GRUB substitutes '\' by '\\' in the cmdline + tr ' ' '\n' "$TABFILE" +fi + +# Do we have any settings from the $TABFILE? +if [ -s "$TABFILE" ]; then + # Create locking directory before invoking cryptsetup(8) to avoid warnings + mkdir -pm0700 /run/cryptsetup + modprobe -q dm_crypt + + crypttab_foreach_entry setup_mapping +fi + +exit 0 diff --git a/roles/base/cryptsetup-helper/files/systemd-cryptsetup@DEVICE.service b/roles/base/cryptsetup-helper/files/systemd-cryptsetup@DEVICE.service new file mode 100644 index 0000000..f326bc7 --- /dev/null +++ b/roles/base/cryptsetup-helper/files/systemd-cryptsetup@DEVICE.service @@ -0,0 +1,31 @@ +# +################################################ +### Managed by someone's ansible provisioner ### +################################################ +# Part of: https://git.somenet.org/root/pub/somesible.git +# 2017-2024 by someone +# + +# Automatically generated by systemd-cryptsetup-generator on 2022-09-15 and manually removed too much information. + +[Unit] +Description=Cryptography Setup for %I +Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8) +SourcePath=/etc/crypttab +DefaultDependencies=no +IgnoreOnIsolate=true +After=cryptsetup-pre.target systemd-udevd-kernel.socket +Before=blockdev@dev-mapper-%i.target +Wants=blockdev@dev-mapper-%i.target +Conflicts=umount.target +Before=cryptsetup.target +Before=umount.target + +[Service] +Type=oneshot +RemainAfterExit=yes +TimeoutSec=0 +KeyringMode=shared +OOMScoreAdjust=500 +ExecStart=/bin/true +#ExecStop=/lib/systemd/systemd-cryptsetup detach '..._crypt' diff --git a/roles/base/cryptsetup-helper/handlers/main.yml b/roles/base/cryptsetup-helper/handlers/main.yml new file mode 100644 index 0000000..b7b3da9 --- /dev/null +++ b/roles/base/cryptsetup-helper/handlers/main.yml @@ -0,0 +1,10 @@ +##################################### +### someone's ansible provisioner ### +##################################### +# Part of: https://git.somenet.org/root/pub/somesible.git +# 2017-2024 by someone +# +--- +- name: update-initramfs + command: update-initramfs -uck all + ignore_errors: yes diff --git a/roles/base/cryptsetup-helper/tasks/main.yml b/roles/base/cryptsetup-helper/tasks/main.yml new file mode 100644 index 0000000..b51bacc --- /dev/null +++ b/roles/base/cryptsetup-helper/tasks/main.yml @@ -0,0 +1,43 @@ +##################################### +### someone's ansible provisioner ### +##################################### +# Part of: https://git.somenet.org/root/pub/somesible.git +# 2017-2024 by someone +# +# cryptsetup-helper +# +--- +- name: install cryptsetup tools + apt: + pkg: + - cryptsetup-bin + - cryptsetup-initramfs + - cryptsetup-run + state: present + policy_rc_d: 101 + when: cryptsetup_devices is defined + tags: "online" + ignore_errors: "{{ignore_online_errors | bool}}" + + +- name: silence systemd for all crypt devices + copy: + src: "systemd-cryptsetup@DEVICE.service" + dest: "/etc/systemd/system/systemd-cryptsetup@{{item}}.service" + mode: 0644 + owner: "root" + group: "root" + with_items: + - "{{cryptsetup_devices}}" + when: cryptsetup_devices is defined + + +- name: copy cryptroot-initrd script with askpass fallback + copy: + src: "cryptroot" + dest: "/etc/initramfs-tools/scripts/local-top/cryptroot" + mode: 0755 + owner: "root" + group: "root" + when: cryptsetup_devices is defined + notify: update-initramfs -- 2.43.0