From b93f5390ce6f23377b37ee4923beceba09181d78 Mon Sep 17 00:00:00 2001 From: Magnus Kulke Date: Wed, 16 Oct 2024 17:28:50 +0200 Subject: [PATCH] ci: add provenance attestation for agent artifact This adds provenance attestation logic for agent binaries that are published to an oci registry via ORAS. As a downstream consumer of the kata-agent binary the Peerpod project needs to verify that the artifact has been built on kata's CI. To create an attestation we need to know the exact digest of the oci artifact, at the point when the artifact was pushed. Therefore we record the full oci image as returned by oras push. The pushing and tagging logic has been slightly reworked to make this task less repetetive. The oras cli accepts multiple tags separated by comma on pushes, so a push can be performed atomically instead of iterating through tags and pushing each individually. This removes the risk of partially successful push operations (think: rate limits on the oci registry). So far the provenance creation has been only enabled for agent builds on amd64 and xs390x. Signed-off-by: Magnus Kulke --- .../build-kata-static-tarball-amd64.yaml | 30 ++++++++ .../build-kata-static-tarball-s390x.yaml | 25 ++++++ .../local-build/kata-deploy-binaries.sh | 77 +++++++++---------- 3 files changed, 92 insertions(+), 40 deletions(-) diff --git a/.github/workflows/build-kata-static-tarball-amd64.yaml b/.github/workflows/build-kata-static-tarball-amd64.yaml index 021efe8d1c..d0d4db9a17 100644 --- a/.github/workflows/build-kata-static-tarball-amd64.yaml +++ b/.github/workflows/build-kata-static-tarball-amd64.yaml @@ -24,6 +24,11 @@ on: jobs: build-asset: runs-on: ubuntu-22.04 + permissions: + contents: read + packages: write + id-token: write + attestations: write strategy: matrix: asset: @@ -83,11 +88,16 @@ jobs: TARGET_BRANCH: ${{ inputs.target-branch }} - name: Build ${{ matrix.asset }} + id: build run: | make "${KATA_ASSET}-tarball" build_dir=$(readlink -f build) # store-artifact does not work with symlink mkdir -p kata-build && cp "${build_dir}"/kata-static-${KATA_ASSET}*.tar.* kata-build/. + # export oci name and digest for attestation + oci_image="$(<"${build_dir}/${KATA_ASSET}-oci-image")" + echo "oci-name=${oci_image%@*}" >> $GITHUB_OUTPUT + echo "oci-digest=${oci_image#*@}" >> $GITHUB_OUTPUT env: KATA_ASSET: ${{ matrix.asset }} TAR_OUTPUT: ${{ matrix.asset }}.tar.gz @@ -98,6 +108,26 @@ jobs: TARGET_BRANCH: ${{ inputs.target-branch }} RELEASE: ${{ inputs.stage == 'release' && 'yes' || 'no' }} + - uses: oras-project/setup-oras@v1 + if: (matrix.asset == 'agent') && (inputs.push-to-registry == 'yes') + with: + version: "1.2.0" + + # for pushing attestations to the registry + - uses: docker/login-action@v3 + if: (matrix.asset == 'agent') && (inputs.push-to-registry == 'yes') + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - uses: actions/attest-build-provenance@v1 + if: (matrix.asset == 'agent') && (inputs.push-to-registry == 'yes') + with: + subject-name: ${{ steps.build.outputs.oci-name }} + subject-digest: ${{ steps.build.outputs.oci-digest }} + push-to-registry: true + - name: store-artifact ${{ matrix.asset }} if: ${{ matrix.stage != 'release' || (matrix.asset != 'agent' && matrix.asset != 'coco-guest-components' && matrix.asset != 'pause-image') }} uses: actions/upload-artifact@v4 diff --git a/.github/workflows/build-kata-static-tarball-s390x.yaml b/.github/workflows/build-kata-static-tarball-s390x.yaml index ad66eee835..60d02ab993 100644 --- a/.github/workflows/build-kata-static-tarball-s390x.yaml +++ b/.github/workflows/build-kata-static-tarball-s390x.yaml @@ -24,6 +24,11 @@ on: jobs: build-asset: runs-on: s390x + permissions: + contents: read + packages: write + id-token: write + attestations: write strategy: matrix: asset: @@ -60,11 +65,16 @@ jobs: TARGET_BRANCH: ${{ inputs.target-branch }} - name: Build ${{ matrix.asset }} + id: build run: | make "${KATA_ASSET}-tarball" build_dir=$(readlink -f build) # store-artifact does not work with symlink mkdir -p kata-build && cp "${build_dir}"/kata-static-${KATA_ASSET}*.tar.* kata-build/. + # export oci name and digest for attestation + oci_image="$(<"${build_dir}/${KATA_ASSET}-oci-image")" + echo "oci-name=${oci_image%@*}" >> $GITHUB_OUTPUT + echo "oci-digest=${oci_image#*@}" >> $GITHUB_OUTPUT env: KATA_ASSET: ${{ matrix.asset }} TAR_OUTPUT: ${{ matrix.asset }}.tar.gz @@ -75,6 +85,21 @@ jobs: TARGET_BRANCH: ${{ inputs.target-branch }} RELEASE: ${{ inputs.stage == 'release' && 'yes' || 'no' }} + # for pushing attestations to the registry + - uses: docker/login-action@v3 + if: (matrix.asset == 'agent') && (inputs.push-to-registry == 'yes') + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - uses: actions/attest-build-provenance@v1 + if: (matrix.asset == 'agent') && (inputs.push-to-registry == 'yes') + with: + subject-name: ${{ steps.build.outputs.oci-name }} + subject-digest: ${{ steps.build.outputs.oci-digest }} + push-to-registry: true + - name: store-artifact ${{ matrix.asset }} if: ${{ inputs.stage != 'release' || (matrix.asset != 'agent' && matrix.asset != 'coco-guest-components' && matrix.asset != 'pause-image') }} uses: actions/upload-artifact@v4 diff --git a/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh b/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh index 4396aa3125..316ecd257c 100755 --- a/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh +++ b/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh @@ -1173,51 +1173,48 @@ handle_build() { echo "Pushing ${build_target} with tags: ${tags[*]}" + normalized_tags="" for tag in "${tags[@]}"; do # tags can only contain lowercase and uppercase letters, digits, underscores, periods, and hyphens # and limited to 128 characters, so filter out non-printable characers, replace invalid printable # characters with underscode and trim down to leave enough space for the arch suffix - tag_length_limit=$(expr 128 - $(echo "-$(uname -m)" | wc -c)) - tag=("$(echo ${tag} | tr -dc '[:print:]' | tr -c '[a-zA-Z0-9\_\.\-]' _ | head -c ${tag_length_limit})-$(uname -m)") - case ${build_target} in - kernel-nvidia-gpu) - oras push \ - ${ARTEFACT_REGISTRY}/kata-containers/cached-artefacts/${build_target}:${tag} \ - ${final_tarball_name} \ - "kata-static-${build_target}-headers.tar.xz" \ - ${build_target}-version \ - ${build_target}-builder-image-version \ - ${build_target}-sha256sum - ;; - kernel-nvidia-gpu-confidential) - oras push \ - ${ARTEFACT_REGISTRY}/${ARTEFACT_REPOSITORY}/cached-artefacts/${build_target}:${tag} \ - ${final_tarball_name} \ - "kata-static-${build_target}-modules.tar.xz" \ - "kata-static-${build_target}-headers.tar.xz" \ - ${build_target}-version \ - ${build_target}-builder-image-version \ - ${build_target}-sha256sum - ;; - kernel*-confidential) - oras push \ - ${ARTEFACT_REGISTRY}/${ARTEFACT_REPOSITORY}/cached-artefacts/${build_target}:${tag} \ - ${final_tarball_name} \ - "kata-static-${build_target}-modules.tar.xz" \ - ${build_target}-version \ - ${build_target}-builder-image-version \ - ${build_target}-sha256sum - ;; - *) - oras push \ - ${ARTEFACT_REGISTRY}/${ARTEFACT_REPOSITORY}/cached-artefacts/${build_target}:${tag} \ - ${final_tarball_name} \ - ${build_target}-version \ - ${build_target}-builder-image-version \ - ${build_target}-sha256sum - ;; - esac + tag_length_limit="$(expr 128 - $(echo "-$(uname -m)" | wc -c))" + normalized_tag="$(echo "${tag}" \ + | tr -dc '[:print:]' \ + | tr -c '[a-zA-Z0-9\_\.\-]' _ \ + | head -c "${tag_length_limit}" \ + )-$(uname -m)" + normalized_tags="${normalized_tags},${normalized_tag}" done + declare -a files_to_push=( + "${final_tarball_name}" + "${build_target}-version" + "${build_target}-builder-image-version" + "${build_target}-sha256sum" + ) + oci_image="${ARTEFACT_REGISTRY}/${ARTEFACT_REPOSITORY}/cached-artefacts/${build_target}:${normalized_tags}" + case ${build_target} in + kernel-nvidia-gpu) + files_to_push+=( + "kata-static-${build_target}-headers.tar.xz" + ) + ;; + kernel-nvidia-gpu-confidential) + files_to_push+=( + "kata-static-${build_target}-modules.tar.xz" + "kata-static-${build_target}-headers.tar.xz" + ) + ;; + kernel*-confidential) + files_to_push+=( + "kata-static-${build_target}-modules.tar.xz" + ) + ;; + *) + ;; + esac + oci_sha="$(oras push "${oci_image}" "${files_to_push[@]}" --format go-template='{{.reference}}' --no-tty)" + echo "${oci_sha}" > "${build_target}-oci-image" oras logout "${ARTEFACT_REGISTRY}" fi