Skip to content

Commit

Permalink
Do SB signing for official builds in a separate additional job
Browse files Browse the repository at this point in the history
We only want to do the signing in Azure, not the whole image job. This
new job downloads the unsigned image, signs it, and replaces it.

Signed-off-by: James Le Cuirot <jlecuirot@microsoft.com>
  • Loading branch information
chewi committed Dec 2, 2024
1 parent c1801e4 commit 86f6f9b
Show file tree
Hide file tree
Showing 5 changed files with 268 additions and 6 deletions.
73 changes: 69 additions & 4 deletions build_library/build_image_util.sh
Original file line number Diff line number Diff line change
Expand Up @@ -791,10 +791,12 @@ EOF
seek=${verity_offset} count=64 bs=1 status=none
fi

# Sign the kernel after /usr is in a consistent state and verity is calculated
[[ ${COREOS_OFFICIAL:-0} -ne 1 ]] && \
do_sbsign --output "${root_fs_dir}/boot/flatcar/vmlinuz-a"{,}
cleanup_sbsign_certs
# Sign the kernel after /usr is in a consistent state and verity is
# calculated. Only for unofficial builds as official builds get signed later.
if [[ ${COREOS_OFFICIAL:-0} -ne 1 ]]; then
do_sbsign --output "${root_fs_dir}/boot/flatcar/vmlinuz-a"{,}
cleanup_sbsign_certs
fi

if [[ -n "${image_kernel}" ]]; then
# copying kernel from vfat so ignore the permissions
Expand Down Expand Up @@ -880,3 +882,66 @@ EOF
cleanup_mounts "${root_fs_dir}"
trap - EXIT
}

sbsign_image() {
local image_name="$1"
local disk_layout="$2"
local root_fs_dir="$3"
local image_kernel="$4"
local pcr_policy="$5"
local image_grub="$6"

local disk_img="${BUILD_DIR}/${image_name}"
local EFI_ARCH

case "${FLAGS_board}" in
amd64-usr) EFI_ARCH="x64" ;;
arm64-usr) EFI_ARCH="aa64" ;;
esac

"${BUILD_LIBRARY_DIR}/disk_util" --disk_layout="${disk_layout}" \
mount "${disk_img}" "${root_fs_dir}"
trap "cleanup_mounts '${root_fs_dir}'; cleanup_sbsign_certs" EXIT

# Sign the kernel with the shim-embedded key.
do_sbsign --output "${root_fs_dir}/boot/flatcar/vmlinuz-a"{,}

if [[ -n "${image_kernel}" ]]; then
# copying kernel from vfat so ignore the permissions
cp --no-preserve=mode \
"${root_fs_dir}/boot/flatcar/vmlinuz-a" \
"${BUILD_DIR}/${image_kernel}"
fi

# Sign GRUB and mokmanager(mm) with the shim-embedded key.
do_sbsign --output "${root_fs_dir}/boot/EFI/boot/grub${EFI_ARCH}.efi"{,}
do_sbsign --output "${root_fs_dir}/boot/EFI/boot/mm${EFI_ARCH}.efi"{,}

# copying from vfat so ignore permissions
if [[ -n "${image_grub}" ]]; then
cp --no-preserve=mode "${root_fs_dir}/boot/EFI/boot/grub${EFI_ARCH}.efi" \
"${BUILD_DIR}/${image_grub}"
fi

if [[ -n "${pcr_policy}" ]]; then
mkdir -p "${BUILD_DIR}/pcrs"
"${BUILD_LIBRARY_DIR}"/generate_kernel_hash.py \
"${root_fs_dir}/boot/flatcar/vmlinuz-a" "${FLATCAR_VERSION}" \
>"${BUILD_DIR}/pcrs/kernel.config"
fi

cleanup_mounts "${root_fs_dir}"
cleanup_sbsign_certs
trap - EXIT

if [[ -n "${pcr_policy}" ]]; then
"${BUILD_LIBRARY_DIR}"/generate_grub_hashes.py \
"${disk_img}" /usr/lib/grub/ "${BUILD_DIR}/pcrs" "${FLATCAR_VERSION}"

