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 <magnuskulke@microsoft.com>
This commit is contained in:
Magnus Kulke 2024-10-16 17:28:50 +02:00
parent 02f5fd94bd
commit b93f5390ce
3 changed files with 92 additions and 40 deletions

View File

@ -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

View File

@ -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

View File

@ -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