From 8fbf6c4e14cca7a7080b658f1e4fb25bdf1ee04f Mon Sep 17 00:00:00 2001 From: Jakob Naucke Date: Mon, 21 Mar 2022 20:20:24 +0100 Subject: [PATCH] osbuilder: Multistrap Ubuntu Use `multistrap` for building Ubuntu rootfs. Adds support for building for foreign architectures using the `ARCH` environment variable (including umoci). In the process, the Ubuntu rootfs workflow is vastly simplified. Signed-off-by: Jakob Naucke --- tools/osbuilder/rootfs-builder/rootfs.sh | 37 +++++-- .../rootfs-builder/ubuntu/Dockerfile.in | 43 +++----- .../osbuilder/rootfs-builder/ubuntu/config.sh | 59 +++++----- .../rootfs-builder/ubuntu/rootfs_lib.sh | 103 +++++------------- tools/osbuilder/scripts/lib.sh | 5 +- 5 files changed, 100 insertions(+), 147 deletions(-) diff --git a/tools/osbuilder/rootfs-builder/rootfs.sh b/tools/osbuilder/rootfs-builder/rootfs.sh index 323c541450..fa2dfad496 100755 --- a/tools/osbuilder/rootfs-builder/rootfs.sh +++ b/tools/osbuilder/rootfs-builder/rootfs.sh @@ -39,7 +39,11 @@ handle_error() { trap 'handle_error $LINENO' ERR # Default architecture -ARCH=$(uname -m) +export ARCH=${ARCH:-$(uname -m)} +if [ "$ARCH" == "ppc64le" ] || [ "$ARCH" == "s390x" ]; then + LIBC=gnu + echo "WARNING: Forcing LIBC=gnu because $ARCH has no musl Rust target" +fi # distro-specific config file typeset -r CONFIG_SH="config.sh" @@ -103,6 +107,11 @@ AGENT_SOURCE_BIN Path to the directory of agent binary. AGENT_VERSION Version of the agent to include in the rootfs. Default value: ${AGENT_VERSION:-} +ARCH Target architecture (according to \`uname -m\`). + Foreign bootstraps are currently only supported for Ubuntu + and glibc agents. + Default value: $(uname -m) + DISTRO_REPO Use host repositories to install guest packages. Default value: @@ -428,6 +437,7 @@ build_rootfs_distro() --env ROOTFS_DIR="/rootfs" \ --env AGENT_BIN="${AGENT_BIN}" \ --env AGENT_INIT="${AGENT_INIT}" \ + --env ARCH="${ARCH}" \ --env CI="${CI}" \ --env KERNEL_MODULES_DIR="${KERNEL_MODULES_DIR}" \ --env LIBC="${LIBC}" \ @@ -560,11 +570,6 @@ EOF AGENT_DIR="${ROOTFS_DIR}/usr/bin" AGENT_DEST="${AGENT_DIR}/${AGENT_BIN}" - if [ "$ARCH" == "ppc64le" ] || [ "$ARCH" == "s390x" ]; then - LIBC=gnu - warning "Forcing LIBC=gnu because $ARCH has no musl Rust target" - fi - if [ -z "${AGENT_SOURCE_BIN}" ] ; then test -r "${HOME}/.cargo/env" && source "${HOME}/.cargo/env" # rust agent needs ${arch}-unknown-linux-${LIBC} @@ -583,7 +588,7 @@ EOF info "Set up libseccomp" libseccomp_install_dir=$(mktemp -d -t libseccomp.XXXXXXXXXX) gperf_install_dir=$(mktemp -d -t gperf.XXXXXXXXXX) - bash ${script_dir}/../../../ci/install_libseccomp.sh "${libseccomp_install_dir}" "${gperf_install_dir}" + ${script_dir}/../../../ci/install_libseccomp.sh "${libseccomp_install_dir}" "${gperf_install_dir}" echo "Set environment variables for the libseccomp crate to link the libseccomp library statically" export LIBSECCOMP_LINK_TYPE=static export LIBSECCOMP_LIB_PATH="${libseccomp_install_dir}/lib" @@ -667,16 +672,28 @@ EOF source "${HOME}/.cargo/env" target="${ARCH}-unknown-linux-${LIBC}" if [ "${AA_KBC}" == "eaa_kbc" ] && [ "${ARCH}" == "x86_64" ]; then - AA_RUSTFLAG="-C link-args=-Wl,-rpath,/usr/local/lib/rats-tls" + RUSTFLAGS="-C link-args=-Wl,-rpath,/usr/local/lib/rats-tls" # Currently eaa_kbc module only support this specific platform target="x86_64-unknown-linux-gnu" fi - RUSTFLAGS=${AA_RUSTFLAG} cargo build --release --target "${target}" --no-default-features --features "${AA_KBC}" - install -o root -g root -m 0755 "target/${target}/release/attestation-agent" "${ROOTFS_DIR}/usr/local/bin/" + if [ "$(uname -m)" != "$ARCH" ]; then + RUSTFLAGS+=" -C linker=$CC" + fi + export RUSTFLAGS + # Foreign CC is incompatible with libgit2 -- CC is still handled by `-C linker=...` flag + CC= cargo build --release --target "${target}" --no-default-features --features "${AA_KBC}" + install -D -o root -g root -m 0755 "target/${target}/release/attestation-agent" -t "${ROOTFS_DIR}/usr/local/bin/" popd fi if [ "${UMOCI}" = "yes" ]; then + case "$ARCH" in + aarch64) GOARCH=arm64;; + x86_64) GOARCH=amd64;; + *) GOARCH="$ARCH" + esac + export GOARCH + umoci_url="$(get_package_version_from_kata_yaml externals.umoci.url)" umoci_tag="$(get_package_version_from_kata_yaml externals.umoci.tag)" info "Install umoci" diff --git a/tools/osbuilder/rootfs-builder/ubuntu/Dockerfile.in b/tools/osbuilder/rootfs-builder/ubuntu/Dockerfile.in index c0fffd07eb..25d1907a6f 100644 --- a/tools/osbuilder/rootfs-builder/ubuntu/Dockerfile.in +++ b/tools/osbuilder/rootfs-builder/ubuntu/Dockerfile.in @@ -1,51 +1,36 @@ -# -# Copyright (c) 2018 Yash Jain +# Copyright (c) 2018 Yash Jain, 2022 IBM Corp. # # SPDX-License-Identifier: Apache-2.0 ARG IMAGE_REGISTRY=docker.io -#ubuntu: docker image to be used to create a rootfs -#@OS_VERSION@: Docker image version to build this dockerfile FROM ${IMAGE_REGISTRY}/ubuntu:@OS_VERSION@ +@SET_PROXY@ -# This dockerfile needs to provide all the componets need to build a rootfs -# Install any package need to create a rootfs (package manager, extra tools) - -# RUN commands -RUN apt-get update && apt-get --no-install-recommends install -y \ - apt-utils \ - autoconf \ - automake \ - binutils \ - build-essential \ +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive \ + apt-get --no-install-recommends -y install \ ca-certificates \ - chrony \ - coreutils \ curl \ - debianutils \ - debootstrap \ g++ \ - gcc \ + $(gcc_arch="@ARCH@" && [ "$(uname -m)" != "$gcc_arch" ] && ( \ + libc_arch="$gcc_arch" && \ + [ "$gcc_arch" = aarch64 ] && libc_arch=arm64; \ + [ "$gcc_arch" = ppc64le ] && gcc_arch=powerpc64le && libc_arch=ppc64el; \ + [ "$gcc_arch" = x86_64 ] && gcc_arch=x86-64 && libc_arch=amd64; \ + echo "gcc-$gcc_arch-linux-gnu libc6-dev-$libc_arch-cross")) \ git \ golang-go \ libdevmapper-dev \ - libc6-dev \ libgpgme-dev \ libssl-dev \ - libstdc++-8-dev \ - m4 \ make \ + multistrap \ musl-tools \ pkg-config \ - protobuf-compiler \ - sed \ - systemd \ - tar \ - vim \ - wget + protobuf-compiler + # aarch64 requires this name -- link for all RUN ln -s /usr/bin/musl-gcc "/usr/bin/$(uname -m)-linux-musl-gcc" -# This will install the proper packages to build Kata components @INSTALL_RUST@ @INSTALL_AA_KBC@ diff --git a/tools/osbuilder/rootfs-builder/ubuntu/config.sh b/tools/osbuilder/rootfs-builder/ubuntu/config.sh index 3c4dbb9319..d9e249f8d0 100644 --- a/tools/osbuilder/rootfs-builder/ubuntu/config.sh +++ b/tools/osbuilder/rootfs-builder/ubuntu/config.sh @@ -1,46 +1,39 @@ -# This is a configuration file add extra variables to -# -# Copyright (c) 2018 Yash Jain +# Copyright (c) 2018 Yash Jain, 2022 IBM Corp. # # SPDX-License-Identifier: Apache-2.0 -# be used by build_rootfs() from rootfs_lib.sh the variables will be -# loaded just before call the function. For more information see the -# rootfs-builder/README.md file. -OS_VERSION=${OS_VERSION:-20.04} +OS_NAME=ubuntu # This should be Ubuntu's code name, e.g. "focal" (Focal Fossa) for 20.04 -OS_NAME=${OS_NAME:-"focal"} +OS_VERSION=${OS_VERSION:-focal} +PACKAGES=chrony +[ "$AGENT_INIT" = no ] && PACKAGES+=" init" +[ "$SECCOMP" = yes ] && PACKAGES+=" libseccomp2" +[ "$SKOPEO" = yes ] && PACKAGES+=" libgpgme11" +REPO_URL=http://ports.ubuntu.com -# packages to be installed by default -# Note: ca-certificates is required for confidential containers -# to pull the container image on the guest -PACKAGES="systemd coreutils init kmod ca-certificates" -EXTRA_PKGS+=" chrony" - -DEBOOTSTRAP=${PACKAGE_MANAGER:-"debootstrap"} - -case $(uname -m) in - x86_64) ARCHITECTURE="amd64";; - ppc64le) ARCHITECTURE="ppc64el";; - aarch64) ARCHITECTURE="arm64";; - s390x) ARCHITECTURE="s390x";; - (*) die "$(uname -m) not supported " +case "$ARCH" in + aarch64) DEB_ARCH=arm64;; + ppc64le) DEB_ARCH=ppc64el;; + s390x) DEB_ARCH="$ARCH";; + x86_64) DEB_ARCH=amd64; REPO_URL=http://archive.ubuntu.com/ubuntu;; + *) die "$ARCH not supported" esac -# Init process must be one of {systemd,kata-agent} -INIT_PROCESS=systemd -# List of zero or more architectures to exclude from build, -# as reported by `uname -m` -ARCH_EXCLUDE_LIST=() - -[ "$SECCOMP" = "yes" ] && PACKAGES+=" libseccomp2" || true -[ "$SKOPEO" = "yes" ] && PACKAGES+=" libgpgme11" || true - if [ "${AA_KBC}" == "eaa_kbc" ] && [ "${ARCH}" == "x86_64" ]; then - AA_KBC_EXTRAS=" + PACKAGES+=" apt gnupg" + AA_KBC_EXTRAS=" RUN echo 'deb [arch=amd64] http://mirrors.openanolis.cn/inclavare-containers/ubuntu20.04 bionic main' \| tee /etc/apt/sources.list.d/inclavare-containers.list; \ - wget -qO - http://mirrors.openanolis.cn/inclavare-containers/ubuntu20.04/DEB-GPG-KEY.key \| apt-key add -; \ + curl -L http://mirrors.openanolis.cn/inclavare-containers/ubuntu20.04/DEB-GPG-KEY.key \| apt-key add -; \ apt-get update; \ apt-get install -y rats-tls " fi + +if [ "$(uname -m)" != "$ARCH" ]; then + case "$ARCH" in + ppc64le) cc_arch=powerpc64le;; + x86_64) cc_arch=x86-64;; + *) cc_arch="$ARCH" + esac + export CC="$cc_arch-linux-gnu-gcc" +fi diff --git a/tools/osbuilder/rootfs-builder/ubuntu/rootfs_lib.sh b/tools/osbuilder/rootfs-builder/ubuntu/rootfs_lib.sh index 4e048ca6a0..90c13dd0a0 100644 --- a/tools/osbuilder/rootfs-builder/ubuntu/rootfs_lib.sh +++ b/tools/osbuilder/rootfs-builder/ubuntu/rootfs_lib.sh @@ -1,84 +1,41 @@ -# - Arguments -# -# Copyright (c) 2018 Yash Jain +# Copyright (c) 2018 Yash Jain, 2022 IBM Corp. # # SPDX-License-Identifier: Apache-2.0 -# -# -# rootfs_dir=$1 -# -# - Optional environment variables -# -# EXTRA_PKGS: Variable to add extra PKGS provided by the user -# -# BIN_AGENT: Name of the Kata-Agent binary -# -# REPO_URL: URL to distribution repository ( should be configured in -# config.sh file) -# -# Any other configuration variable for a specific distro must be added -# and documented on its own config.sh -# -# - Expected result -# -# rootfs_dir populated with rootfs pkgs -# It must provide a binary in /sbin/init -# + build_rootfs() { - # Mandatory - local ROOTFS_DIR=$1 + local rootfs_dir=$1 + local multistrap_conf=multistrap.conf - # Name of the Kata-Agent binary - local BIN_AGENT=${BIN_AGENT} + [ -z "$rootfs_dir" ] && die "need rootfs" + [ "$rootfs_dir" = "/" ] && die "rootfs cannot be slash" - # In case of support EXTRA packages, use it to allow - # users to add more packages to the base rootfs - local EXTRA_PKGS=${EXTRA_PKGS:-} + # For simplicity's sake, use multistrap for foreign and native bootstraps. + cat > "$multistrap_conf" << EOF +[General] +cleanup=true +aptsources=Ubuntu +bootstrap=Ubuntu - # In case rootfs is created using repositories allow user to modify - # the default URL - local REPO_URL=${REPO_URL:-YOUR_REPO} +[Ubuntu] +source=$REPO_URL +keyring=ubuntu-keyring +suite=focal +packages=$PACKAGES $EXTRA_PKGS +EOF + multistrap -a "$DEB_ARCH" -d "$rootfs_dir" -f "$multistrap_conf" + rm -rf "$rootfs_dir/var/run" + ln -s /run "$rootfs_dir/var/run" + for file in /etc/{resolv.conf,ssl/certs/ca-certificates.crt}; do + mkdir -p "$rootfs_dir$(dirname $file)" + cp --remove-destination "$file" "$rootfs_dir$file" + done - # PATH where files this script is placed - # Use it to refer to files in the same directory - # Example: ${CONFIG_DIR}/foo - local CONFIG_DIR=${CONFIG_DIR} + # Reduce image size and memory footprint by removing unnecessary files and directories. + rm -rf $rootfs_dir/usr/share/{bash-completion,bug,doc,info,lintian,locale,man,menu,misc,pixmaps,terminfo,zsh} - - # Populate ROOTFS_DIR - # Must provide /sbin/init and /bin/${BIN_AGENT} - DEBOOTSTRAP="debootstrap" - check_root - mkdir -p "${ROOTFS_DIR}" - if [ -n "${PKG_MANAGER}" ]; then - info "debootstrap path provided by user: ${PKG_MANAGER}" - elif check_program $DEBOOTSTRAP ; then - PKG_MANAGER=$DEBOOTSTRAP - else - die "$DEBOOTSTRAP is not installed" - fi - # trim whitespace - PACKAGES=$(echo $PACKAGES |xargs ) - # add comma as debootstrap needs , separated package names. - # Don't change $PACKAGES in config.sh to include ',' - # This is done to maintain consistency - PACKAGES=$(echo $PACKAGES | sed -e 's/ /,/g' ) - - ${PKG_MANAGER} --variant=minbase \ - --arch=${ARCHITECTURE}\ - --include="$PACKAGES" \ - ${OS_NAME} \ - ${ROOTFS_DIR} - - [ -n "${EXTRA_PKGS}" ] && chroot $ROOTFS_DIR apt-get install -y ${EXTRA_PKGS} - - # Reduce image size and memory footprint - # removing not needed files and directories. - chroot $ROOTFS_DIR rm -rf /usr/share/{bash-completion,bug,doc,info,lintian,locale,man,menu,misc,pixmaps,terminfo,zoneinfo,zsh} - - if [ "${AA_KBC}" == "eaa_kbc" ] && [ "${ARCH}" == "x86_64" ]; then - wget -qO - http://mirrors.openanolis.cn/inclavare-containers/ubuntu20.04/DEB-GPG-KEY.key | chroot $ROOTFS_DIR apt-key add - - cat << EOF | chroot $ROOTFS_DIR + if [ "${AA_KBC}" == "eaa_kbc" ] && [ "${ARCH}" == "x86_64" ]; then + curl -L http://mirrors.openanolis.cn/inclavare-containers/ubuntu20.04/DEB-GPG-KEY.key | chroot "$rootfs_dir" apt-key add - + cat << EOF | chroot "$rootfs_dir" echo 'deb [arch=amd64] http://mirrors.openanolis.cn/inclavare-containers/ubuntu20.04 bionic main' | tee /etc/apt/sources.list.d/inclavare-containers.list apt-get update apt-get install -y rats-tls diff --git a/tools/osbuilder/scripts/lib.sh b/tools/osbuilder/scripts/lib.sh index 5601a5b2b6..7ee6b79986 100644 --- a/tools/osbuilder/scripts/lib.sh +++ b/tools/osbuilder/scripts/lib.sh @@ -227,8 +227,8 @@ generate_dockerfile() dir="$1" [ -d "${dir}" ] || die "${dir}: not a directory" - local rustarch=$(uname -m) - [ "$rustarch" = ppc64le ] && rustarch=powerpc64le + local rustarch="$ARCH" + [ "$ARCH" = ppc64le ] && rustarch=powerpc64le [ -n "${http_proxy:-}" ] && readonly set_proxy="RUN sed -i '$ a proxy="${http_proxy:-}"' /etc/dnf/dnf.conf /etc/yum.conf; true" @@ -244,6 +244,7 @@ RUN . /root/.cargo/env; cargo install cargo-when sed \ -e "s#@OS_VERSION@#${OS_VERSION:-}#g" \ + -e "s#@ARCH@#$ARCH#g" \ -e "s#@INSTALL_RUST@#${install_rust//$'\n'/\\n}#g" \ -e "s#@SET_PROXY@#${set_proxy:-}#g" \ -e "s#@INSTALL_AA_KBC@#${AA_KBC_EXTRAS//$'\n'/\\n}#g" \