info "Generating $pcr_policy"
pushd "${BUILD_DIR}" >/dev/null
zip --quiet -r -9 "${BUILD_DIR}/${pcr_policy}" pcrs
popd >/dev/null
rm -rf "${BUILD_DIR}/pcrs"
fi
}
4 changes: 2 additions & 2 deletions build_library/grub_install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,10 @@ case "${FLAGS_target}" in
--output "${ESP_DIR}/EFI/boot/boot${EFI_ARCH}.efi" \
"${BOARD_ROOT}/usr/lib/shim/shim${EFI_ARCH}.efi"
else
# Official build: Copy the unsigned files.
# Official build: Copy signed shim and mm for signing later.
sudo cp "${BOARD_ROOT}/usr/lib/shim/mm${EFI_ARCH}.efi" \
"${ESP_DIR}/EFI/boot/mm${EFI_ARCH}.efi"
sudo cp "${BOARD_ROOT}/usr/lib/shim/shim${EFI_ARCH}.efi" \
sudo cp "${BOARD_ROOT}/usr/lib/shim/shim${EFI_ARCH}.efi.signed" \
"${ESP_DIR}/EFI/boot/boot${EFI_ARCH}.efi"
fi

Expand Down
32 changes: 32 additions & 0 deletions build_library/prod_image_util.sh
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,15 @@ EOF
"${image_initrd_contents_wtd}" \
"${image_disk_usage}"

# Official builds will sign and upload these files later, so remove them to
# prevent them from being uploaded now.
if [[ ${COREOS_OFFICIAL:-0} -eq 1 ]]; then
rm -v \
"${BUILD_DIR}/${image_kernel}" \
"${BUILD_DIR}/${image_pcr_policy}" \
"${BUILD_DIR}/${image_grub}"
fi

local files_to_evaluate=( "${BUILD_DIR}/${image_name}" )
compress_disk_images files_to_evaluate
}
Expand Down Expand Up @@ -225,3 +234,26 @@ create_prod_sysexts() {
-out_file "${BUILD_DIR}/flatcar_test_update-${name}.gz"
done
}

sbsign_prod_image() {
local image_name="$1"
local disk_layout="$2"

info "Signing production image ${image_name} for Secure Boot"
local root_fs_dir="${BUILD_DIR}/rootfs"
local image_prefix="${image_name%.bin}"
local image_kernel="${image_prefix}.vmlinuz"
local image_pcr_policy="${image_prefix}_pcr_policy.zip"
local image_grub="${image_prefix}.grub"

sbsign_image \
"${image_name}" \
"${disk_layout}" \
"${root_fs_dir}" \
"${image_kernel}" \
"${image_pcr_policy}" \
"${image_grub}"

local files_to_evaluate=( "${BUILD_DIR}/${image_name}" )
compress_disk_images files_to_evaluate
}
97 changes: 97 additions & 0 deletions ci-automation/sbsign_image.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/bin/bash
#
# Copyright (c) 2024 The Flatcar Maintainers.
# Use of this source code is governed by the Apache 2.0 license.

# >>> This file is supposed to be SOURCED from the repository ROOT. <<<
#
# sbsign_image() should be called w/ the positional INPUT parameters below.

# Secure Boot image signing build automation stub.
# This script will sign an existing OS image for Secure Boot.
#
# PREREQUISITES:
#
# 1. SDK version and OS image version are recorded in sdk_container/.repo/manifests/version.txt
# 2. Scripts repo version tag of OS image version to be built is available and checked out.
# 3. The generic Flatcar image must be present in build cache server.
#
# INPUT:
#
# 1. Architecture (ARCH) of the TARGET vm images ("arm64", "amd64").
#
# OPTIONAL INPUT:
#
# 1. SIGNER. Environment variable. Name of the owner of the artifact signing key.
# Defaults to nothing if not set - in such case, artifacts will not be signed.
# If provided, SIGNING_KEY environment variable should also be provided, otherwise this environment variable will be ignored.
#
# 2. SIGNING_KEY. Environment variable. The artifact signing key.
# Defaults to nothing if not set - in such case, artifacts will not be signed.
# If provided, SIGNER environment variable should also be provided, otherwise this environment variable will be ignored.
#
# 3. A file ../scripts.patch to apply with "git am -3" for the scripts repo.
#
# OUTPUT:
#
# 1. OS image and related artifacts signed for Secure Boot pushed to buildcache.
# 2. If signer key was passed, signatures of artifacts from point 1, pushed along to buildcache.
# 3. DIGESTS of the artifacts from point 1, pushed to buildcache. If signer key was passed, armored ASCII files of the generated DIGESTS files too, pushed to buildcache.

function sbsign_image() {
# Run a subshell, so the traps, environment changes and global
# variables are not spilled into the caller.
(
set -euo pipefail

_sbsign_image_impl "${@}"
)
}
# --

