diff --git a/src/cmd-buildextend-metal b/src/cmd-buildextend-metal index 86dafd3cac28b4d7185c7e45e6632ed56fe24606..4be486d84f052a111817d99e097a3929284e921b 100755 --- a/src/cmd-buildextend-metal +++ b/src/cmd-buildextend-metal @@ -36,6 +36,7 @@ EOF # Parse options hostkey= genprotimgvm=/data.secex/genprotimgvm.qcow2 +ignition_pubkey= rc=0 build= force= @@ -72,7 +73,6 @@ while true; do ;; -*) fatal "$0: unrecognized option: $1" - exit 1 ;; *) break @@ -163,18 +163,17 @@ if [ "${image_type}" = dasd ] || [ "${image_type}" = metal4k ]; then ignition_platform_id=metal fi -yaml2json "/usr/lib/coreos-assembler/image-default.yaml" image-default.json -# Combine with the defaults -cat image-default.json "${image_json}" | jq -s add > image-configured.json - # We do some extra handling of the rootfs here; it feeds into size estimation. -rootfs_type=$(jq -re .rootfs < image-configured.json) +rootfs_type=$(jq -re .rootfs < "${image_json}") -deploy_container= -container_imgref=$(jq -r '.["container-imgref"]//""' < image-configured.json) -if test -n "${container_imgref}" || jq -re '.["deploy-via-container"]' < image-configured.json >/dev/null; then - deploy_container=ostree-unverified-image:oci-archive:$builddir/$(meta_key images.ostree.path) +deploy_via_container="" +if jq -re '.["deploy-via-container"]' < "${image_json}"; then + deploy_via_container="true" fi +container_imgref=$(jq -r '.["container-imgref"]//""' < "${image_json}") +# Nowadays we pull the container across virtiofs rather than accessing the repo, see +# https://github.com/openshift/os/issues/594 +ostree_container=ostree-unverified-image:oci-archive:$builddir/$(meta_key images.ostree.path) # fs-verity requires block size = page size. We need to take that into account # in the disk size estimation due to higher fragmentation on larger blocks. @@ -233,15 +232,7 @@ fi set -x kargs="$(python3 -c 'import sys, json; args = json.load(sys.stdin)["extra-kargs"]; print(" ".join(args))' < "${image_json}")" -tty="console=tty0 console=${DEFAULT_TERMINAL},115200n8" -# On each s390x hypervisor, a tty would be automatically detected by the kernel -# and systemd, there is no need to specify one. However, we keep DEFAULT_TERMINAL -# as ttysclp0, which is helpful for building/testing with KVM+virtio (cmd-run). -# For aarch64, ttyAMA0 is used as the default console -case "$basearch" in - "aarch64"|"s390x") tty= ;; -esac -kargs="$kargs $tty ignition.platform.id=$ignition_platform_id" +kargs="$kargs ignition.platform.id=$ignition_platform_id" qemu-img create -f ${image_format} "${path}.tmp" "${image_size}" @@ -260,18 +251,23 @@ cat >image-dynamic.json << EOF "osname": "${name}", "buildid": "${build}", "imgid": "${img}", - "deploy-container": "${deploy_container}", + "deploy-via-container": "${deploy_via_container}", "container-imgref": "${container_imgref}", "ostree-commit": "${commit}", "ostree-ref": "${ref}", - "ostree-repo": "${ostree_repo}" + "ostree-container": "${ostree_container}" } EOF -cat image-configured.json image-dynamic.json | jq -s add > image.json +cat "${image_json}" image-dynamic.json | jq -s add > image-for-disk.json +platforms_json="${workdir}/tmp/platforms.json" +yaml2json "${configdir}/platforms.yaml" "${platforms_json}" + runvm "${qemu_args[@]}" -- \ /usr/lib/coreos-assembler/create_disk.sh \ - --config "$(pwd)"/image.json \ - --kargs "\"${kargs}\"" \ + --config "$(pwd)"/image-for-disk.json \ + --kargs "${kargs}" \ + --platform "${ignition_platform_id}" \ + --platforms-json "${platforms_json}" \ "${disk_args[@]}" if [[ $secure_execution -eq "1" && -z "${hostkey}" ]]; then @@ -293,12 +289,30 @@ j['images']['${image_type}${image_suffix}'] = { json.dump(j, sys.stdout, indent=4) " | jq -s add > "meta.json.new" +# one more artifact for Secure Execution +if [[ -n "${ignition_pubkey}" ]]; then + gpg_key=${name}-${build}-ignition-secex-key.gpg.pub + python3 -c " +import sys, json +j = json.load(sys.stdin) +j['images']['ignition-gpg-key'] = { + 'path': '${gpg_key}', + 'sha256': '$(sha256sum_str < "${ignition_pubkey}")', + 'size': $(stat -c '%s' "${ignition_pubkey}"), + 'skip-compression': True +} +json.dump(j, sys.stdout, indent=4) +" < "meta.json.new" | jq -s add > "key.json" + mv key.json meta.json.new + /usr/lib/coreos-assembler/finalize-artifact "${ignition_pubkey}" "${builddir}/${gpg_key}" +fi + # and now the crucial bits cosa meta --workdir "${workdir}" --build "${build}" --artifact "${image_type}" --artifact-json "$(readlink -f meta.json.new)" /usr/lib/coreos-assembler/finalize-artifact "${img}" "${builddir}/${img}" # Quiet for the rest of this so the last thing we see is a success message set +x -# clean up the tmpild +# clean up the tmpbuild rm -rf "${tmp_builddir}" echo "Successfully generated: ${img}" diff --git a/src/cmd-generate-release-meta b/src/cmd-generate-release-meta index 3a3a5ec06284bd081cd5f2d9a8a1a64b462d2f80..5466c678709c2cb23b962a864621d159555e052b 100755 --- a/src/cmd-generate-release-meta +++ b/src/cmd-generate-release-meta @@ -158,6 +158,10 @@ def append_build(out, input_): "bucket": cloud_dict[bucket_field], "url": cloud_dict[url_field] } + # IBM Secure Execution specific additions + i = input_.get("images", {}).get("ignition-gpg-key", None) + if i is not None: + arch_dict["media"]["qemu-secex"]["ignition-gpg-key"] = artifact(i) # GCP specific additions if input_.get("gcp", None) is not None: diff --git a/src/create_disk.sh b/src/create_disk.sh index 73afdc7ab0645ab40c6391b9be0792b1101a4e03..e9050428525651809f5e453249116327a8f252b7 100755 --- a/src/create_disk.sh +++ b/src/create_disk.sh @@ -30,6 +30,8 @@ Options: --disk: disk device to use --help: show this help --kargs: kernel CLI args + --platform: Ignition platform ID + --platforms-json: platforms.yaml in JSON format --no-x86-bios-bootloader: don't install BIOS bootloader on x86_64 --with-secure-execution: enable IBM SecureExecution @@ -40,7 +42,10 @@ EOC config= disk= +platform=metal +platforms_json= secure_execution=0 +ignition_pubkey= x86_bios_bootloader=1 extrakargs="" @@ -48,12 +53,15 @@ while [ $# -gt 0 ]; do flag="${1}"; shift; case "${flag}" in - --config) config="${1}"; shift;; + --config) config="${1}"; shift;; --disk) disk="${1}"; shift;; - --help) usage; exit;; - --kargs) extrakargs="${extrakargs} ${1}"; shift;; - --no-x86-bios-bootloader) x86_bios_bootloader=0;; + --help) usage; exit;; + --kargs) extrakargs="${extrakargs} ${1}"; shift;; + --no-x86-bios-bootloader) x86_bios_bootloader=0;; + --platform) platform="${1}"; shift;; + --platforms-json) platforms_json="${1}"; shift;; --with-secure-execution) secure_execution=1;; + --write-ignition-pubkey-to) ignition_pubkey="${1}"; shift;; *) echo "${flag} is not understood."; usage; exit 10;; esac; done @@ -66,6 +74,19 @@ udevtrig() { export PATH=$PATH:/sbin:/usr/sbin arch="$(uname -m)" +if [ -z "$platforms_json" ]; then + echo "Missing --platforms-json" >&2 + exit 1 +fi +# just copy it over to /tmp and work from there to minimize virtiofs I/O +cp "${platforms_json}" /tmp/platforms.json +platforms_json=/tmp/platforms.json +platform_grub_cmds=$(jq -r ".${arch}.${platform}.grub_commands // [] | join(\"\\\\n\")" < "${platforms_json}") +platform_kargs=$(jq -r ".${arch}.${platform}.kernel_arguments // [] | join(\" \")" < "${platforms_json}") +if [ -n "${platform_kargs}" ]; then + extrakargs="${extrakargs} ${platform_kargs}" +fi + disk=$(realpath /dev/disk/by-id/virtio-target) config="${config:?--config must be defined}" @@ -98,12 +119,12 @@ esac bootfs=$(getconfig "bootfs") grub_script=$(getconfig "grub-script") -ostree=$(getconfig "ostree-repo") +ostree_container=$(getconfig "ostree-container") commit=$(getconfig "ostree-commit") ref=$(getconfig "ostree-ref") # We support not setting a remote name (used by RHCOS) remote_name=$(getconfig_def "ostree-remote" "") -deploy_container=$(getconfig "deploy-container" "") +deploy_via_container=$(getconfig "deploy-via-container" "") container_imgref=$(getconfig "container-imgref" "") os_name=$(getconfig "osname") rootfs_size=$(getconfig "rootfs-size") @@ -293,18 +314,18 @@ fi # *not* the shell here. Hence the backslash escape. allkargs="$extrakargs \$ignition_firstboot" -if test -n "${deploy_container}"; then +if test -n "${deploy_via_container}"; then kargsargs="" for karg in $allkargs do kargsargs+="--karg=$karg " done - ostree container image deploy --imgref "${deploy_container}" \ + ostree container image deploy --imgref "${ostree_container}" \ ${container_imgref:+--target-imgref $container_imgref} \ --stateroot "$os_name" --sysroot $rootfs $kargsargs else - # Pull the commit - time ostree pull-local --repo $rootfs/ostree/repo "$ostree" "$commit" + # Pull the container image... + time ostree container image pull $rootfs/ostree/repo "${ostree_container}" # Deploy it, using an optional remote prefix if test -n "${remote_name}"; then deploy_ref="${remote_name}:${ref}" @@ -403,6 +424,17 @@ install_grub_cfg() { fi } +generate_gpgkeys() { + local pkey + pkey="${1}" + local tmp_home + tmp_home=$(mktemp -d /tmp/gpg-XXXXXX) + gpg --homedir "${tmp_home}" --batch --passphrase '' --yes --quick-gen-key "Secure Execution (secex) $buildid" rsa4096 encr none + gpg --homedir "${tmp_home}" --armor --export secex > "${ignition_pubkey}" + gpg --homedir "${tmp_home}" --armor --export-secret-key secex > "${pkey}" + rm -rf "${tmp_home}" +} + # Other arch-specific bootloader changes case "$arch" in x86_64) diff --git a/src/gf-platformid b/src/gf-set-platform similarity index 64% rename from src/gf-platformid rename to src/gf-set-platform index 429ca1beb5ba7b96e946d3cb6234e10bf9402fbb..997178190b8bee3eb9a76ce0c6ec3a73f18d8575 100755 --- a/src/gf-platformid +++ b/src/gf-set-platform @@ -7,8 +7,8 @@ dn=$(dirname "$0") # shellcheck source=src/libguestfish.sh . "${dn}"/libguestfish.sh -# Usage: gf-platformid PLATFORMID -# Example: gf-platformid fedora-coreos.qcow2 fedora-coreos-aws.qcow2 aws +# Usage: gf-set-platform PLATFORMID +# Example: gf-set-platform fedora-coreos.qcow2 fedora-coreos-aws.qcow2 aws # # This will add ignition.platform.id=aws to the bootloader arguments. Intended to # be used for Ignition. It's much faster to do this than generate a fresh image @@ -30,7 +30,7 @@ set -x # See also: # https://github.com/coreos/coreos-assembler/issues/292 # https://github.com/coreos/coreos-assembler/pull/394 -tmpd=$(mktemp -tdp "$(dirname "${dest}")" gf-platformid.XXXXXX) +tmpd=$(mktemp -tdp "$(dirname "${dest}")" gf-set-platform.XXXXXX) tmp_dest=${tmpd}/box.img /usr/lib/coreos-assembler/cp-reflink "${src}" "${tmp_dest}" @@ -41,17 +41,46 @@ coreos_gf_run_mount ro "${tmp_dest}" # We just mount the boot partition writable coreos_gf remount /boot rw:true +# Look up platform-specific configuration +rewrite_grub_cmds= +extra_grub_cmds= +extra_kargs= +remove_kargs= +if [ "$(coreos_gf exists /boot/nestos/platforms.json)" = "true" ]; then + coreos_gf download /boot/nestos/platforms.json "${tmpd}"/platforms.json + rewrite_grub_cmds=1 + extra_grub_cmds=$(jq -r ".${platformid}.grub_commands // [] | join(\"\\\\n\")" < "${tmpd}/platforms.json") + extra_kargs=$(jq -r ".${platformid}.kernel_arguments // [] | join(\" \")" < "${tmpd}/platforms.json") + remove_kargs=$(jq -r ".qemu.kernel_arguments // [] | join(\" \")" < "${tmpd}/platforms.json") +fi + # Inject PLATFORM label in BLS config (for subsequent config regeneration) blscfg_path=$(coreos_gf glob-expand /boot/loader/entries/ostree-*.conf) coreos_gf download "${blscfg_path}" "${tmpd}"/bls.conf # Remove any platformid currently there sed -i -e 's, ignition.platform.id=[a-zA-Z0-9]*,,g' "${tmpd}"/bls.conf sed -i -e '/^options / s,$, ignition.platform.id='"${platformid}"',' "${tmpd}"/bls.conf +if [ -n "$remove_kargs" ]; then + # Remove existing qemu-specific kargs + sed -i -e '/^options / s@ '"${remove_kargs}"'@@' "${tmpd}"/bls.conf +fi +if [ -n "$extra_kargs" ]; then + sed -i -e '/^options / s@$@ '"${extra_kargs}"'@' "${tmpd}"/bls.conf +fi coreos_gf upload "${tmpd}"/bls.conf "${blscfg_path}" +if [ -n "$rewrite_grub_cmds" ]; then + # Remove qemu-specific grub.cfg commands and inject any new ones + coreos_gf download /boot/grub2/grub.cfg "${tmpd}"/grub-orig.cfg + awk '/^# CONSOLE-SETTINGS-START$/ {suspend=1; print} {if (!suspend) print} /^# CONSOLE-SETTINGS-END$/ {suspend=0; print}' "${tmpd}"/grub-orig.cfg | \ + sed -E 's@(^# CONSOLE-SETTINGS-START$)@\1'"${extra_grub_cmds:+\\n${extra_grub_cmds}}"'@' \ + > "${tmpd}"/grub.cfg + coreos_gf upload "${tmpd}"/grub.cfg /boot/grub2/grub.cfg +fi + if [ "$basearch" = "s390x" ] ; then # Before we re-run zipl make sure we have the firstboot options - # A hack similar to https://github.com/coreos/coreos-assembler/blob/main/src/create_disk.sh#L381 + # There's a similar hack in create_disk.sh sed -i -e 's|^\(options .*\)|\1 ignition.firstboot|' "${tmpd}"/bls.conf coreos_gf rename "${blscfg_path}" "${blscfg_path}.orig" coreos_gf upload "${tmpd}"/bls.conf "${blscfg_path}" diff --git a/src/grub.cfg b/src/grub.cfg index 0169c29d2ccc9cab49e6839257a1db8cff4bfea4..c1cbc6d1eccdb14346c253e19fcfe48dc90b2d5a 100644 --- a/src/grub.cfg +++ b/src/grub.cfg @@ -56,9 +56,10 @@ function load_video { fi } -serial --speed=115200 -terminal_input serial console -terminal_output serial console +# Any non-default console settings will be inserted here. +# CONSOLE-SETTINGS-START +# CONSOLE-SETTINGS-END + if [ x$feature_timeout_style = xy ] ; then set timeout_style=menu set timeout=1