diff --git a/.github/workflows/run-kola-tests.yaml b/.github/workflows/run-kola-tests.yaml index f2da99351f2..7cf4dad3ed0 100644 --- a/.github/workflows/run-kola-tests.yaml +++ b/.github/workflows/run-kola-tests.yaml @@ -182,7 +182,6 @@ jobs: PARALLEL_ARCH=5 - cat > sdk_container/.env < sys-auth/sssd -> sys-apps/shadow[pam] -> sys-auth/pambase - break_dep_loop sys-apps/util-linux cryptsetup,pam,systemd,udev \ + break_dep_loop sys-apps/util-linux cryptsetup,pam,su,systemd,udev \ sys-fs/cryptsetup udev \ sys-fs/lvm2 systemd,udev \ sys-apps/systemd audit,cryptsetup,pam,selinux,tpm \ diff --git a/build_sdk_container_image b/build_sdk_container_image index 7321f09cd30..d3e3cb89415 100755 --- a/build_sdk_container_image +++ b/build_sdk_container_image @@ -229,7 +229,7 @@ else docker_build -t "${sdk_build_image}" \ --build-arg VERSION="${docker_vernum}" \ --build-arg BINHOST="http://${binhost}" \ - --build-arg OFFICIAL="${official}" \ + --build-arg COREOS_OFFICIAL="${official}" \ -f sdk_lib/Dockerfile.sdk-build \ . diff --git a/changelog/changes/2026-10-02-su.md b/changelog/changes/2026-10-02-su.md new file mode 100644 index 00000000000..4805e65576b --- /dev/null +++ b/changelog/changes/2026-10-02-su.md @@ -0,0 +1 @@ +- Switched from shadow's su implementation to util-linux's, as the former is deprecated upstream. diff --git a/ci-automation/ci-config.env b/ci-automation/ci-config.env index bb9990591e7..a3239e044bd 100644 --- a/ci-automation/ci-config.env +++ b/ci-automation/ci-config.env @@ -40,11 +40,6 @@ CONTAINER_IMAGE_ROOT="/home/sdk/trunk/src/build/images" # NOTE that these settings are evaluated by the vendor-tests script inside the # SDK container. To override, new values must be passed into the container. -# Use something like -# echo "export [VAR]=\"${[VALUE]}\\"" > sdk_container/.env -# in your CI to override, e.g. -# echo "export PARALLEL_TESTS=\"5\"" > sdk_container/.env -# to override the number of test cases to be run in parallel. # -- General -- @@ -81,10 +76,6 @@ QEMU_DEVCONTAINER_URL="${QEMU_DEVCONTAINER_URL:-}" QEMU_DEVCONTAINER_BINHOST_URL="${QEMU_DEVCONTAINER_BINHOST_URL:-}" QEMU_DEVCONTAINER_FILE="${QEMU_DEVCONTAINER_FILE:-}" -# -- PXE -- -PXE_KERNEL_NAME="flatcar_production_pxe.vmlinuz" -PXE_IMAGE_NAME="flatcar_production_pxe_image.cpio.gz" - GCE_IMAGE_NAME="flatcar_production_gce.tar.gz" GCE_GCS_IMAGE_UPLOAD="gs://flatcar-jenkins/developer/gce-ci" GCE_MACHINE_TYPE="${GCE_MACHINE_TYPE:-n1-standard-2}" @@ -99,13 +90,13 @@ GCE_PARALLEL="${PARALLEL_TESTS:-4}" : ${DIGITALOCEAN_MACHINE_SIZE:='s-2vcpu-2gb'} DIGITALOCEAN_PARALLEL="${PARALLEL_TESTS:-8}" # DIGITALOCEAN_TOKEN_JSON env var is used for credentials, and should -# come from sdk_container/.env. It must be base64-encoded. +# come from the caller. It must be base64-encoded. # -- VMware ESX -- : ${VMWARE_ESX_IMAGE_NAME:='flatcar_production_vmware_ova.ova'} VMWARE_ESX_PARALLEL="${PARALLEL_TESTS:-4}" -# VMWARE_ESX_CREDS should come from sdk_container/.env and must be +# VMWARE_ESX_CREDS should come from the caller and must be # base64-encoded. # -- AWS -- @@ -122,8 +113,7 @@ VMWARE_ESX_PARALLEL="${PARALLEL_TESTS:-4}" : ${AWS_REGION:="us-east-1"} : ${AWS_AMI_ID:=""} AWS_PARALLEL="${PARALLEL_TESTS:-8}" -# AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY should come from -# sdk_container/.env +# AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY should come from the caller. # -- Azure -- : ${AZURE_IMAGE_NAME:="flatcar_production_azure_image.vhd"} @@ -132,7 +122,6 @@ AWS_PARALLEL="${PARALLEL_TESTS:-8}" : ${AZURE_USE_GALLERY:=""} : ${AZURE_KOLA_VNET:=""} : ${AZURE_USE_PRIVATE_IPS:=true} -: ${AZURE_VNET_SUBNET_NAME:="jenkins-vnet-westeurope"} AZURE_PARALLEL="${PARALLEL_TESTS:-20}" AZURE_LOCATION="${AZURE_LOCATION:-westeurope}" diff --git a/ci-automation/garbage_collect.sh b/ci-automation/garbage_collect.sh index 1d33dc8dc2c..850907d852b 100644 --- a/ci-automation/garbage_collect.sh +++ b/ci-automation/garbage_collect.sh @@ -255,21 +255,7 @@ function _garbage_collect_impl() { local mantle_ref mantle_ref=$(cat sdk_container/.repo/manifests/mantle-container) - docker run --pull always --rm --net host \ - --env AWS_ACCESS_KEY_ID --env AWS_SECRET_ACCESS_KEY \ - --env AWS_CREDENTIALS \ - --env DIGITALOCEAN_TOKEN_JSON \ - --env GCP_JSON_KEY \ - --env VMWARE_ESX_CREDS \ - --env BRIGHTBOX_CLIENT_ID --env BRIGHTBOX_CLIENT_SECRET \ - --env AKAMAI_TOKEN \ - --env STACKIT_SERVICE_ACCOUNT \ - --env STACKIT_PROJECT_ID \ - --env ORACLECLOUD_TENANCY \ - --env ORACLECLOUD_USER \ - --env ORACLECLOUD_FINGERPRINT \ - --env ORACLECLOUD_PRIVATE_KEY \ - --env ORACLECLOUD_COMPARTMENT_ID \ + docker run --pull always --rm --net host --env-file="sdk_lib/env_mantle.txt" \ -w /work -v "$PWD":/work "${mantle_ref}" /work/ci-automation/garbage_collect_cloud.sh echo diff --git a/ci-automation/garbage_collect_cloud.sh b/ci-automation/garbage_collect_cloud.sh index 68a3edfb2c1..4ebfa107ed0 100755 --- a/ci-automation/garbage_collect_cloud.sh +++ b/ci-automation/garbage_collect_cloud.sh @@ -2,14 +2,14 @@ set -euo pipefail source ci-automation/ci_automation_common.sh timeout --signal=SIGQUIT 60m ore aws gc --access-id "${AWS_ACCESS_KEY_ID}" --secret-key "${AWS_SECRET_ACCESS_KEY}" -timeout --signal=SIGQUIT 60m ore gcloud gc --json-key <(echo "${GCP_JSON_KEY}" | base64 --decode) +timeout --signal=SIGQUIT 60m ore gcloud gc --json-key <(base64 --decode <<< "${GCP_JSON_KEY}") timeout --signal=SIGQUIT 60m ore azure gc --duration 6h timeout --signal=SIGQUIT 60m ore brightbox gc --duration 6h \ --brightbox-client-id="${BRIGHTBOX_CLIENT_ID}" --brightbox-client-secret="${BRIGHTBOX_CLIENT_SECRET}" timeout --signal=SIGQUIT 60m ore akamai gc --duration 6h \ --akamai-token="${AKAMAI_TOKEN}" timeout --signal=SIGQUIT 60m ore stackit gc --duration 6h \ - --stackit-service-account-key-path=<(echo "${STACKIT_SERVICE_ACCOUNT}" | base64 --decode) \ + --stackit-service-account-key-path=<(base64 --decode <<< "${STACKIT_SERVICE_ACCOUNT}") \ --stackit-project-id="${STACKIT_PROJECT_ID}" secret_to_file aws_credentials_config_file "${AWS_CREDENTIALS}" for channel in alpha beta stable lts; do @@ -29,5 +29,5 @@ timeout --signal=SIGQUIT 60m ore oraclecloud gc --duration 6h \ --oraclecloud-tenancy="${ORACLECLOUD_TENANCY}" \ --oraclecloud-user="${ORACLECLOUD_USER}" \ --oraclecloud-fingerprint="${ORACLECLOUD_FINGERPRINT}" \ - --oraclecloud-private-key="$(echo "${ORACLECLOUD_PRIVATE_KEY}" | base64 --decode)" \ + --oraclecloud-private-key="$(base64 --decode <<< "${ORACLECLOUD_PRIVATE_KEY}")" \ --oraclecloud-compartment-id="${ORACLECLOUD_COMPARTMENT_ID}" diff --git a/ci-automation/release.sh b/ci-automation/release.sh index 4d3bc483c82..678fde80341 100644 --- a/ci-automation/release.sh +++ b/ci-automation/release.sh @@ -75,8 +75,6 @@ function _inside_mantle() { source sdk_lib/sdk_container_common.sh source ci-automation/ci_automation_common.sh source sdk_container/.repo/manifests/version.txt - # Needed because we are not the SDK container here - source sdk_container/.env CHANNEL="$(get_git_channel)" VERSION="${FLATCAR_VERSION}" aws_credentials_config_file="" @@ -240,8 +238,6 @@ function _release_build_impl() { source ci-automation/gpg_setup.sh source sdk_container/.repo/manifests/version.txt - # Needed because we are not the SDK container here - source sdk_container/.env local sdk_version="${FLATCAR_SDK_VERSION}" local docker_sdk_vernum="" docker_sdk_vernum="$(vernum_to_docker_image_version "${sdk_version}")" @@ -257,9 +253,9 @@ function _release_build_impl() { # A job on each worker prunes old mantle images (docker image prune), no need to do it here echo "docker rm -f '${container_name}'" >> ./ci-cleanup.sh - touch sdk_container/.env # This file should already contain the required credentials as env vars docker run --pull always --rm --name="${container_name}" --net host \ - -w /work -v "$PWD":/work "${mantle_ref}" bash -c "git config --global --add safe.directory /work && source ci-automation/release.sh && _inside_mantle" + -w /work -v "$PWD":/work --env-file="sdk_lib/env_mantle.txt" "${mantle_ref}" \ + bash -c "git config --global --add safe.directory /work && source ci-automation/release.sh && _inside_mantle" # Push flatcar_production_ami_*txt and flatcar_production_ami_*json to the right bincache folder for arch in amd64 arm64; do sudo chown -R "$USER:$USER" "aws-${arch}" diff --git a/ci-automation/release/azure_marketplace.sh b/ci-automation/release/azure_marketplace.sh index 6ec48822b8e..0b9b50e9367 100644 --- a/ci-automation/release/azure_marketplace.sh +++ b/ci-automation/release/azure_marketplace.sh @@ -37,17 +37,17 @@ function _release_azure_marketplace_impl() { # A job on each worker prunes old mantle images (docker image prune), no need to do it here echo "docker rm -f '${container_name}'" >> ./ci-cleanup.sh - source sdk_container/.env AZ_STORAGE_KEY=$(secret_from_base64 "AZ_STORAGE_KEY" "${AZ_MARKETPLACE_PUBLISH}") AZ_TENANT_ID=$(secret_from_base64 "AZ_TENANT_ID" "${AZ_MARKETPLACE_PUBLISH}") AZ_CLIENT_ID=$(secret_from_base64 "AZ_CLIENT_ID" "${AZ_MARKETPLACE_PUBLISH}") AZ_SECRET_VALUE=$(secret_from_base64 "AZ_SECRET_VALUE" "${AZ_MARKETPLACE_PUBLISH}") + export AZ_STORAGE_KEY AZ_TENANT_ID AZ_CLIENT_ID AZ_SECRET_VALUE docker run --pull always --rm --name="${container_name}" --net host \ - -e AZ_STORAGE_KEY="${AZ_STORAGE_KEY}" \ - -e AZ_TENANT_ID="${AZ_TENANT_ID}" \ - -e AZ_CLIENT_ID="${AZ_CLIENT_ID}" \ - -e AZ_SECRET_VALUE="${AZ_SECRET_VALUE}" \ + -e AZ_STORAGE_KEY \ + -e AZ_TENANT_ID \ + -e AZ_CLIENT_ID \ + -e AZ_SECRET_VALUE \ -v "${PWD}"/ci-automation/release/azure_marketplace_publish.py:/app/azure_marketplace_publish.py \ -w /app \ ghcr.io/flatcar/uv:alpine \ diff --git a/ci-automation/test.sh b/ci-automation/test.sh index c8db48edd01..9f694500c1a 100644 --- a/ci-automation/test.sh +++ b/ci-automation/test.sh @@ -33,6 +33,7 @@ # # 3. List of tests / test patterns. Defaults to "*" (all tests). # All positional arguments after the first 2 (see above) are tests / patterns of tests to run. +# 4. Standard input. Use this to run arbitrary commands inside container before starting the tests. # # MAX_RETRIES. Environment variable. Number of re-runs to overcome transient failures. Defaults to 20. # PARALLEL_TESTS. Environment variable. Number of test cases to run in parallel. @@ -72,21 +73,6 @@ # script would need to make anyway. For more information, please refer # to the vendor_test.sh file. -function __escape_multiple() { - local out_array_arg_name="${1}"; shift - # rest are args to be escape and appended into the array named - # after the first arg - local -n out_array_arg_ref="${out_array_arg_name}" - local arg arg_escaped - - out_array_arg_ref=() - for arg; do - printf -v arg_escaped '%q' "${arg}" - out_array_arg_ref+=( "${arg_escaped}" ) - done -} -# -- - function test_run() { # Run a subshell, so the traps, environment changes and global # variables are not spilled into the caller. @@ -143,38 +129,30 @@ function _test_run_impl() { # A job on each worker prunes old mantle images (docker image prune) echo "docker rm -f '${container_name}'" >> ./ci-cleanup.sh - local image_escaped - printf -v image_escaped '%q' "${image}" local common_test_args=( "${work_dir}" "${tests_dir}" "${arch}" "${vernum}" ) - local common_test_args_escaped=() - __escape_multiple common_test_args_escaped "${common_test_args[@]}" - local tests_escaped=() - __escape_multiple tests_escaped "${@}" + local stdin="" + [[ ! -t 0 ]] && stdin=$(< /dev/stdin) # Vendor tests may need to know if it is a first run or a rerun touch "${work_dir}/first_run" for retry in $(seq "${retries}"); do local tapfile="results-run-${retry}.tap" local failfile="failed-run-${retry}.txt" - local tapfile_escaped - printf -v tapfile_escaped '%q' "${tapfile}" # Ignore retcode since tests are flaky. We'll re-run failed tests and # determine success based on test results (tapfile). - set +e - touch sdk_container/.env docker run --pull always --rm --name="${container_name}" --privileged --net host -v /dev:/dev \ - -w /work -v "$PWD":/work "${MANTLE_REF}" \ - bash -c "git config --global --add safe.directory /work && \ - source sdk_container/.env && \ - ci-automation/vendor-testing/${image_escaped}.sh ${common_test_args_escaped[*]} ${tapfile_escaped} ${tests_escaped[*]}" - set -e + -w /work -v "$PWD":/work --env-file="sdk_lib/env_mantle.txt" -i "${MANTLE_REF}" bash -ec \ + 'git config --global --add safe.directory /work + source /dev/stdin + ci-automation/vendor-testing/"${1}".sh "${@:2}"' \ + -- "${image}" "${common_test_args[@]}" "${tapfile}" "${@}" <<< "${stdin}" || : rm -f "${work_dir}/first_run" # Note: git safe.directory is not set in this run as it does not use git @@ -208,7 +186,7 @@ function _test_run_impl() { echo "Failed tests:" printf '%s\n' "${failed_tests[@]}" echo "-----------" - __escape_multiple tests_escaped "${failed_tests[@]}" + set -- "${failed_tests[@]}" done if ${print_give_up}; then diff --git a/ci-automation/vendor-testing/brightbox.sh b/ci-automation/vendor-testing/brightbox.sh index e18a9153c83..8d520554e52 100755 --- a/ci-automation/vendor-testing/brightbox.sh +++ b/ci-automation/vendor-testing/brightbox.sh @@ -22,7 +22,7 @@ if [[ "${CIA_ARCH}" == "arm64" ]]; then exit 1 fi -# BRIGHTBOX_CLIENT_ID, BRIGHTBOX_CLIENT_SECRET should be provided by sdk_container/.env +# BRIGHTBOX_CLIENT_ID, BRIGHTBOX_CLIENT_SECRET should be provided by the caller. # Upload the image on Brightbox. IMAGE_ID=$(ore brightbox create-image \ diff --git a/ci-automation/vendor-testing/hetzner.sh b/ci-automation/vendor-testing/hetzner.sh index 167670ddeb0..0ea602e396b 100755 --- a/ci-automation/vendor-testing/hetzner.sh +++ b/ci-automation/vendor-testing/hetzner.sh @@ -16,7 +16,7 @@ hetzner_instance_type="${!hetzner_instance_type_var}" hetzner_location_var="HETZNER_${CIA_ARCH}_LOCATION" hetzner_location="${!hetzner_location_var}" -# HETZNER_TPS_TOKEN should be provided by sdk_container/.env +# HETZNER_TPS_TOKEN should be provided by the caller. # We first need to create a temporary project using HETZNER_TPS_TOKEN # When the project is created it returns a regular HETZNER_TOKEN that can be used diff --git a/ci-automation/vendor-testing/openstack.sh b/ci-automation/vendor-testing/openstack.sh index d1a1a4143a9..e780bd90aec 100755 --- a/ci-automation/vendor-testing/openstack.sh +++ b/ci-automation/vendor-testing/openstack.sh @@ -22,7 +22,7 @@ if [[ "${CIA_ARCH}" == "arm64" ]]; then exit 1 fi -# OPENSTACK_CREDS, OPENSTACK_USER, OPENSTACK_HOST, OPENSTACK_KEYFILE should be provided by sdk_container/.env +# OPENSTACK_CREDS, OPENSTACK_USER, OPENSTACK_HOST, OPENSTACK_KEYFILE should be provided by the caller. config_file='' secret_to_file config_file "${OPENSTACK_CREDS}" diff --git a/ci-automation/vendor-testing/stackit.sh b/ci-automation/vendor-testing/stackit.sh index ea8c30e31bb..aa23cd05c2b 100755 --- a/ci-automation/vendor-testing/stackit.sh +++ b/ci-automation/vendor-testing/stackit.sh @@ -22,7 +22,7 @@ kola_test_basename="ci-${CIA_VERNUM//[+.]/-}" # Upload the image on STACKIT. IMAGE_ID=$(ore stackit \ - --stackit-service-account-key-path=<(echo "${STACKIT_SERVICE_ACCOUNT}" | base64 --decode) \ + --stackit-service-account-key-path=<(base64 --decode <<< "${STACKIT_SERVICE_ACCOUNT}") \ --stackit-project-id="${STACKIT_PROJECT_ID}" \ create-image \ --board "${CIA_ARCH}-usr" \ @@ -39,7 +39,7 @@ timeout --signal=SIGQUIT 2h kola run \ --channel="${CIA_CHANNEL}" \ --basename="${kola_test_basename}" \ --platform=stackit \ - --stackit-service-account-key-path=<(echo "${STACKIT_SERVICE_ACCOUNT}" | base64 --decode) \ + --stackit-service-account-key-path=<(base64 --decode <<< "${STACKIT_SERVICE_ACCOUNT}") \ --stackit-project-id="${STACKIT_PROJECT_ID}" \ --stackit-image-id="${IMAGE_ID}" \ --stackit-type="${stackit_instance_type}" \ diff --git a/common.sh b/common.sh index c209e2ff490..ce6472922ab 100644 --- a/common.sh +++ b/common.sh @@ -256,32 +256,6 @@ get_gclient_root() { fi } -# Populate the ENVIRONMENT_ALLOWLIST array. -load_environment_allowlist() { - ENVIRONMENT_ALLOWLIST=( - COREOS_OFFICIAL - FLATCAR_BUILD_ID - FORCE_STAGES - GIT_AUTHOR_EMAIL - GIT_AUTHOR_NAME - GIT_COMMITTER_EMAIL - GIT_COMMITTER_NAME - GIT_PROXY_COMMAND - GIT_SSH - RSYNC_PROXY - GNUPGHOME - GPG_AGENT_INFO - SSH_AGENT_PID - SSH_AUTH_SOCK - USE - all_proxy - ftp_proxy - http_proxy - https_proxy - no_proxy - ) -} - load_environment_var() { local file="$1"; shift unset "${@}" diff --git a/jenkins/systemd-run-wrap.sh b/jenkins/systemd-run-wrap.sh index 4b5c4e0b974..315b8f3b9e1 100755 --- a/jenkins/systemd-run-wrap.sh +++ b/jenkins/systemd-run-wrap.sh @@ -1,34 +1,10 @@ #!/bin/bash set -euo pipefail -# note: to make sure you forward the whole env, you can first run 'source <(export)' before starting this script -# Add /opt/bin explicitly because the lbzcat binary is there on the Jenkins workers -export PATH="$PATH:/opt/bin" - -# Use a system session unit because the user session may not be set up correctly in a CI env -ARGS=("--system" "--collect" "--same-dir" "--pipe" "--wait" "--property=User=$USER" "--property=Group=$USER") -# Extra "bash -c" is needed to only export the exported variables. Do -# not use sh - it will add POSIXLY_CORRECT into the environment, which -# is unnecessary. -for VARNAME in $(bash -c 'compgen -v'); do - set +u - VAL="${!VARNAME}" - set -u - ARGS+=("--setenv" "${VARNAME}=${VAL}") -done - -UNITNAME="run-$(date '+%s')-${RANDOM}" - -# The --pipe option does not stop the unit when the systemd-run process is killed, we have to do this through a trap -# (and --pty as alternative doesn't behave well because it leads to processes expecting stdin when there is none) -function cancel() { - echo - echo "Terminating" - sudo systemctl stop "${UNITNAME}" - exit 1 -} -trap cancel INT - -ARGS+=("--unit=${UNITNAME}") - -sudo systemd-run "${ARGS[@]}" "$@" +exec systemd-run \ + --user \ + --scope \ + --collect \ + --same-dir \ + --expand-environment=no \ + "${@}" diff --git a/run_local_tests.sh b/run_local_tests.sh index e4ee0c8a08a..54f69973a3f 100755 --- a/run_local_tests.sh +++ b/run_local_tests.sh @@ -1,11 +1,11 @@ #!/bin/bash # # Copyright (c) 2023 The Flatcar Maintainers. -# Licensed under the Apache License, Version 2.0 (the "License"); +# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # QoL wrapper around ci-automation test.sh for running local tests of qemu_uefi image. # The devcontainer tests will be skipped since these require a valid commit ref in @@ -17,7 +17,7 @@ # Prerequisites: # - Flatcar OS image and qemu uefi code to be tested in # __build__/images/images/amd64-usr/latest/ -# +# # This script is intended to be run after building a qemu_uefi image with the SDK container: # ./build_packages # ./build_image @@ -48,15 +48,12 @@ function set_vars() { local arch="${1}" local parallel="${2}" - # Read by the mantle container. # The local directory ("pwd") will be mounted to /work/ in the container. - cat > sdk_container/.env <: - Mount local file or directory inside the container." echo " Can be specified multiple times." + echo " -e Space-separated list of environment variable names to pass through." + echo " Can be specified multiple times." echo " -- Stop parsing options at this point, pass the rest as the container command." echo " -h Print this help." echo @@ -73,6 +76,14 @@ while [[ $# -gt 0 ]] ; do update_versionfile= shift;; -m) mounts+=( -v "$2" ); shift; shift;; + -e) if [[ $2 == *=* ]]; then + echo "Do not pass environment variable values to -e, only names." + exit 1 + fi + for var in $2; do + envs+=( --env "${var}" ) + done + shift 2;; --) shift; break;; -*) echo "Unknown flag ${1@Q}, use '-h' or '--help' for usage"; exit 1;; *) break;; @@ -103,11 +114,6 @@ fi stat=$(call_docker ps --all --no-trunc --filter name="${filter}${name}\$" --format '{{.Status}}' \ | cut -f1 -d' ') -# pass SDK related environment variables and gcloud auth -# into container -setup_sdk_env -setup_gsutil - mkdir -p "__build__/images" mkdir -p "sdk_container/.cache/sdks" @@ -121,8 +127,8 @@ fi if [[ -z ${stat} ]] ; then yell "Creating a new container '$name'" - gpg_volumes=() - gnupg_ssh_gcloud_mount_opts gpg_volumes + credential_args=() + credential_docker_args credential_args if [[ -z ${custom_image} ]]; then ( @@ -145,7 +151,7 @@ if [[ -z ${stat} ]] ; then -v "${PWD}/sdk_container:/mnt/host/source/" -v "${PWD}/__build__/images:/mnt/host/source/src/build" -v "${PWD}:/mnt/host/source/src/scripts" - "${gpg_volumes[@]}" + "${credential_args[@]}" "${mounts[@]}" --privileged --network host @@ -173,6 +179,14 @@ if [[ ${stat} != "Up" ]] ; then fi # Workaround: The SDK expects to be able to write to /etc/hosts -call_docker exec "${name}" sh -c 'cp /etc/hosts /etc/hosts2; umount /etc/hosts ; mv /etc/hosts2 /etc/hosts' - -call_docker exec "${tty[@]}" -i "${name}" /mnt/host/source/src/scripts/sdk_lib/sdk_entry.sh "$@" +call_docker exec -i "${name}" sh <= 4.11 does not have it by default. -# Ideally util-linux should have the su binary, but that is currently not -# possible, because of a bunch of additional dependencies in SDK like -# pam_sssd in baselayout. -# -# Disable su for util-linux to avoid conflict with sys-apps/shadow, which -# has its own su binary. -sys-apps/shadow su -sys-apps/util-linux -su - # Enable kerberos support for NFS net-fs/nfs-utils junction kerberos ldap libmount nfsv3 nfsv4 uuid net-libs/libtirpc kerberos diff --git a/sdk_container/src/third_party/coreos-overlay/profiles/coreos/targets/sdk/package.use b/sdk_container/src/third_party/coreos-overlay/profiles/coreos/targets/sdk/package.use index 702d47ca6e6..614123e8a61 100644 --- a/sdk_container/src/third_party/coreos-overlay/profiles/coreos/targets/sdk/package.use +++ b/sdk_container/src/third_party/coreos-overlay/profiles/coreos/targets/sdk/package.use @@ -21,3 +21,6 @@ virtual/zlib static-libs # Needed for signed sysexts using systemd-repart sys-apps/systemd cryptsetup + +# Don't include su because it requires PAM, which we don't want in the SDK. +sys-apps/util-linux -su diff --git a/sdk_lib/90_env_keep b/sdk_lib/90_env_keep deleted file mode 100644 index 995b9a1a3d7..00000000000 --- a/sdk_lib/90_env_keep +++ /dev/null @@ -1,9 +0,0 @@ -Defaults env_keep += "FLATCAR_BUILD_ID COREOS_OFFICIAL \ - EMAIL GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME \ - GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME \ - GIT_PROXY_COMMAND GIT_SSH RSYNC_PROXY \ - GNUPGHOME GPG_AGENT_INFO SSH_AUTH_SOCK \ - BOTO_PATH GOOGLE_APPLICATION_CREDENTIALS \ - USE FEATURES PORTAGE_USERNAME FORCE_STAGES \ - SIGNER \ - all_proxy ftp_proxy http_proxy https_proxy no_proxy" diff --git a/sdk_lib/Dockerfile.sdk-build b/sdk_lib/Dockerfile.sdk-build index 8217ea14fad..3bc270f1670 100644 --- a/sdk_lib/Dockerfile.sdk-build +++ b/sdk_lib/Dockerfile.sdk-build @@ -2,15 +2,11 @@ ARG VERSION=9999.99.99-version-missing FROM flatcar-sdk-import:${VERSION} ARG BINHOST -ARG OFFICIAL=0 - -# mark build as official where appropriate -RUN echo "export COREOS_OFFICIAL=$OFFICIAL" > /mnt/host/source/.env +ARG COREOS_OFFICIAL=0 RUN FEATURES="-ipc-sandbox -network-sandbox -pid-sandbox" \ /home/sdk/sdk_entry.sh ./sdk_lib/setup_boards.sh start "${BINHOST}" -RUN rm /mnt/host/source/.env RUN rm -rf /home/sdk/toolchain-pkgs # Clean up ephemeral key directory variables that were added during build diff --git a/sdk_lib/Dockerfile.sdk-import b/sdk_lib/Dockerfile.sdk-import index a7e11ef9acc..7f3445b25e8 100644 --- a/sdk_lib/Dockerfile.sdk-import +++ b/sdk_lib/Dockerfile.sdk-import @@ -1,3 +1,5 @@ +# syntax=docker/dockerfile:1 + ARG VERSION=9999.99.99-version-missing FROM flatcar-sdk-tarball:${VERSION} @@ -26,10 +28,12 @@ COPY --chown=sdk:sdk sdk_container/ /mnt/host/source COPY --chown=sdk:sdk . /mnt/host/source/src/scripts RUN chown sdk:sdk /mnt/host/source -COPY sdk_lib/90_env_keep /etc/sudoers.d/90_env_keep -RUN chmod 0440 /etc/sudoers.d/90_env_keep +RUN --mount=type=bind,target=/mnt/host/source/src/scripts \ + cat /mnt/host/source/src/scripts/sdk_lib/env_{pass,keep}.txt | \ + sed -e '1i Defaults env_keep += " \\' -e 's:$: \\:' -e '$a "' | \ + install -m0440 /dev/stdin /etc/sudoers.d/90_env_keep -RUN mkdir -p /mnt/host/source/src/scripts /mnt/host/source/src/build +RUN mkdir -p /mnt/host/source/src/build RUN ln -s /mnt/host/source /home/sdk/trunk RUN rm /home/sdk/.bashrc @@ -37,10 +41,6 @@ RUN cp /etc/skel/.bashrc /home/sdk RUN echo "cd /home/sdk/trunk/src/scripts" >> /home/sdk/.bashrc RUN echo 'export PATH="$PATH:/usr/local/bin:/usr/local/sbin"' >> /home/sdk/.bashrc -# user and SDK environment variables pass-through into container -RUN echo "if [ -f /mnt/host/source/.env ]; then source /mnt/host/source/.env; fi" >> /home/sdk/.bashrc -RUN echo "if [ -f /mnt/host/source/.sdkenv ]; then source /mnt/host/source/.sdkenv; fi" >> /home/sdk/.bashrc - RUN chown -h sdk:sdk /mnt/host/source/src/scripts /mnt/host/source/src/build /home/sdk/trunk /home/sdk/.bashrc COPY --chown=sdk:sdk sdk_lib/sdk_entry.sh /home/sdk diff --git a/sdk_lib/env_keep.txt b/sdk_lib/env_keep.txt new file mode 100644 index 00000000000..9e6fa9f0f5d --- /dev/null +++ b/sdk_lib/env_keep.txt @@ -0,0 +1,3 @@ +FEATURES +PORTAGE_USERNAME +USE diff --git a/sdk_lib/env_mantle.txt b/sdk_lib/env_mantle.txt new file mode 100644 index 00000000000..cdb3d5fe432 --- /dev/null +++ b/sdk_lib/env_mantle.txt @@ -0,0 +1,37 @@ +AKAMAI_TOKEN +AWS_ACCESS_KEY_ID +AWS_CLOUDFORMATION_CREDENTIALS +AWS_CREDENTIALS +AWS_IAM_PROFILE +AWS_MARKETPLACE_ARN +AWS_MARKETPLACE_CREDENTIALS +AWS_REGION +AWS_SECRET_ACCESS_KEY +AZURE_LOCATION +AZURE_SUBSCRIPTION_ID +BRIGHTBOX_CLIENT_ID +BRIGHTBOX_CLIENT_SECRET +DIGITALOCEAN_TOKEN_JSON +GCP_JSON_KEY +GOOGLE_RELEASE_CREDENTIALS +HETZNER_TPS_TOKEN +OPENSTACK_CREDS +OPENSTACK_HOST +OPENSTACK_KEYFILE +OPENSTACK_USER +ORACLECLOUD_COMPARTMENT_ID +ORACLECLOUD_FINGERPRINT +ORACLECLOUD_PRIVATE_KEY +ORACLECLOUD_TENANCY +ORACLECLOUD_USER +PARALLEL_TESTS +QEMU_DEVCONTAINER_BINHOST_URL +QEMU_DEVCONTAINER_URL +QEMU_IMAGE_NAME +QEMU_KOLA_SKIP_MANGLE +QEMU_UEFI_FIRMWARE +QEMU_UEFI_OVMF_VARS +QEMU_UPDATE_PAYLOAD +STACKIT_PROJECT_ID +STACKIT_SERVICE_ACCOUNT +VMWARE_ESX_CREDS diff --git a/sdk_lib/env_pass.txt b/sdk_lib/env_pass.txt new file mode 100644 index 00000000000..913f42ad344 --- /dev/null +++ b/sdk_lib/env_pass.txt @@ -0,0 +1,25 @@ +all_proxy +COREOS_OFFICIAL +EMAIL +FLATCAR_BUILD_ID +FORCE_STAGES +ftp_proxy +GIT_AUTHOR_EMAIL +GIT_AUTHOR_NAME +GIT_COMMITTER_EMAIL +GIT_COMMITTER_NAME +GIT_PROXY_COMMAND +GIT_SSH +GPG_AGENT_INFO +http_proxy +https_proxy +MODULE_SIGNING_KEY_DIR +no_proxy +RSYNC_PROXY +SBSIGN_CERT +SBSIGN_DB_CERT +SBSIGN_DB_KEY +SBSIGN_KEY +SHIM_SIGNING_CERTIFICATE +SIGNER +SYSEXT_SIGNING_KEY_DIR diff --git a/sdk_lib/sdk_container_common.sh b/sdk_lib/sdk_container_common.sh index d1514a5f72b..b44fd7f6198 100644 --- a/sdk_lib/sdk_container_common.sh +++ b/sdk_lib/sdk_container_common.sh @@ -9,7 +9,6 @@ # sdk_container_common_versionfile="sdk_container/.repo/manifests/version.txt" sdk_container_common_registry="ghcr.io/flatcar" -sdk_container_common_env_file="sdk_container/.sdkenv" # Check for podman and docker; use docker if present, podman alternatively. # Podman needs 'sudo' since we need privileged containers for the SDK. @@ -34,7 +33,7 @@ fi docker_a=( docker ) if "${is_podman}"; then - docker_a=( sudo podman ) + docker_a=( sudo -E podman ) fi docker=${docker_a[*]} @@ -180,138 +179,32 @@ EOF } # -- -# -# Set up SDK environment variables. -# Environment vars are put in a file that is sourced by the container's -# .bashrc (if present). GNUPGHOME and SSH_AUTH_SOCK are set -# to container-specific paths if applicable. - -function setup_sdk_env() { - local var - - rm -f "$sdk_container_common_env_file" - - # conditionally set up gnupg, ssh socket, and gcloud auth / boto - # depending on availability on the host - GNUPGHOME="${GNUPGHOME:-$HOME/.gnupg}" - if [ -d "${GNUPGHOME}" ] ; then - echo "GNUPGHOME=\"/home/sdk/.gnupg\"" >> "$sdk_container_common_env_file" - echo "export GNUPGHOME" >> "$sdk_container_common_env_file" - export GNUPGHOME - fi - - if [ -e "${SSH_AUTH_SOCK:-}" ] ; then - local sockname="$(basename "${SSH_AUTH_SOCK}")" - echo "SSH_AUTH_SOCK=\"/run/sdk/ssh/$sockname\"" >> "$sdk_container_common_env_file" - echo "export SSH_AUTH_SOCK" >> "$sdk_container_common_env_file" - fi - - # keep in sync with 90_env_keep, without GNUPGHOME and - # SSH_AUTH_SOCK as those are set up above, and without BOTO_PATH - # and GOOGLE_APPLICATION_CREDENTIALS as those are set up in the - # setup_gsutil function. - for var in FLATCAR_BUILD_ID COREOS_OFFICIAL \ - EMAIL GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME \ - GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME \ - GIT_PROXY_COMMAND GIT_SSH RSYNC_PROXY \ - GPG_AGENT_INFO \ - \ - USE FEATURES PORTAGE_USERNAME FORCE_STAGES \ - SIGNER \ - SBSIGN_KEY SBSIGN_CERT SBSIGN_DB_KEY SBSIGN_DB_CERT \ - SHIM_SIGNING_CERTIFICATE \ - MODULE_SIGNING_KEY_DIR SYSEXT_SIGNING_KEY_DIR \ - all_proxy ftp_proxy http_proxy https_proxy no_proxy; do - - if [ -n "${!var:-}" ] ; then - echo "${var}=\"${!var}\"" >> "$sdk_container_common_env_file" - echo "export ${var}" >> "$sdk_container_common_env_file" - fi - done -} -# -- - -# Set up gcloud legacy creds (via GOOGLE_APPLICATION_CREDENTIALS) -# for the SDK container. -# This will also create a boto config right next to the -# GOOGLE_APPLICATION_CREDENTIALS json file. - -function setup_gsutil() { - local creds="${GOOGLE_APPLICATION_CREDENTIALS:-$HOME/.config/gcloud/application_default_credentials.json}" - if [ ! -e "$creds" ]; then - return - fi - - local creds_dir="$(dirname "$creds")" - local botofile="$creds_dir/boto-flatcar-sdk" - - # TODO t-lo: move generation of boto file to sdk_entry so - # it's only created inside the container. - - # read creds file and create boto file for gsutil - local tmp="$(mktemp)" - trap "rm -f '$tmp'" EXIT - - local oauth_refresh="$(jq -r '.refresh_token' "$creds")" - local client_id="$(jq -r '.client_id' "$creds")" - local client_secret="$(jq -r '.client_secret' "$creds")" - - cat >>"$tmp" <> "$sdk_container_common_env_file" - echo "export BOTO_PATH" >> "$sdk_container_common_env_file" - echo "GOOGLE_APPLICATION_CREDENTIALS=\"$creds\"" >> "$sdk_container_common_env_file" - echo "export GOOGLE_APPLICATION_CREDENTIALS" >> "$sdk_container_common_env_file" - - BOTO_PATH="$botofile" - GOOGLE_APPLICATION_CREDENTIALS="$creds" - export BOTO_PATH - export GOOGLE_APPLICATION_CREDENTIALS -} - -# -- - -# Generate volume mount command line options for docker -# to pass gpg, ssh, and gcloud auth host directories -# into the SDK container. - -function gnupg_ssh_gcloud_mount_opts() { +# Generate command line options for Docker to pass GPG and SSH host directories +# into the SDK container. +function credential_docker_args() { local -n args_ref="${1}"; shift + args_ref=() local sdk_gnupg_home="/home/sdk/.gnupg" - local gpgagent_dir="/run/user/$(id -u)/gnupg" + local gpgagent_dir="/run/user/${UID}/gnupg" - args_ref=() # pass host GPG home and Agent directories to container - if [[ -d ${GNUPGHOME} ]] ; then - args_ref+=( -v "$GNUPGHOME:$sdk_gnupg_home" ) + : "${GNUPGHOME:="${HOME}"/.gnupg}" + if [[ -d ${GNUPGHOME:-} ]] ; then + args_ref+=( + -v "$GNUPGHOME:$sdk_gnupg_home" + -e GNUPGHOME="$sdk_gnupg_home" + ) fi if [[ -d ${gpgagent_dir} ]] ; then args_ref+=( -v "${gpgagent_dir}:${gpgagent_dir}" ) fi - local sshsockdir if [[ -e ${SSH_AUTH_SOCK:-} ]] ; then - sshsockdir=$(dirname "$SSH_AUTH_SOCK") - args_ref+=( -v "${sshsockdir}:/run/sdk/ssh" ) - fi - - local creds_dir - if [[ -e ${GOOGLE_APPLICATION_CREDENTIALS:-} ]] ; then - creds_dir=$(dirname "${GOOGLE_APPLICATION_CREDENTIALS}") - if [[ -d ${creds_dir} ]] ; then - echo "Mounting gcloud credentials from ${creds_dir} (used for artifact uploads, safe to ignore if not needed, not baked into any image)" - echo "-v $creds_dir:$creds_dir" - args_ref+=( -v "${creds_dir}:${creds_dir}" ) - fi + args_ref+=( + -v "${SSH_AUTH_SOCK%/*}:/run/sdk/ssh" + -e SSH_AUTH_SOCK="/run/sdk/ssh/${SSH_AUTH_SOCK##*/}" + ) fi } diff --git a/sdk_lib/sdk_entry.sh b/sdk_lib/sdk_entry.sh index 8757b4b39b9..98f65798dd2 100755 --- a/sdk_lib/sdk_entry.sh +++ b/sdk_lib/sdk_entry.sh @@ -1,10 +1,5 @@ #!/bin/bash -# Source SDK environment variables if available (includes COREOS_OFFICIAL, etc.) -if [ -f /mnt/host/source/.sdkenv ]; then - source /mnt/host/source/.sdkenv -fi - if [ -n "${SDK_USER_ID:-}" ] ; then # If the "core" user from /usr/share/baselayout/passwd has the same ID, allow to take it instead usermod --non-unique -u $SDK_USER_ID sdk @@ -15,6 +10,9 @@ fi chown -R sdk:sdk /home/sdk +# GPG won't use the socket dir if /var/run/${UID} has the wrong permissions. +install -o sdk -g sdk -m 0700 -d "/run/user/$(id -u sdk)" + # Fix up SDK repo configuration to use the new coreos-overlay name. sed -i -r 's/^\[coreos\]/[coreos-overlay]/' /etc/portage/repos.conf/coreos.conf 2>/dev/null sed -i -r '/^masters =/s/\bcoreos(\s|$)/coreos-overlay\1/g' /usr/local/portage/crossdev/metadata/layout.conf 2>/dev/null @@ -48,15 +46,14 @@ sed -i -r '/^masters =/s/\bcoreos(\s|$)/coreos-overlay\1/g' /usr/local/portage/c echo echo "Updating board support in '/build/${target}' to use package cache for version '${version}'" echo "---" - sudo su sdk -l -c "/home/sdk/trunk/src/scripts/setup_board --board='$target' --regen_configs_only" + sudo sudo -u sdk -i /home/sdk/trunk/src/scripts/setup_board --board="$target" --regen_configs_only echo "TARGET_FLATCAR_VERSION='${version}'" | sudo tee "/build/$target/etc/target-version.txt" >/dev/null done fi ) -# SDK container is launched using the su command below, which does not preserve environment -# moreover, if multiple shells are attached to the same container, -# we want all of them to share the same value of the variable, therefore we need to save it in .bashrc +# If multiple shells are attached to the same container, we want all of them to +# share the same value of the variable, therefore we need to save it in .bashrc. # Check if MODULE_SIGNING_KEY_DIR exists in .bashrc and if the directory actually exists if grep -q 'export MODULE_SIGNING_KEY_DIR=' /home/sdk/.bashrc; then # Extract the existing path @@ -73,15 +70,15 @@ fi # Create key directory if not already configured in .bashrc if ! grep -q 'export MODULE_SIGNING_KEY_DIR=' /home/sdk/.bashrc; then if [[ -n ${MODULE_SIGNING_KEY_DIR:-} ]]; then - # Pre-set via environment (e.g. .sdkenv) — use as-is + # Pre-set via environment — use as-is : elif [[ ${COREOS_OFFICIAL:-0} -eq 1 ]]; then # For official builds, use ephemeral keys - MODULE_SIGNING_KEY_DIR=$(su sdk -c "mktemp -d") + MODULE_SIGNING_KEY_DIR=$(sudo -u sdk mktemp -d) else # For unofficial builds, use persistent directory MODULE_SIGNING_KEY_DIR="/home/sdk/.module-signing-keys" - su sdk -c "mkdir -p ${MODULE_SIGNING_KEY_DIR@Q}" + sudo -u sdk mkdir -p "${MODULE_SIGNING_KEY_DIR}" fi if [[ ! ${MODULE_SIGNING_KEY_DIR} || ! -d ${MODULE_SIGNING_KEY_DIR} ]]; then echo "Failed to create directory for module signing keys." @@ -102,13 +99,13 @@ if grep -q 'export SYSEXT_SIGNING_KEY_DIR' /home/sdk/.bashrc; then fi grep -q 'export SYSEXT_SIGNING_KEY_DIR' /home/sdk/.bashrc || { if [[ -n ${SYSEXT_SIGNING_KEY_DIR:-} ]]; then - # Pre-set via environment (e.g. .sdkenv) — use as-is + # Pre-set via environment — use as-is : elif [[ ${COREOS_OFFICIAL:-0} -eq 1 ]]; then - SYSEXT_SIGNING_KEY_DIR=$(su sdk -c "mktemp -d") + SYSEXT_SIGNING_KEY_DIR=$(sudo -u sdk mktemp -d) else SYSEXT_SIGNING_KEY_DIR="/home/sdk/.sysext-signing-keys" - su sdk -c "mkdir -p ${SYSEXT_SIGNING_KEY_DIR@Q}" + sudo -u sdk mkdir -p "${SYSEXT_SIGNING_KEY_DIR}" fi if [[ ! "$SYSEXT_SIGNING_KEY_DIR" || ! -d "$SYSEXT_SIGNING_KEY_DIR" ]]; then echo "Failed to create directory for sysext signing keys." @@ -119,42 +116,21 @@ grep -q 'export SYSEXT_SIGNING_KEY_DIR' /home/sdk/.bashrc || { build_id=$(source "/mnt/host/source/.repo/manifests/version.txt"; echo "$FLATCAR_BUILD_ID") # Generate sysext signing key only if missing or empty if [[ ! -s sysexts.key || ! -s sysexts.crt ]]; then - su sdk -c "openssl req -new -nodes -utf8 \ + sudo -u sdk openssl req -new -nodes -utf8 \ -x509 -batch -sha256 \ -days 36000 \ -outform PEM \ -out sysexts.crt \ -keyout sysexts.key \ -newkey 4096 \ - -subj '/CN=Flatcar sysext key/OU=$build_id'" \ + -subj "/CN=Flatcar sysext key/OU=$build_id" \ || echo "Generating sysext signing key failed" fi popd > /dev/null } -# This is ugly. -# We need to sudo -u sdk -i so the SDK user gets a fresh login. -# 'sdk' is member of multiple groups, and plain docker USER only -# allows specifying membership of a single group. -# When a command is passed to the container, we run, respectively: -# sudo -u sdk "". -# Then, we need to preserve whitespaces in arguments of commands -# passed to the container, e.g. -# ./update_chroot --toolchain_boards="amd64-usr arm64-usr". -# This is done via a separate ".cmd" file since we have used up -# our quotes for sudo "" already. -if [ $# -gt 0 ] ; then - cmd="/home/sdk/.cmd" - echo -n "exec bash -l -i -c '" >"$cmd" - for arg in "$@"; do - echo -n "\"$arg\" " >>"$cmd" - done - echo "'" >>"$cmd" - chmod 755 "$cmd" - sudo -u sdk "$cmd" - rc=$? - rm -f "$cmd" - exit $rc -else - exec sudo -u sdk -i -fi +# We need to sudo -u sdk with bash -l so that the SDK user gets a fresh login. +# sudo has an -i option to get a login shell, but that cannot be combined with +# -E to preserve the environment. We already have a relatively clean environment +# inside the container, but we want to preserve variables passed through Docker. +exec sudo -u sdk -EH bash -l -i ${1+-c '"${@}"' -- "${@}"}