function _sbsign_image_impl() {
local arch="$1"

source sdk_lib/sdk_container_common.sh
local channel=""
channel="$(get_git_channel)"
source ci-automation/ci_automation_common.sh
source ci-automation/gpg_setup.sh
source sdk_container/.repo/manifests/version.txt

if is_official "${FLATCAR_VERSION}"; then
export COREOS_OFFICIAL=1
else
export COREOS_OFFICIAL=0
fi

apply_local_patches

local images_remote="images/${arch}/${FLATCAR_VERSION}"
local images_local="__build__/images/images/${arch}-usr/${channel}-${FLATCAR_VERSION}"

copy_from_buildcache "${images_remote}/flatcar_production_image.bin.bz2" "${images_local}"
lbunzip2 --force "${images_local}/flatcar_production_image.bin.bz2"

# Get SDK from either the registry or import from build cache
# This is a NOP if the image is present locally.
local sdk_name="flatcar-sdk-${arch}"
local docker_sdk_vernum="$(vernum_to_docker_image_version "${FLATCAR_SDK_VERSION}")"

docker_image_from_registry_or_buildcache "${sdk_name}" "${docker_sdk_vernum}"
local sdk_image="$(docker_image_fullname "${sdk_name}" "${docker_sdk_vernum}")"
echo "docker image rm -f '${sdk_image}'" >> ./ci-cleanup.sh

./run_sdk_container -x ./ci-cleanup.sh -v "${FLATCAR_VERSION}" -U -C "${sdk_image}" \
./sbsign_image --board="${arch}-usr" \
--group="${channel}" --version="${FLATCAR_VERSION}" \
--output_root="${CONTAINER_IMAGE_ROOT}" \
--only_store_compressed

# Delete uncompressed generic image before signing and upload
rm "${images_local}/flatcar_production_image.bin"
create_digests "${SIGNER}" "${images_local}"/*
sign_artifacts "${SIGNER}" "${images_local}"/*
copy_to_buildcache "${images_remote}"/ "${images_local}"/*
}
# --
68 changes: 68 additions & 0 deletions sbsign_image
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/bin/bash

# Copyright (c) 2024 The Flatcar Maintainers.
# Use of this source code is governed by the Apache 2.0 license.

# Script to sign an existing raw Flatcar disk image for Secure Boot.

SCRIPT_ROOT=$(dirname "$(readlink -f "$0")")
. "${SCRIPT_ROOT}/common.sh" || exit 1

# Script must run inside the chroot
assert_inside_chroot

assert_not_root_user

DEFAULT_GROUP=developer

# Developer-visible flags.
DEFINE_string board "${DEFAULT_BOARD}" \
"The board to build an image for."
DEFINE_string output_root "${DEFAULT_BUILD_ROOT}/images" \
"Directory in which to place image result directories (named by version)"
DEFINE_string disk_layout "" \
"The disk layout type to use for this image."
DEFINE_string group "${DEFAULT_GROUP}" \
"The update group."

# include upload options
. "${BUILD_LIBRARY_DIR}/release_util.sh" || exit 1

FLAGS_HELP="USAGE: sbsign_image [flags]
This script is used to sign the GRUB and kernel images within an
existing raw Flatcar disk image for Secure Boot. The disk image is
read from the output directory and modified in-place. The signed GRUB
and kernel images are also written separately to the same directory.
"
show_help_if_requested "$@"

# The following options are advanced options, only available to those willing
# to read the source code. They are not shown in help output, since they are
# not needed for the typical developer workflow.
DEFINE_integer build_attempt 1 \
"The build attempt for this image build."
DEFINE_string version "" \
"Overrides version number in name to this version."

# Parse command line.
FLAGS "$@" || exit 1

# Only now can we die on error. shflags functions leak non-zero error codes,
# so will die prematurely if 'switch_to_strict_mode' is specified before now.
switch_to_strict_mode

# N.B. Ordering matters for some of the libraries below, because
# some of the files contain initialization used by later files.
. "${BUILD_LIBRARY_DIR}/toolchain_util.sh" || exit 1
. "${BUILD_LIBRARY_DIR}/board_options.sh" || exit 1
. "${BUILD_LIBRARY_DIR}/build_image_util.sh" || exit 1
. "${BUILD_LIBRARY_DIR}/prod_image_util.sh" || exit 1

# Create the output directory and temporary mount points.
mkdir -p "${BUILD_DIR}"

fix_mtab
sbsign_prod_image "${FLATCAR_PRODUCTION_IMAGE_NAME}" "${FLAGS_disk_layout:-base}"

echo "Done. ${FLATCAR_PRODUCTION_IMAGE_NAME} and associated files are now signed for Secure Boot in ${BUILD_DIR}."
command_completed

0 comments on commit 86f6f9b

Please # to comment.