From eab4fde8cf43f462fefe59572f01690fff836aea Mon Sep 17 00:00:00 2001 From: Nikita Dubrovskii Date: Fri, 8 Nov 2024 14:29:33 +0100 Subject: [PATCH 1/6] genprotimg.bu: drop ssh key for core user ssh access to the VM is not required, was here just for debug purposes. --- src/secex-genprotimgvm-scripts/genprotimg.bu | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/secex-genprotimgvm-scripts/genprotimg.bu b/src/secex-genprotimgvm-scripts/genprotimg.bu index 978d1b58f1..13cfaebe7f 100644 --- a/src/secex-genprotimgvm-scripts/genprotimg.bu +++ b/src/secex-genprotimgvm-scripts/genprotimg.bu @@ -3,8 +3,6 @@ version: 1.5.0 passwd: users: - name: core - ssh_authorized_keys_local: - - id_rsa.pub groups: - wheel storage: From f15c4f5bf4089a1c0458f6973c0308cbf64d7f6c Mon Sep 17 00:00:00 2001 From: Nikita Dubrovskii Date: Fri, 15 Nov 2024 07:42:55 +0100 Subject: [PATCH 2/6] genprotimg.bu: store main script under /usr/local/bin instead of /etc Cannot recall the reason why script was under '/etc', so removing this weird path. --- src/secex-genprotimgvm-scripts/genprotimg.bu | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/secex-genprotimgvm-scripts/genprotimg.bu b/src/secex-genprotimgvm-scripts/genprotimg.bu index 13cfaebe7f..9d4f17fc09 100644 --- a/src/secex-genprotimgvm-scripts/genprotimg.bu +++ b/src/secex-genprotimgvm-scripts/genprotimg.bu @@ -14,7 +14,7 @@ storage: overwrite: true contents: local: secex-hostkey - - path: /etc/do_genprotimg + - path: /usr/local/bin/do_genprotimg overwrite: true mode: 0755 contents: @@ -52,7 +52,7 @@ systemd: [Service] Type=oneshot StandardOutput=journal+console - ExecStart=/etc/do_genprotimg + ExecStart=/usr/local/bin/do_genprotimg ExecStopPost=/sbin/halt [Install] WantedBy=default.target From b437efd06ad7cfceba051b37400d60de67103ac3 Mon Sep 17 00:00:00 2001 From: Nikita Dubrovskii Date: Mon, 11 Nov 2024 13:57:11 +0100 Subject: [PATCH 3/6] genprotimg.bu: halt system after firstboot completed We use CoreOS as base system for the FakeSecureVM, unfortunately it's not possible to generate 'sdboot' image during `firstboot`, because ignition checks for unique `boot` labeled fs, but added as a disk qemu-secex.qcow2 image has its onw 'boot' partition. --- src/secex-genprotimgvm-scripts/genprotimg.bu | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/secex-genprotimgvm-scripts/genprotimg.bu b/src/secex-genprotimgvm-scripts/genprotimg.bu index 9d4f17fc09..eac37c897d 100644 --- a/src/secex-genprotimgvm-scripts/genprotimg.bu +++ b/src/secex-genprotimgvm-scripts/genprotimg.bu @@ -71,3 +71,16 @@ systemd: Options=rw,noatime [Install] WantedBy=default.target + - name: autohalt.service + enabled: true + contents: | + [Unit] + Description=Halts system on firstboot + ConditionKernelCommandLine=ignition.firstboot + After=multi-user.target + [Service] + Type=oneshot + ExecStartPre=/bin/echo "Shutting down" + ExecStart=/usr/bin/systemctl --no-block poweroff + [Install] + WantedBy=multi-user.target From cc0d950b9fad5817681a29d3d3253f371ba31360 Mon Sep 17 00:00:00 2001 From: Nikita Dubrovskii Date: Fri, 8 Nov 2024 13:05:56 +0100 Subject: [PATCH 4/6] genprotimg.bu: add coreos-genprotimg-generator This fixes an issue when during firstboot system tried to mount genprotimg partition. --- src/secex-genprotimgvm-scripts/genprotimg.bu | 49 +++++++++++++------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/secex-genprotimgvm-scripts/genprotimg.bu b/src/secex-genprotimgvm-scripts/genprotimg.bu index eac37c897d..e5769f4a13 100644 --- a/src/secex-genprotimgvm-scripts/genprotimg.bu +++ b/src/secex-genprotimgvm-scripts/genprotimg.bu @@ -20,7 +20,7 @@ storage: contents: inline: | #!/bin/bash - set -euo pipefail + set -xeuo pipefail trap "rm -f /var/genprotimg/signal.file" EXIT bash /var/build/genprotimg-script.sh & while [ ! -e "/var/genprotimg/signal.file" ]; do @@ -29,6 +29,34 @@ storage: genprotimg -V --no-verify -i /var/genprotimg/vmlinuz -r /var/genprotimg/initrd.img -p /var/genprotimg/parmfile -k /etc/se-hostkeys/ibm-z-hostkey-1 -o /var/genprotimg/se.img rm -f /var/genprotimg/signal.file bash /var/build/post-script.sh + - path: /etc/systemd/system-generators/coreos-genprotimg-generator + overwrite: true + mode: 0755 + contents: + inline: | + #!/bin/bash + export PATH="/usr/bin:/usr/sbin:${PATH}" + set -euo pipefail + . /usr/lib/coreos/generator-lib.sh + if [ ! -z $(karg ignition.firstboot) ]; then + exit 0 + fi + mkdir -p "${UNIT_DIR}/default.target.wants" + + cat > "${UNIT_DIR}"/var-build.mount << 'EOF' + # generated by coreos-genprotimg-generator + # Mounts partition with parmfile, pre- and post- scripts used by genprotimg.service + [Unit] + Description=Genprotimg partition mount + Requires=dev-disk-by\x2did-virtio\x2dgenprotimg.device + After=dev-disk-by\x2did-virtio\x2dgenprotimg.device + [Mount] + What=/dev/disk/by-id/virtio-genprotimg + Where=/var/build + Type=ext4 + Options=rw,noatime + EOF + ln -sf "../var-build.mount" "${UNIT_DIR}/default.target.wants/" systemd: units: - name: serial-getty@.service @@ -46,29 +74,14 @@ systemd: enabled: true contents: | [Unit] - Description=GenProtImg + Description=Creates sdboot image on 'se' labeled partition of qemu-secex qcow2 image ConditionKernelCommandLine=!ignition.firstboot After=var-build.mount [Service] Type=oneshot StandardOutput=journal+console ExecStart=/usr/local/bin/do_genprotimg - ExecStopPost=/sbin/halt - [Install] - WantedBy=default.target - - name: var-build.mount - enabled: true - contents: | - [Unit] - Description=Mounts genprotimg build partition - ConditionKernelCommandLine=!ignition.firstboot - Requires=dev-disk-by\x2did-virtio\x2dgenprotimg.device - After=dev-disk-by\x2did-virtio\x2dgenprotimg.device - [Mount] - What=/dev/disk/by-id/virtio-genprotimg - Where=/var/build - Type=ext4 - Options=rw,noatime + ExecStartPost=/usr/bin/systemctl --no-block poweroff [Install] WantedBy=default.target - name: autohalt.service From 979c3f4aa1c4ea2236fdcf6e9680dd370d60c653 Mon Sep 17 00:00:00 2001 From: Nikita Dubrovskii Date: Mon, 11 Nov 2024 14:06:29 +0100 Subject: [PATCH 5/6] qemu-secex: generate fake-secure-vm.qcow2 for local build Automatically generates genprotimgvm during build, when official one is not available and/or there is no so-called "IBM Universal Hostkey". Main goal is to support local/custom build of qemu-secex target. Assuming there is a valid hostkey (/srv/secex-hostkey), it'd possible to generate coreos.qemu-secex.qcow2 just by running: ``` cosa cmd-buildextend-secex ``` If later there is a need to build some other variant, previously generated genprotimgvm could be used again: ``` cosa buildextend-secex --force --genprotimgvm path/to/fake-secure-vm.qcow2 ``` --- src/cmd-osbuild | 111 ++++++++++++++++++++++++++++-------------------- 1 file changed, 66 insertions(+), 45 deletions(-) diff --git a/src/cmd-osbuild b/src/cmd-osbuild index 1e8b1ca2fd..a9f9d33c4c 100755 --- a/src/cmd-osbuild +++ b/src/cmd-osbuild @@ -77,51 +77,67 @@ json.dump(j, sys.stdout, indent=4) # For qemu-secex we need to do a few extra things like spin up a # VM to run genprotimg and save off the pubkey for Ignition. postprocess_qemu_secex() { - if [ ! -f "${genprotimgvm}" ]; then - fatal "No genprotimgvm provided at ${genprotimgvm}" - fi - - # Basic qemu args: - qemu_args=(); blk_size="512" - [[ $platform == metal4k ]] && blk_size="4096" - qemu_args+=("-drive" "if=none,id=target,format=qcow2,file=${imgpath},cache=unsafe" \ - "-device" "virtio-blk,serial=target,drive=target,physical_block_size=${blk_size},logical_block_size=${blk_size}") - - # SecureVM (holding Universal Key for all IBM Z Mainframes) requires scripts to execute genprotimg - se_script_dir="/usr/lib/coreos-assembler/secex-genprotimgvm-scripts" - genprotimg_img="${PWD}/secex-genprotimg.img" - genprotimg_dir=$(mktemp -p "${tmp_builddir}" -d) - cp "${se_script_dir}/genprotimg-script.sh" "${se_script_dir}/post-script.sh" "${genprotimg_dir}" - # Extra kargs with dm-verity hashes - secex_kargs="ignition.firstboot" - secex_kargs+=" rootfs.roothash=$(<"${outdir}/${platform}/rootfs_hash")" - secex_kargs+=" bootfs.roothash=$(<"${outdir}/${platform}/bootfs_hash")" - echo "${secex_kargs}" > "${genprotimg_dir}/parmfile" - virt-make-fs --format=raw --type=ext4 "${genprotimg_dir}" "${genprotimg_img}" - rm -rf "${genprotimg_dir}" - qemu_args+=("-drive" "if=none,id=genprotimg,format=raw,file=${genprotimg_img}" \ - "-device" "virtio-blk,serial=genprotimg,drive=genprotimg") - - # GPG keys used for protecting Ignition config - tmp_gpg_home=$(mktemp -p "${tmp_builddir}" -d) - ignition_pubkey=$(mktemp -p "${tmp_builddir}") - ignition_prikey=$(mktemp -p "${tmp_builddir}") - gpg --homedir "${tmp_gpg_home}" --batch --passphrase '' --yes --quick-gen-key "Secure Execution (secex) ${build}" rsa4096 encr none - gpg --homedir "${tmp_gpg_home}" --armor --export secex > "${ignition_pubkey}" - gpg --homedir "${tmp_gpg_home}" --armor --export-secret-key secex > "${ignition_prikey}" - exec 9<"${ignition_prikey}" - rm -rf "${tmp_gpg_home}" "${ignition_prikey}" - qemu_args+=("-add-fd" "fd=9,set=3" "-drive" "if=none,id=gpgkey,format=raw,file=/dev/fdset/3,readonly=on" \ - "-device" "virtio-blk,serial=gpgkey,drive=gpgkey") - - /usr/lib/coreos-assembler/secex-genprotimgvm-scripts/runvm.sh \ - --genprotimgvm "${genprotimgvm}" -- "${qemu_args[@]}" - rm -f "${genprotimg_img}" - exec 9>&- - - # Now store the generated ${ignition_pubkey} in the builddir and meta.json - gpg_key_filename="${name}-${build}-ignition-secex-key.gpg.pub" - postprocess_artifact "ignition-gpg-key" "${ignition_pubkey}" "${gpg_key_filename}" 'True' + if [ ! -f "${genprotimgvm}" ]; then + echo "No genprotimgvm provided" + genprotimgvm="${workdir}/tmp/fake-secure-vm.qcow2" + if [ -f "${genprotimgvm}" ]; then + echo "Found locally generated ${genprotimgvm}, skipping generation" + else + if [ ! -f "${hostkey}" ]; then + fatal "No hostkey and no genprotimgvm provided" + fi + ignition=$(mktemp -p "${tmp_builddir}") + butane -p -d "$(dirname "${hostkey}")" /usr/lib/coreos-assembler/secex-genprotimgvm-scripts/genprotimg.bu -o "${ignition}" + + cp "/srv/builds/latest/${basearch}/${name}-${build}-qemu.${basearch}.${suffix}" "${genprotimgvm}" + chmod +w "${genprotimgvm}" + genvm_args=("-drive" "if=none,id=hda,format=qcow2,file=${genprotimgvm},auto-read-only=off,cache=unsafe" \ + "-device" "virtio-blk,drive=hda,bootindex=1") + kola qemuexec -i "${ignition}" -- "${genvm_args[@]}" + fi + fi + + # Basic qemu args: + qemu_args=(); blk_size="512" + [[ $platform == metal4k ]] && blk_size="4096" + qemu_args+=("-drive" "if=none,id=target,format=qcow2,file=${imgpath},cache=unsafe" \ + "-device" "virtio-blk,serial=target,drive=target,physical_block_size=${blk_size},logical_block_size=${blk_size}") + + # SecureVM (holding Universal Key for all IBM Z Mainframes) requires scripts to execute genprotimg + se_script_dir="/usr/lib/coreos-assembler/secex-genprotimgvm-scripts" + genprotimg_img="${PWD}/secex-genprotimg.img" + genprotimg_dir=$(mktemp -p "${tmp_builddir}" -d) + cp "${se_script_dir}/genprotimg-script.sh" "${se_script_dir}/post-script.sh" "${genprotimg_dir}" + # Extra kargs with dm-verity hashes + secex_kargs="ignition.firstboot" + secex_kargs+=" rootfs.roothash=$(<"${outdir}/${platform}/rootfs_hash")" + secex_kargs+=" bootfs.roothash=$(<"${outdir}/${platform}/bootfs_hash")" + echo "${secex_kargs}" > "${genprotimg_dir}/parmfile" + virt-make-fs --format=raw --type=ext4 "${genprotimg_dir}" "${genprotimg_img}" + rm -rf "${genprotimg_dir}" + qemu_args+=("-drive" "if=none,id=genprotimg,format=raw,file=${genprotimg_img}" \ + "-device" "virtio-blk,serial=genprotimg,drive=genprotimg") + + # GPG keys used for protecting Ignition config + tmp_gpg_home=$(mktemp -p "${tmp_builddir}" -d) + ignition_pubkey=$(mktemp -p "${tmp_builddir}") + ignition_prikey=$(mktemp -p "${tmp_builddir}") + gpg --homedir "${tmp_gpg_home}" --batch --passphrase '' --yes --quick-gen-key "Secure Execution (secex) ${build}" rsa4096 encr none + gpg --homedir "${tmp_gpg_home}" --armor --export secex > "${ignition_pubkey}" + gpg --homedir "${tmp_gpg_home}" --armor --export-secret-key secex > "${ignition_prikey}" + exec 9<"${ignition_prikey}" + rm -rf "${tmp_gpg_home}" "${ignition_prikey}" + qemu_args+=("-add-fd" "fd=9,set=3" "-drive" "if=none,id=gpgkey,format=raw,file=/dev/fdset/3,readonly=on" \ + "-device" "virtio-blk,serial=gpgkey,drive=gpgkey") + + /usr/lib/coreos-assembler/secex-genprotimgvm-scripts/runvm.sh \ + --genprotimgvm "${genprotimgvm}" -- "${qemu_args[@]}" + rm -f "${genprotimg_img}" + exec 9>&- + + # Now store the generated ${ignition_pubkey} in the builddir and meta.json + gpg_key_filename="${name}-${build}-ignition-secex-key.gpg.pub" + postprocess_artifact "ignition-gpg-key" "${ignition_pubkey}" "${gpg_key_filename}" 'True' } # Here we generate the input JSON we pass to runvm_osbuild for all of our image builds @@ -207,6 +223,7 @@ EOF main() { # Set Some Defaults genprotimgvm=/data.secex/genprotimgvm.qcow2 + hostkey=/srv/secex-hostkey build= force= @@ -244,6 +261,10 @@ main() { genprotimgvm="$2" shift ;; + --hostkey) + hostkey="$2" + shift + ;; --platforms) shift # The arg is next in position args # Split the comma separated string of platforms into an array From 4cdb9b6ef7e53cfc28f5151e5961d664a41e21f8 Mon Sep 17 00:00:00 2001 From: Nikita Dubrovskii Date: Wed, 13 Nov 2024 09:20:35 +0100 Subject: [PATCH 6/6] qemu-secex: drop hardcoded 'secex-hostkey' name and inject user-provided file instead --- src/cmd-osbuild | 12 +++++++++--- src/secex-genprotimgvm-scripts/genprotimg.bu | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/cmd-osbuild b/src/cmd-osbuild index a9f9d33c4c..aa2b43426a 100755 --- a/src/cmd-osbuild +++ b/src/cmd-osbuild @@ -86,14 +86,20 @@ postprocess_qemu_secex() { if [ ! -f "${hostkey}" ]; then fatal "No hostkey and no genprotimgvm provided" fi - ignition=$(mktemp -p "${tmp_builddir}") - butane -p -d "$(dirname "${hostkey}")" /usr/lib/coreos-assembler/secex-genprotimgvm-scripts/genprotimg.bu -o "${ignition}" + echo "Injecting user-provided hostkey into config" + ignition_cfg=$(mktemp -p "${tmp_builddir}") + butane_cfg=$(mktemp -p "${tmp_builddir}") + hostkey_name=$(basename "${hostkey}") + hostkey_path=$(dirname "${hostkey}") + cp /usr/lib/coreos-assembler/secex-genprotimgvm-scripts/genprotimg.bu "${butane_cfg}" + sed -i 's/HOSTKEY-FILE/'"${hostkey_name}"'/g' "${butane_cfg}" + butane -p -d "${hostkey_path}" "${butane_cfg}" -o "${ignition_cfg}" cp "/srv/builds/latest/${basearch}/${name}-${build}-qemu.${basearch}.${suffix}" "${genprotimgvm}" chmod +w "${genprotimgvm}" genvm_args=("-drive" "if=none,id=hda,format=qcow2,file=${genprotimgvm},auto-read-only=off,cache=unsafe" \ "-device" "virtio-blk,drive=hda,bootindex=1") - kola qemuexec -i "${ignition}" -- "${genvm_args[@]}" + kola qemuexec -i "${ignition_cfg}" -- "${genvm_args[@]}" fi fi diff --git a/src/secex-genprotimgvm-scripts/genprotimg.bu b/src/secex-genprotimgvm-scripts/genprotimg.bu index e5769f4a13..bd827b130d 100644 --- a/src/secex-genprotimgvm-scripts/genprotimg.bu +++ b/src/secex-genprotimgvm-scripts/genprotimg.bu @@ -13,7 +13,7 @@ storage: - path: /etc/se-hostkeys/ibm-z-hostkey-1 overwrite: true contents: - local: secex-hostkey + local: HOSTKEY-FILE - path: /usr/local/bin/do_genprotimg overwrite: true mode: 0755