Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:favogt:symbolictw
disk-encryption-tool
disk-encryption-tool-1+git20240826.c956112.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File disk-encryption-tool-1+git20240826.c956112.obscpio of Package disk-encryption-tool
07070100000000000081A400000000000000000000000166CC462400000026000000000000000000000000000000000000003A00000000disk-encryption-tool-1+git20240826.c956112/.dir-locals.el((sh-mode . ((sh-basic-offset . 8)))) 07070100000001000081A400000000000000000000000166CC46240000013B000000000000000000000000000000000000003900000000disk-encryption-tool-1+git20240826.c956112/.editorconfig# EditorConfig configuration for sdbootutil # http://EditorConfig.org # Top-most EditorConfig file root = true # Unix-style newlines with a newline ending every file, utf-8 charset [*] end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true charset = utf-8 indent_style = tab indent_size = 8 07070100000002000041ED00000000000000000000000266CC462400000000000000000000000000000000000000000000003300000000disk-encryption-tool-1+git20240826.c956112/.github07070100000003000041ED00000000000000000000000266CC462400000000000000000000000000000000000000000000003D00000000disk-encryption-tool-1+git20240826.c956112/.github/workflows07070100000004000081A400000000000000000000000166CC46240000026B000000000000000000000000000000000000004600000000disk-encryption-tool-1+git20240826.c956112/.github/workflows/test.ymlname: MicroOS in QEMU on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt update sudo apt install -y qemu-system-x86 ovmf # Normally setfacl -m u:$USER:rw /dev/kvm should work, but for some # reason this only sticks around for a single QEMU run. udev? sudo usermod -a -G kvm "$USER" - name: Test run: | # Needed to activate the new kvm group membership sudo -u "$USER" bash test/test.sh 07070100000005000081A400000000000000000000000166CC46240000042E000000000000000000000000000000000000003300000000disk-encryption-tool-1+git20240826.c956112/LICENSEMIT License Copyright (c) 2023 Ludwig Nussel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 07070100000006000081A400000000000000000000000166CC4624000006DC000000000000000000000000000000000000003500000000disk-encryption-tool-1+git20240826.c956112/README.mdTool to turn a plain text image into one using LUKS full disk encryption. There are three modes: * Directly encrypt a disk image on a host system. The image can then be deployed somewhere else * Prime a disk image by adding code to the initrd of the image that encrypts the image on first boot * Include the initrd code already when building an image. The image would then encrypt itself on first boot. In general the tool is developed with [kiwi](https://github.com/OSInside/kiwi) in mind. It assumes that the image contains a single root fs using btrfs in the third partition. Both grub2 and systemd-boot are supported. The tool generates a Example to directly encrypt an image: disk-encryption-tool -v SLE-Micro.x86_64-5.4.0-Default-GM.raw Example to prime a plain text image to encrypt on first boot: disk-encryption-tool -v --prime SLE-Micro.x86_64-5.4.0-Default-GM.raw When run on first boot the tool integrates with [jeos-firstboot](https://github.com/openSUSE/jeos-firstboot/). The encryption in initrd deploys an automatically generated recovery key, compatible with [systemd-cryptenroll](https://www.freedesktop.org/software/systemd/man/latest/systemd-cryptenroll.html). Later in the real root a jeos-firsboot module then offers to deploy either the root password or another custom passphrase as well. Parameters for cryptsetup-reencrypt(8) can be passed via `/etc/encrypt_options`. One option per line, e.g. --type=luks1 --iter-time=2000 It's also possible to integrate with combustion. The combustion script would have to look like this: #!/bin/bash # combustion: prepare if [ "$1" = "--prepare" ]; then echo 12345 | disk-encryption-tool -v else echo root:12345 | chpasswd fi 07070100000007000081ED00000000000000000000000166CC462400002EC2000000000000000000000000000000000000004000000000disk-encryption-tool-1+git20240826.c956112/disk-encryption-tool#!/bin/bash # SPDX-License-Identifier: MIT # SPDX-FileCopyrightText: Copyright 2023 SUSE LLC set -e shopt -s nullglob unset "${!LC_@}" LANG="C.utf8" export LANG verbose= prime= gen_key= switched_rw= cr_name='cr_root' cr_dev= blkdev= blkpart= partno= mp= mounted= tmpdir=$(mktemp -d -t disk-encryption-tool.XXXXXX) cleanup() { set +e if [ -n "$mp" ]; then while read -r i; do [ "$i" != "$mp" ] || make_ro umount "$i" done < <(findmnt -o TARGET -Rn --list "$mp" | tac) fi if [ -n "$mounted" ]; then if [ -e "$tmpdir/mounts" ]; then # restore previous mounts while read -r line; do eval "$line" mapfile -td, options < <(echo -n "$OPTIONS") if [ -n "$cr_dev" ] && [ "$SOURCE" = "$blkpart" ]; then SOURCE="$cr_dev" fi mount "$SOURCE" "$TARGET" -t "$FSTYPE" -o "$OPTIONS" done < "$tmpdir/mounts" fi else [ -e "$cr_dev" ] && cryptsetup close "${cr_dev##*/}" case "$blkdev" in /dev/nbd*) qemu-nbd -d "$blkdev" ;; /dev/loop*) losetup -d "$blkdev" ;; esac fi [ -d "$tmpdir" ] && ! mountpoint -q "$tmpdir/mnt" && rm -rf "$tmpdir" } trap cleanup EXIT helpandquit() { cat <<-EOF Usage: $0 [OPTIONS] IMAGE|BLOCKDEV Encrypt IMAGE or BLOCKDEV OPTIONS: --verbose verbose --prime add hook scripts to initrd to encrypt on first boot --partno=N partition number (default 3) --gen-key generate random recovery key -h help screen EOF exit 0 } log_info() { [ "${verbose:-0}" -gt 0 ] || return 0 echo "$@" } err() { echo "Error: $*" >&2 exit 1 } warn() { echo "Warning: $*" >&2 } isdigits() { local v="${1:?}" [ -z "${v//[0-9]*/}" ] } settle_umount_events() { # Manual umount confuses systemd sometimes because it's async and the # .mount unit might still be active when the "start" is queued, making # it a noop, which ultimately leaves /sysroot unmounted # (https://github.com/systemd/systemd/issues/20329). To avoid that, # wait until systemd processed the umount events. In a chroot (or with # SYSTEMD_OFFLINE=1) systemctl always succeeds, so avoid an infinite loop. if [ "$mounted" = "/sysroot" ] && ! systemctl --quiet is-active does-not-exist.mount; then while systemctl --quiet is-active sysroot.mount; do sleep 0.5; done fi } read_password() { local password2 [ -z "$password" ] || return 0 if ! [ -t 0 ]; then read -r -s password return "$?" fi while true; do read -r -s -p "Enter encryption passphrase: " password echo if type -p pwscore &>/dev/null; then echo "$password" | pwscore || continue fi read -r -s -p "Confirm encryption passphrase: " password2 echo if [ "$password" != "$password2" ]; then echo "Entered passwords don't match" continue fi [ -n "$password" ] || err "No password, no encryption" break done } encrypt() { local encrypt_options=(\ --reduce-device-size 32m \ --progress-frequency=1 \ ) if [ -e "${ENCRYPTION_CONFIG:-/etc/encrypt_options}" ]; then while read -r op; do [ "${op//#}" = "$op" ] || continue encrypt_options+=("$op") done < "${ENCRYPTION_CONFIG:-/etc/encrypt_options}" fi # sle 15 compat code if type -p cryptsetup-reencrypt &> /dev/null; then read_password echo "$password" | cryptsetup-reencrypt --new --type luks1 "${encrypt_options[@]}" "$@" "${blkpart}" log_info "Encryption done" log_info "open encrypted image" echo "$password" | cryptsetup open "${blkpart}" "$cr_name" else log_info "encrypt with options ${encrypt_options[*]}" if [ -n "$password" ]; then # XXX: hopefully we can use the kernel keyring in the future here cryptsetup reencrypt --force-password --verbose --encrypt "${encrypt_options[@]}" "$@" "${blkpart}" "$cr_name" <<<"$password" [ -z "$gen_key" ] || echo '{"type":"systemd-recovery","keyslots":["0"]}' | cryptsetup token import "${blkpart}" else cryptsetup reencrypt --batch-mode --verify-passphrase --force-password --verbose --encrypt "${encrypt_options[@]}" "$@" "${blkpart}" "$cr_name" fi fi cr_dev="/dev/mapper/$cr_name" } call_dracut() { if [ -L "$mp/boot/initrd" ]; then local initrd kv initrd="$(readlink "$mp/boot/initrd")" kv="${initrd#initrd-}" log_info "create initrd for $kv" chroot "$mp" dracut --add-drivers dm_crypt -q -f "/boot/$initrd" "$kv" "$@" elif [ -e "$mp/etc/kernel/entry-token" ]; then local token kernel kv read -r token < "$mp/etc/kernel/entry-token" log_info "token $token" for initrd in "$mp/boot/efi/$token"/*/initrd-*; do kv="${initrd%/*}" kv="${kv##*/}" initrd="${initrd#"$mp"}" log_info "create $initrd for $kv" hostonly_l=no chroot "$mp" dracut -q --reproducible -f "$initrd" "$kv" "$@" done else err "Unsupported boot loader or fs layout" fi } mountstuff() { mount -t tmpfs -o size=10m tmpfs "$mp/run" for i in proc dev sys; do mount --bind "/$i" "$mp/$i" done for i in /.snapshots /boot/efi /boot/writable /var; do grep -q "\s$i\s" "$mp/etc/fstab" || continue [ -d "$mp/$i" ] || continue mountpoint -q "$mp/$i" && continue mount -T "$mp"/etc/fstab --target-prefix="$mp" "/$i" done } make_rw() { local prop read -r prop < <(btrfs prop get -t s "$mp" ro) [ "$prop" = "ro=true" ] || return 0 log_info "switch to rw" btrfs prop set -t s "$mp" ro false switched_rw=1 } make_ro() { [ -n "$switched_rw" ] || return 0 unset switched_rw log_info "set ro again" btrfs prop set -t s "$mp" ro true } ####### main ####### getopttmp=$(getopt -o hv --long help,verbose,prime,partno:,gen-key -n "${0##*/}" -- "$@") eval set -- "$getopttmp" while true ; do case "$1" in -h|--help) helpandquit ;; -v|--verbose) verbose=$((++verbose)); shift ;; --prime) prime="1"; shift ;; --partno) partno="$2"; shift 2;; --gen-key) gen_key="1"; shift;; --) shift ; break ;; *) echo "Internal error!" ; exit 1 ;; esac done [ -z "$1" ] && [ -e /etc/initrd-release ] && set -- /sysroot [ -n "$1" ] || helpandquit [ -z "$prime" ] && [ -e "/dev/mapper/$cr_name" ] && err "$cr_name exists. Exit." if [ -d "$1" ] || [ -b "$1" ]; then if [ -b "$1" ]; then blkpart="$1" else mountpoint -q "$1" || err "$1 is not a valid mountpoint" mp="$1" mounted="$1" blkpart="$(findmnt -nvo SOURCE "$mp")" fi [ -L "/sys/class/block/${blkpart##*/}" ] || err "$blkpart is not a partition" blkdev="$(readlink -f "/sys/class/block/${blkpart##*/}")" blkdev="${blkdev%/*}" blkdev="/dev/${blkdev##*/}" read -r partno < "/sys/class/block/${blkpart##*/}"/partition else [ -n "$partno" ] || warn "--partno not specified, assuming 3" : "${partno:=3}" case "${1##*/}" in *.raw ) log_info "setting up loop device" blkdev="$(losetup --show -fP "$1")" log_info "loop device $blkdev" ;; *.qcow2) [ -e "/dev/nbd0" ] || modprobe nbd blkdev=/dev/nbd0 qemu-nbd -c "$blkdev" "$1" udevadm settle ;; *) err "Unsupported image" ;; esac blkpart="${blkdev}p${partno}" fi shift eval "$(blkid -c /dev/null -o export "$blkpart"|sed 's/^/loop_/')" [ "$loop_TYPE" != crypto_LUKS ] || { echo "Already encrypted"; exit 0; } [ "$loop_TYPE" = btrfs ] || err "File system is ${loop_TYPE:-unknown} but only btrfs is supported" if [ -z "$mounted" ]; then log_info "mounting fs" mkdir -p "$tmpdir/mnt" mount -t btrfs -o rw "${blkpart}" "$tmpdir/mnt" mp="$tmpdir/mnt" else mountpoint -q "$mp" || err "$mp is not mounted" findmnt -o SOURCE,TARGET,FSTYPE,OPTIONS -Rvn --pairs "$mp" > "$tmpdir/mounts" mount -o remount,rw "$mp" fi if [ -n "$prime" ]; then mkdir -p "$tmpdir/overlay-w" dst="$tmpdir/overlay/95disk-encryption-tool" mkdir -p "$dst" for i in disk-encryption-tool disk-encryption-tool-dracut module-setup.sh \ disk-encryption-tool-dracut.service generate-recovery-key; do cp "${0%/*}/$i" "$dst/$i" done if [ -e "${ENCRYPTION_CONFIG:-/etc/encrypt_options}" ]; then cp "${ENCRYPTION_CONFIG:-/etc/encrypt_options}" "$dst/encrypt_options" export ENCRYPTION_CONFIG="/usr/lib/dracut/modules.d/95disk-encryption-tool/encrypt_options" fi make_rw mountstuff # dirty if [ -d "$mp/usr/share/jeos-firstboot/modules" ]; then install -D -m 644 "${0%/*}/jeos-firstboot-diskencrypt-override.conf" "$mp/usr/lib/systemd/system/jeos-firstboot.service.d/jeos-firstboot-diskencrypt-override.conf" cp "${0%/*}/jeos-firstboot-enroll" "$mp/usr/share/jeos-firstboot/modules/enroll" fi mount -t overlay overlay \ -o lowerdir="$mp/usr/lib/dracut/modules.d/,upperdir=$tmpdir/overlay,workdir=$tmpdir/overlay-w" \ "$mp/usr/lib/dracut/modules.d/" call_dracut exit 0 fi read -r minsize bytes _rest < <(btrfs inspect-internal min-dev-size "$mp") isdigits "$minsize" || err "Failed to read minimum btrfs size" [ "$bytes" = 'bytes' ] || err "Failed to read minimum btrfs size" log_info "resizing fs" btrfs filesystem resize "$minsize" "$mp" if [ -e "$tmpdir/mounts" ]; then # subshell intentional here tac "$tmpdir/mounts" | while read -r line; do eval "$line" umount "$TARGET" done else umount "$mp" fi unset mp settle_umount_events # shrink partition to a minimum so reencryption doesn't write everything log_info "resizing partition" echo "size=$((minsize/1024+32*1024))KiB" | sfdisk -q -N "$partno" "$blkdev" udevadm settle if [ -n "$gen_key" ]; then read -r password < <(generate-recovery-key) echo -e "Recovery key: \e[1m$password\e[m" if [ -e /etc/initrd-release ]; then read -r key_id < <(echo -n "$password" | keyctl padd user cryptenroll @u) fi fi echo "Encrypting..." encrypt "$@" log_info "grow partition again" echo ", +" | sfdisk --no-reread -q -N "$partno" "$blkdev" &> /dev/null if [ -e /etc/initrd-release ]; then # seems to be the only way to tell the kernel about a specific partition change partx -u --nr "$partno" "$blkdev" || : cryptsetup resize "$cr_name" <<<"$password" fi if [ -z "$mounted" ]; then mount -o rw "$cr_dev" "/mnt" mp="/mnt" else read -r line < "$tmpdir/mounts" eval "$line" mapfile -td, options < <(echo -n "$OPTIONS") for ((i=0;i<${#options};++i)); do [ "${options[i]}" = ro ] && options[i]=rw; done OPTIONS="$(IFS=, eval echo '"${options[*]}"')" [ "$SOURCE" = "$blkpart" ] && SOURCE="$cr_dev" mount "$cr_dev" "$TARGET" -t "$FSTYPE" -o "$OPTIONS" mp="$TARGET" fi log_info "resizing fs to max again" btrfs filesystem resize max "$mp" make_rw declare loop_UUID eval "$(blkid -c /dev/null -o export "$blkpart"|sed 's/^/loop_/')" if [ -n "$loop_UUID" ]; then echo "$cr_name /dev/disk/by-uuid/$loop_UUID none x-initrd.attach" > "$mp"/etc/crypttab else warn "Can't determine device UUID. Can't generate crypttab" fi mountstuff if grep -q "LOADER_TYPE.*grub2" "$mp"/etc/sysconfig/bootloader; then log_info "Update bootloader" echo GRUB_ENABLE_CRYPTODISK=y >> "$mp"/etc/default/grub sed -i -e 's/^LOADER_TYPE=.*/LOADER_TYPE="grub2"/' "$mp"/etc/sysconfig/bootloader chroot "$mp" update-bootloader --reinit sed -i -e 's/^LOADER_TYPE=.*/LOADER_TYPE="grub2-efi"/' "$mp"/etc/sysconfig/bootloader chroot "$mp" update-bootloader --reinit mv "$mp/boot/grub2/grub.cfg" "$mp/boot/grub2/grub.cfg.bak" cat > "$mp/boot/grub2/grub.cfg" <<-'EOF' set linux=linux set initrd=initrd if [ "${grub_cpu}" = "x86_64" -o "${grub_cpu}" = "i386" ]; then if [ "${grub_platform}" = "efi" ]; then set linux=linuxefi set initrd=initrdefi fi fi export linux initrd EOF sed -e 's/linuxefi/$linux/;s/initrdefi/$initrd/' < "$mp/boot/grub2/grub.cfg.bak" >> "$mp/boot/grub2/grub.cfg" rm "$mp/boot/grub2/grub.cfg.bak" elif [ -e "$mp/etc/kernel/entry-token" ]; then : # sd-boot else log_info "unsupported boot loader" grep LOADER_TYPE "$mp"/etc/sysconfig/bootloader fi # A new initrd is created as side effect of the enrolment # (jeos-firtboot module), as this calls sdbootutil make_ro echo "Image encryption completed" 07070100000008000081ED00000000000000000000000166CC4624000004EA000000000000000000000000000000000000004700000000disk-encryption-tool-1+git20240826.c956112/disk-encryption-tool-dracut#!/bin/sh exec < /dev/console >/dev/console 2>&1 type getarg > /dev/null 2>&1 || . /lib/dracut-lib.sh # get systemd credential # https://systemd.io/CREDENTIALS/ get_credential() { local var="${1:?}" local name="${2:?}" [ -n "$CREDENTIALS_DIRECTORY" ] || return 1 [ -e "$CREDENTIALS_DIRECTORY/$name" ] || return 1 read -r "$var" < "$CREDENTIALS_DIRECTORY/$name" || [ -n "${!var}" ] } encrypt= if get_credential encrypt disk-encryption-tool-dracut.encrypt && [ "$encrypt" = "no" ]; then exit 0 fi # check whether encryption was explicitly turned off if ! getargbool 1 rd.encrypt; then exit 0 fi # XXX: this is so dirty systemctl start sysroot.mount mount --target-prefix /sysroot --fstab /sysroot/etc/fstab /var if [ ! -e /sysroot/var/lib/YaST2/reconfig_system ] && [ "$encrypt" != "force" ]; then echo "system already configured, no encryption" umount /sysroot/var exit 0 fi umount /sysroot/var # silence systemd kill -SIGRTMIN+21 1 inhibitor= if [ "$encrypt" != "force" ]; then echo -ne '\n\n\a' read -n1 -s -r -t 10 -p "*** Press ESC to prevent encrypting the disk" inhibitor echo fi if [ "$inhibitor" != $'\e' ]; then /usr/bin/disk-encryption-tool -v --gen-key || die "Encryption failed" fi # turn messages on again kill -SIGRTMIN+20 1 07070100000009000081A400000000000000000000000166CC462400000355000000000000000000000000000000000000004F00000000disk-encryption-tool-1+git20240826.c956112/disk-encryption-tool-dracut.service[Unit] Description=Encrypt root disk DefaultDependencies=false # /sysroot needs to be available, but it's temporarily stopped # for remounting so a direct requirement is not possible Requires=initrd-root-device.target After=initrd-root-device.target After=combustion.service # After ignition completed its stuff After=ignition-complete.target # So that /etc/fstab's x-initrd.mount entries are read (again) later Before=initrd-parse-etc.service Conflicts=initrd-switch-root.target umount.target Conflicts=dracut-emergency.service emergency.service emergency.target # Without this it goes into an endless loop on failure OnFailure=emergency.target OnFailureJobMode=isolate [Service] Type=oneshot KeyringMode=shared ExecStart=/usr/bin/disk-encryption-tool-dracut ImportCredential=disk-encryption-tool-dracut.* [Install] RequiredBy=firstboot.target 0707010000000A000081ED00000000000000000000000166CC462400000895000000000000000000000000000000000000004700000000disk-encryption-tool-1+git20240826.c956112/disk-encryption-tool-enroll#!/bin/bash get_credential() { local var="${1:?}" local name="${2:?}" local keyid keyid="$(keyctl id %user:"$name" 2> /dev/null)" || true if [ -e "$CREDENTIALS_DIRECTORY/$name" ]; then read -r "$var" < "$CREDENTIALS_DIRECTORY/$name" elif [ -n "$keyid" ]; then read -r "$var" <<< "$(keyctl pipe "$keyid")" fi } have_luks2() { lsblk --noheadings -o PATH,FSTYPE | grep -q crypto_LUKS } write_issue_file() { if [ -e '/usr/sbin/issue-generator' ]; then mkdir -p "/run/issue.d/" issuefile="/run/issue.d/90-diskencrypt.conf" else issuefile='/dev/stdout' fi echo -ne "Encryption recovery key:\n " > "$issuefile" keyctl pipe "$crypt_keyid" >> "$issuefile" echo -e "\n" >> "$issuefile" if [ -x /usr/bin/qrencode ]; then echo "You can also scan it with your mobile phone:" >> "$issuefile" keyctl pipe "$crypt_keyid" | qrencode -t utf8i >> "$issuefile" fi issue-generator } [ ! -e "/var/lib/YaST2/reconfig_system" ] || exit 0 have_luks2 || exit 0 crypt_keyid="$(keyctl id %user:cryptenroll 2> /dev/null)" || exit 0 [ -n "$crypt_keyid" ] || { echo "Recovery key not registered in the keyring. Aborting" > /dev/stderr exit 1 } write_issue_file # Proceed with the enrollment pw= get_credential pw "disk-encryption-tool-enroll.pw" tpm2_pin= get_credential tpm2_pin "disk-encryption-tool-enroll.tpm2+pin" tpm2= get_credential tpm2 "disk-encryption-tool-enroll.tpm2" fido2= get_credential fido2 "disk-encryption-tool-enroll.fido2" [ -z "$pw" ] || { echo "Enrolling password" # Note that if --no-reuse-initrd is used, then a new initrd # will be created and will break the measurement of the # initial components if later the TPM2 enrollment is called extra= if [ -z "$tpm2_pin" ] && [ -z "$tpm2" ] && [ -z "$fido2" ]; then extra="--no-reuse-initrd" fi PW="$pw" sdbootutil enroll --method=password "$extra" } if [ -n "$tpm2_pin" ]; then echo "Enrolling TPM2 with PIN" SDB_ADD_INITIAL_COMPONENT=1 PIN="$crypt_tpm_pin" sdbootutil enroll --method=tpm2+pin elif [ -n "$tpm2" ]; then echo "Enrolling TPM2" SDB_ADD_INITIAL_COMPONENT=1 sdbootutil enroll --method=tpm2 fi [ -z "$fido2" ] || { echo "Enrolling a FIDO2 key" sdbootutil enroll --method=fido2 } 0707010000000B000081A400000000000000000000000166CC462400000158000000000000000000000000000000000000004F00000000disk-encryption-tool-1+git20240826.c956112/disk-encryption-tool-enroll.service[Unit] Description=Enroll encrypted root disk DefaultDependencies=false After=jeos-firstboot.service #ConditionPathExists=/var/lib/YaST2/enroll_system [Service] Type=oneshot RemainAfterExit=yes KeyringMode=shared ExecStart=/usr/bin/disk-encryption-tool-enroll ImportCredential=disk-encryption-tool-enroll.* [Install] WantedBy=default.target0707010000000C000081A400000000000000000000000166CC462400000E7C000000000000000000000000000000000000004500000000disk-encryption-tool-1+git20240826.c956112/disk-encryption-tool.spec# # spec file for package disk-encryption-tool # # Copyright (c) 2024 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed # upon. The license for this file, and modifications and additions to the # file, is the same license as for the pristine package itself (unless the # license for the pristine package is not an Open Source License, in which # case the license is the MIT License). An "Open Source License" is a # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. # Please submit bugfixes or comments via https://bugs.opensuse.org/ # # icecream 0 %if 0%{?_build_in_place} %define git_version %(git log '-n1' '--date=format:%Y%m%d' '--no-show-signature' "--pretty=format:+git%cd.%h") BuildRequires: git-core %else # this is required for obs' source validator. It's # 20-files-present-and-referenced ignores all conditionals. So the # definition of git_version actually happens always. %define git_version %{nil} %endif Name: disk-encryption-tool Version: 84.87%{git_version} Release: 0 Summary: Tool to reencrypt kiwi raw images License: MIT URL: https://github.com/lnussel/disk-encryption-tool Source: disk-encryption-tool-%{version}.tar BuildRequires: systemd-rpm-macros Requires: cryptsetup Requires: keyutils Requires: pcr-oracle # something needs to require it. Can be us. Requires: tpm2.0-tools Requires: qrencode ExclusiveArch: aarch64 ppc64le riscv64 x86_64 BuildArch: noarch %{?systemd_requires} %description Convert a plain text kiwi image into one with LUKS full disk encryption. Supports both raw and qcow2 images. It assumes that the third partition is the root fs using btrfs. After encrypting the disk, the fs is mounted and a new initrd created as well as the grub2 config adjusted. %prep %setup -q %build %install mkdir -p %buildroot/usr/lib/dracut/modules.d/95disk-encryption-tool for i in disk-encryption-tool{,-dracut,-dracut.service} module-setup.sh generate-recovery-key; do cp "$i" %buildroot/usr/lib/dracut/modules.d/95disk-encryption-tool/"$i" done mkdir -p %buildroot/usr/bin ln -s ../lib/dracut/modules.d/95disk-encryption-tool/disk-encryption-tool %buildroot/usr/bin ln -s ../lib/dracut/modules.d/95disk-encryption-tool/generate-recovery-key %buildroot/usr/bin install -D -m 644 jeos-firstboot-diskencrypt-override.conf \ %{buildroot}/usr/lib/systemd/system/jeos-firstboot.service.d/jeos-firstboot-diskencrypt-override.conf install -D -m 644 jeos-firstboot-enroll %buildroot/usr/share/jeos-firstboot/modules/enroll install -m 755 disk-encryption-tool-enroll %buildroot/usr/bin/disk-encryption-tool-enroll install -D -m 644 disk-encryption-tool-enroll.service %buildroot/%{_unitdir}/disk-encryption-tool-enroll.service %preun %service_del_preun disk-encryption-tool-enroll.service %postun %service_del_postun disk-encryption-tool-enroll.service %pre %service_add_pre disk-encryption-tool-enroll.service %post %service_add_post disk-encryption-tool-enroll.service %files %license LICENSE /usr/bin/disk-encryption-tool /usr/bin/disk-encryption-tool-enroll /usr/bin/generate-recovery-key %dir /usr/lib/dracut %dir /usr/lib/dracut/modules.d /usr/lib/dracut/modules.d/95disk-encryption-tool %dir /usr/share/jeos-firstboot %dir /usr/share/jeos-firstboot/modules /usr/share/jeos-firstboot/modules/enroll %dir /usr/lib/systemd/system/jeos-firstboot.service.d /usr/lib/systemd/system/jeos-firstboot.service.d/jeos-firstboot-diskencrypt-override.conf %{_unitdir}/disk-encryption-tool-enroll.service %changelog 0707010000000D000081ED00000000000000000000000166CC4624000001C9000000000000000000000000000000000000004100000000disk-encryption-tool-1+git20240826.c956112/generate-recovery-key#!/bin/bash set -e modhex=('c' 'b' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'n' 'r' 't' 'u' 'v') mapfile -t raw_key < <(hexdump -v --format '1/1 "%u\n"' -n 32 /dev/random) [ "${#raw_key[@]}" = 32 ] key="" for ((i=0;i<"${#raw_key[@]}";++i)); do [ "$i" -gt 0 ] && [ "$((i%4))" -eq 0 ] && key="$key-" c="${raw_key[i]}" key="$key${modhex[$((c>>4))]}${modhex[$((c&15))]}" done [ -x /usr/bin/qrencode ] && [ -t 1 ] && echo -n "$key" | qrencode -t utf8i echo "$key" 0707010000000E000081A400000000000000000000000166CC46240000001D000000000000000000000000000000000000005400000000disk-encryption-tool-1+git20240826.c956112/jeos-firstboot-diskencrypt-override.conf[Service] KeyringMode=shared 0707010000000F000081A400000000000000000000000166CC462400001170000000000000000000000000000000000000004100000000disk-encryption-tool-1+git20240826.c956112/jeos-firstboot-enroll#!/bin/bash crypt_keyid="" crypt_pw="" crypt_tpm_pin="" # for pin cryptenroll_tpm_extra_args=() with_fido2= with_tpm2= luks2_devices=() have_luks2() { lsblk --noheadings -o PATH,FSTYPE | grep -q crypto_LUKS } # exit early without defining any helper functions if there are no luks devices have_luks2 || return 0 enroll_systemd_firstboot() { [ -e /usr/bin/systemd-cryptenroll ] || return 0 crypt_keyid="$(keyctl id %user:cryptenroll 2> /dev/null)" || return 0 [ -n "$crypt_keyid" ] || return 0 welcome_screen_with_console_switch local has_fido2=${JEOS_HAS_FIDO2:-} local has_tpm2= [ -z "$(systemd-cryptenroll --fido2-device=list 2>/dev/null)" ] || has_fido2=1 [ ! -e '/sys/class/tpm/tpm0' ] || has_tpm2=lock while true; do local list=() if [ -z "$with_fido2" ] && [ -z "$with_tpm2" ] && [ -n "$has_fido2" ]; then list+=('FIDO2' $'Enroll FIDO2 token') fi if [ -z "$with_tpm2" ] && [ -z "$with_fido2" ] && [ -n "$has_tpm2" ]; then list+=('TPM2' $'Enroll TPM2 based token' 'TPM2_interactive' 'Enroll TPM2 based token with PIN') fi if [ -z "$crypt_pw" ]; then if [ -n "$password" ]; then list+=('root' $'Enroll root password') fi list+=('password' $'Enroll extra password') fi [ -n "$list" ] || break list+=('done' $'Done') d --no-tags --default-item "${list[0]}" --menu $"Disk Encryption" 0 0 "$(menuheight ${#list[@]})" "${list[@]}" if [ "$result" = 'done' ]; then if [ -z "$crypt_pw" ] && [ -z "$with_fido2" ] && [ -z "$with_tpm2" ] && [ -z "$is_jeos_config" ]; then d_styled --yesno $"Neither password, TPM2 nor FIDO2 entrolled. Unlocking disk will only work with recovery key. Is this intended?" 0 0 || continue fi break; elif [ "$result" = 'FIDO2' ]; then with_fido2=1 elif [ "$result" = 'TPM2' ]; then with_tpm2="$has_tpm2" elif [ "$result" = 'TPM2_interactive' ]; then while true; do d --insecure --passwordbox $"Enter new PIN (actually just passphrase)" 0 0 if [ -z "$result" ]; then d_styled --yesno $"Retry?" 0 0 || break continue fi crypt_tpm_pin="$result" d --insecure --passwordbox $"Confirm PIN" 0 0 [ "$crypt_tpm_pin" != "$result" ] || { with_tpm2="$has_tpm2"; break; } d --msgbox $"PINs don't match. Try again" 0 0 done elif [ "$result" = 'root' ]; then crypt_pw="$password" elif [ "$result" = 'password' ]; then while true; do d --insecure --passwordbox $"Enter encryption password" 0 0 if [ -z "$result" ]; then d --aspect 29 --msgbox $"No encryption password set. You can add more keys manually using systemd-cryptenroll." 0 0 break fi crypt_pw="$result" d --insecure --passwordbox $"Confirm encryption password" 0 0 [ "$crypt_pw" != "$result" ] || break d --msgbox $"Passwords don't match. Try again" 0 0 done else d --msgbox "Error: $result" 0 0 fi done return 0 } write_issue_file() { if [ -e '/usr/sbin/issue-generator' ] && [ -z "$dry" ]; then mkdir -p "/run/issue.d/" issuefile="/run/issue.d/90-diskencrypt.conf" else issuefile='/dev/stdout' fi echo -ne "Encryption recovery key:\n " > "$issuefile" keyctl pipe "$crypt_keyid" >> "$issuefile" echo -e "\n" >> "$issuefile" if [ -x /usr/bin/qrencode ]; then echo "You can also scan it with your mobile phone:" >> "$issuefile" keyctl pipe "$crypt_keyid" | qrencode -t utf8i >> "$issuefile" fi run issue-generator } enroll_post() { [ -e /usr/bin/systemd-cryptenroll ] || return 0 [ -n "$crypt_keyid" ] || return 0 write_issue_file do_enroll } do_enroll() { [ -z "$crypt_pw" ] || { # Note that if --no-reuse-initrd is used, then a new # initrd will be created and will break the # measurement of the initial components if later the # TPM2 enrollment is called extra= if [ -z "$with_tpm2" ] && [ -z "$with_fido2" ]; then extra="--no-reuse-initrd" fi PW="$crypt_pw" run sdbootutil enroll --method=password "$extra" } if [ -n "$with_tpm2" ]; then if [ -n "$crypt_tpm_pin" ]; then SDB_ADD_INITIAL_COMPONENT=1 PIN="$crypt_tpm_pin" run sdbootutil enroll --method=tpm2+pin else SDB_ADD_INITIAL_COMPONENT=1 run sdbootutil enroll --method=tpm2 fi fi [ -z "$with_fido2" ] || run sdbootutil enroll --method=fido2 } enroll_jeos_config() { is_jeos_config=1 d --insecure --passwordbox $"Enter decryption password" 0 0 [ -n "$result" ] || return 0 echo -n "$result" | keyctl padd user cryptenroll @u enroll_systemd_firstboot do_enroll } 07070100000010000081ED00000000000000000000000166CC4624000003F5000000000000000000000000000000000000003B00000000disk-encryption-tool-1+git20240826.c956112/module-setup.sh#!/bin/bash # called by dracut check() { require_any_binary cryptsetup || return 1 return 0 } # called by dracut depends() { echo "crypt" return 0 } # called by dracut install() { instmods dmi_sysfs # for systemd credentials via smbios inst_multiple -o cryptsetup-reencrypt inst_multiple cryptsetup btrfs mktemp getopt mountpoint findmnt sfdisk tac sed hexdump keyctl partx inst_script "$moddir"/disk-encryption-tool /usr/bin/disk-encryption-tool inst_script "$moddir"/disk-encryption-tool-dracut /usr/bin/disk-encryption-tool-dracut inst_script "$moddir"/generate-recovery-key /usr/bin/generate-recovery-key for service in "disk-encryption-tool-dracut.service"; do inst_simple "${moddir}/$service" "${systemdsystemunitdir}/$service" $SYSTEMCTL -q --root "$initdir" enable "$service" #$SYSTEMCTL -q --root "$initdir" enable "debug-shell.service" done : "${ENCRYPTION_CONFIG:=/etc/encrypt_options}" [ -e "$ENCRYPTION_CONFIG" ] && inst_simple "$ENCRYPTION_CONFIG" "/etc/encrypt_options" } 07070100000011000041ED00000000000000000000000266CC462400000000000000000000000000000000000000000000003000000000disk-encryption-tool-1+git20240826.c956112/test07070100000012000081A400000000000000000000000166CC46240000029D000000000000000000000000000000000000003B00000000disk-encryption-tool-1+git20240826.c956112/test/config.ign{ "ignition": { "version": "3.2.0" }, "passwd": { "users": [ { "name": "root", "passwordHash": "$2a$10$IGzLVVX6jfMoe4Qoog2v.e24woQJiys9Doe8.taWrqdDkZyrXiGZu" } ] }, "storage": { "filesystems": [ { "device": "/dev/disk/by-label/ROOT", "format": "btrfs", "mountOptions": [ "subvol=/@/home" ], "path": "/home", "wipeFilesystem": false } ], "files": [ { "path": "/etc/locale.conf", "mode": 420, "overwrite": true, "contents": { "source": "data:,LANG=en_US.UTF-8" } } ] } } 07070100000013000081ED00000000000000000000000166CC46240000104B000000000000000000000000000000000000003800000000disk-encryption-tool-1+git20240826.c956112/test/test.sh#!/bin/bash set -euxo pipefail # Some basic combustion testing: # 1. Download the latest MicroOS image # 2. Use its combustion to install the disk-encryption-tool to test and transfer kernel + initrd to the host using 9pfs # 3. Revert the image to the original state and perform tests using the generated kernel + initrd # Skip the generation of a new initrd with the changed disk-encryption-tool. # Only useful when iterating this test script. reuseinitrd= if [ "${1-}" = "--reuseinitrd" ]; then reuseinitrd=1 shift fi # Working dir which is also exposed to the VM through 9pfs. # If not specified, create a temporary directory which is deleted on exit. if [ -n "${1-}" ]; then tmpdir="$(realpath "$1")" else tmpdir="$(mktemp -d)" cleanup() { rm -rf "$tmpdir" } trap cleanup EXIT fi QEMU_BASEARGS=( # -accel tcg was here after -accel kvm but the fallback hid a weird bug # that in GH actions only the first instance of QEMU was able to access /dev/kvm. -accel kvm -cpu host -nographic -m 1024 # Reading from stdin doesn't work, configure serial and monitor appropriately. -chardev null,id=serial,logfile=/dev/stdout,logappend=on -serial chardev:serial -monitor none -virtfs "local,path=${tmpdir},mount_tag=tmpdir,security_model=none") if [ -e /usr/share/qemu/ovmf-x86_64-code.bin ]; then QEMU_BASEARGS+=(-bios /usr/share/qemu/ovmf-x86_64-code.bin) elif [ -e /usr/share/qemu/OVMF.fd ]; then QEMU_BASEARGS+=(-bios /usr/share/qemu/OVMF.fd) else echo "No OVMF found" exit 1 fi # Prepare the temporary dir: Install disk-encryption-tool and copy resources. testdir="$(dirname "$0")" # TODO: Use a Makefile for this and in the .spec file. mkdir -p "${tmpdir}/install/usr/lib/dracut/modules.d/95disk-encryption-tool" for i in disk-encryption-tool{,-dracut,-dracut.service} module-setup.sh generate-recovery-key; do cp "${testdir}/../${i}" "${tmpdir}/install/usr/lib/dracut/modules.d/95disk-encryption-tool/${i}" done cp "${testdir}/"{testscript,config.ign} "${tmpdir}" cd "$tmpdir" # Download latest MicroOS image if ! [ -f openSUSE-MicroOS.x86_64-kvm-and-xen-sdboot.qcow2 ]; then wget --progress=bar:force:noscroll https://download.opensuse.org/tumbleweed/appliances/openSUSE-MicroOS.x86_64-kvm-and-xen-sdboot.qcow2 qemu-img snapshot -c initial openSUSE-MicroOS.x86_64-kvm-and-xen-sdboot.qcow2 else qemu-img snapshot -a initial openSUSE-MicroOS.x86_64-kvm-and-xen-sdboot.qcow2 fi # First step: Use combustion in the downloaded image to generate an initrd with the new disk-encryption-tool. if ! [ -n "${reuseinitrd}" ] || ! [ -e "${tmpdir}/vmlinuz" ] || ! [ -e "${tmpdir}/initrd" ]; then rm -f "${tmpdir}/done" cat >create-initrd <<'EOF' #!/bin/bash set -euxo pipefail exec &>/dev/ttyS0 trap '[ $? -eq 0 ] || poweroff -f' EXIT mount -t 9p -o trans=virtio tmpdir /mnt # Install new disk-encryption-tool, make sure the old remnants are gone rpm -e --nodeps --noscripts disk-encryption-tool cp -av /mnt/install/usr / cp /usr/lib/modules/$(uname -r)/vmlinuz /mnt/vmlinuz dracut -f --no-hostonly /mnt/initrd touch /mnt/done umount /mnt SYSTEMD_IGNORE_CHROOT=1 poweroff -f EOF timeout 300 qemu-system-x86_64 "${QEMU_BASEARGS[@]}" -drive if=virtio,file=openSUSE-MicroOS.x86_64-kvm-and-xen-sdboot.qcow2 \ -fw_cfg name=opt/org.opensuse.combustion/script,file=create-initrd if ! [ -e "${tmpdir}/done" ]; then echo "Initrd generation failed" exit 1 fi fi # Test using a config drive rm -f "${tmpdir}/done" qemu-img snapshot -a initial openSUSE-MicroOS.x86_64-kvm-and-xen-sdboot.qcow2 rm -rf configdrv mkdir -p configdrv/combustion/ cp testscript configdrv/combustion/script mkdir -p configdrv/ignition/ cp config.ign configdrv/ignition/config.ign /sbin/mkfs.ext4 -F -d configdrv -L ignition combustion.raw 16M timeout 300 qemu-system-x86_64 "${QEMU_BASEARGS[@]}" -drive if=virtio,file=openSUSE-MicroOS.x86_64-kvm-and-xen-sdboot.qcow2 \ -kernel vmlinuz -initrd initrd -append "root=LABEL=ROOT console=ttyS0 quiet systemd.show_status=1 systemd.log_target=console systemd.journald.forward_to_console=1 rd.emergency=poweroff rd.shell=0" \ -drive if=virtio,file=combustion.raw if ! [ -e "${tmpdir}/done" ]; then echo "Test failed" exit 1 fi 07070100000014000081A400000000000000000000000166CC462400000A86000000000000000000000000000000000000003B00000000disk-encryption-tool-1+git20240826.c956112/test/testscript#!/bin/bash # combustion: prepare set -euxo pipefail exec &>/dev/ttyS0 # Poweroff immediately on any failure to avoid unnecessary waiting. trap '[ $? -eq 0 ] || poweroff -f' EXIT if [ "${1-}" = "--prepare" ]; then # We set disk-encryption-tool-dracut.encryption credential to # "force". This will make disk-encryption-tool-dracut force the # encryption, ignoring that Combusion configured the system, and # will skip the permission countdown # # After the encryption the recovery key is registered in the # kernel keyring %user:cryptenroll mkdir -p /run/credstore echo "force" > /run/credstore/disk-encryption-tool-dracut.encrypt exit 0 fi # Create a valid machine-id, as this will be required to create later # the host secret systemd-machine-id-setup # We want to persist the host secret key created via systemd-cred # (/var/lib/systemd/credential.secret) mount /var mkdir -p /etc/credstore.encrypted credential="$(mktemp disk-encryption-tool.XXXXXXXXXX)" # Enroll extra password # echo "SECRET_PASSWORD" > "$credential" echo "linux" > "$credential" systemd-creds encrypt --name=disk-encryption-tool-enroll.pw "$credential" \ /etc/credstore.encrypted/disk-encryption-tool-enroll.pw # # Enroll TPM2 with secret PIN # echo "SECRET_PIN" > "$credential" # systemd-creds encrypt --name=disk-encryption-tool-enroll.tpm2+pin "$credential" \ # /etc/credstore.encrypted/disk-encryption-tool-enroll.tpm2+pin # # Enroll TPM2 # echo "1" > "$credential" # systemd-creds encrypt --name=disk-encryption-tool-enroll.tpm2 "$credential" \ # /etc/credstore.encrypted/disk-encryption-tool-enroll.tpm2 # # Enroll FIDO2 # echo "1" > "$credential" # systemd-creds encrypt --name=disk-encryption-tool-enroll.fido2 "$credential" \ # /etc/credstore.encrypted/disk-encryption-tool-enroll.fido2 shred -u "$credential" # Umount back /var to not confuse tukit later umount /var # Keyboard systemd-firstboot --force --keymap=es # Make sure that the system comes up good, leave a marker in the shared FS # and power off the VM. cat >>/usr/bin/combustion-validate <<'EOF' #!/bin/bash set -euxo pipefail exec &>/dev/ttyS0 trap '[ $? -eq 0 ] || poweroff -f' EXIT findmnt lsblk if [ "$(findmnt -nrvo SOURCE /)" != "/dev/mapper/cr_root" ]; then echo "Not encrypted?" exit 1 fi mount -t 9p -o trans=virtio tmpdir /mnt touch /mnt/done umount /mnt poweroff -f EOF chmod a+x /usr/bin/combustion-validate cat >>/etc/systemd/system/combustion-validate.service <<'EOF' [Service] ExecStart=/usr/bin/combustion-validate [Install] RequiredBy=default.target EOF systemctl enable combustion-validate.service # Leave a marker echo "Configured with combustion" > /etc/issue.d/combustion 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!81 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor