diff --git a/src/cmd-osbuild b/src/cmd-osbuild index 1e8b1ca2fd..aa2b43426a 100755 --- a/src/cmd-osbuild +++ b/src/cmd-osbuild @@ -77,51 +77,73 @@ 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 + 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_cfg}" -- "${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 +229,7 @@ EOF main() { # Set Some Defaults genprotimgvm=/data.secex/genprotimgvm.qcow2 + hostkey=/srv/secex-hostkey build= force= @@ -244,6 +267,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 diff --git a/src/secex-genprotimgvm-scripts/genprotimg.bu b/src/secex-genprotimgvm-scripts/genprotimg.bu index 978d1b58f1..bd827b130d 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: @@ -15,14 +13,14 @@ storage: - path: /etc/se-hostkeys/ibm-z-hostkey-1 overwrite: true contents: - local: secex-hostkey - - path: /etc/do_genprotimg + local: HOSTKEY-FILE + - path: /usr/local/bin/do_genprotimg overwrite: true mode: 0755 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 @@ -31,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 @@ -48,28 +74,26 @@ 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=/etc/do_genprotimg - ExecStopPost=/sbin/halt + ExecStart=/usr/local/bin/do_genprotimg + ExecStartPost=/usr/bin/systemctl --no-block poweroff [Install] WantedBy=default.target - - name: var-build.mount + - name: autohalt.service 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 + 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=default.target + WantedBy=multi-user.target