Build and Upload OS image #677
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Build and Upload OS image | |
on: | |
workflow_dispatch: | |
inputs: | |
imageVersion: | |
description: "Semantic version including patch e.g. v<major>.<minor>.<patch> (only used for releases)" | |
required: false | |
isRelease: | |
description: 'Is this a release? (sets "ref" to special value "-")' | |
type: boolean | |
required: false | |
default: false | |
stream: | |
description: "Image stream / type. (Use 'stable' for releases, 'nightly' for regular non-release images, 'console' for images with serial console access and 'debug' for debug builds)" | |
type: choice | |
required: true | |
options: | |
- "debug" | |
- "console" | |
- "nightly" | |
- "stable" | |
ref: | |
type: string | |
description: "Git ref to checkout" | |
required: false | |
workflow_call: | |
inputs: | |
imageVersion: | |
description: "Semantic version including patch e.g. v<major>.<minor>.<patch> (only used for releases)" | |
required: false | |
type: string | |
isRelease: | |
description: 'Is this a release? (sets "ref" to special value "-")' | |
type: boolean | |
required: false | |
default: false | |
stream: | |
description: "Image stream / type. (Use 'stable' for releases, 'nightly' for regular non-release images and 'debug' for debug builds)" | |
type: string | |
required: true | |
ref: | |
type: string | |
description: "Git ref to checkout" | |
required: false | |
jobs: | |
build-settings: | |
name: "Determine build settings" | |
runs-on: ubuntu-22.04 | |
outputs: | |
ref: ${{ steps.ref.outputs.ref }} | |
stream: ${{ steps.stream.outputs.stream }} | |
imageType: ${{ steps.image-type.outputs.imageType }} | |
pkiSet: ${{ steps.pki-set.outputs.pkiSet }} | |
imageVersion: ${{ steps.image-version.outputs.imageVersion }} | |
imageName: ${{ steps.image-version.outputs.imageName }} | |
imageNameShort: ${{ steps.image-version.outputs.imageNameShort }} | |
imageApiBasePath: ${{ steps.image-version.outputs.imageApiBasePath }} | |
cliApiBasePath: ${{ steps.image-version.outputs.cliApiBasePath }} | |
steps: | |
- name: Checkout | |
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 | |
with: | |
ref: ${{ inputs.ref || github.head_ref }} | |
- name: Determine version | |
id: version | |
uses: ./.github/actions/pseudo_version | |
- name: Determine ref | |
id: ref | |
run: | | |
if [[ "${{ inputs.isRelease }}" = "true" ]]; then | |
echo "ref=-" | tee -a "$GITHUB_OUTPUT" | |
else | |
echo "ref=${{ steps.version.outputs.branchName }}" | tee -a "$GITHUB_OUTPUT" | |
fi | |
- name: Determine and validate stream | |
id: stream | |
run: | | |
if [[ "${{ inputs.isRelease }}" == "true" ]] && [[ "${{ inputs.stream }}" == "nightly" ]]; then | |
echo "Nightly builds are not allowed for releases" | |
exit 1 | |
fi | |
if [[ "${{ inputs.isRelease }}" != "true" ]] && [[ "${{ inputs.stream }}" == "stable" ]]; then | |
echo "Stable builds are only allowed for releases" | |
exit 1 | |
fi | |
echo "stream=${{ inputs.stream }}" | tee -a "$GITHUB_OUTPUT" | |
- name: Determine type of image build | |
shell: bash | |
id: image-type | |
run: | | |
case "${{ steps.stream.outputs.stream }}" in | |
"debug") | |
echo "imageType=debug" | tee -a "$GITHUB_OUTPUT" | |
;; | |
"console") | |
echo "imageType=console" | tee -a "$GITHUB_OUTPUT" | |
;; | |
*) | |
echo "imageType=default" | tee -a "$GITHUB_OUTPUT" | |
;; | |
esac | |
make-os-image: | |
name: "Build OS using mkosi" | |
needs: [build-settings] | |
runs-on: ubuntu-22.04 | |
# TODO(malt3): flatten outputs once possible | |
# https://github.com/community/community/discussions/17245 | |
outputs: | |
image-raw-aws-aws-nitro-tpm-sha256: ${{ steps.collect-hashes.outputs.image-raw-aws-aws-nitro-tpm-sha256 }} | |
image-raw-azure-azure-sev-snp-sha256: ${{ steps.collect-hashes.outputs.image-raw-azure-azure-sev-snp-sha256 }} | |
image-raw-gcp-gcp-sev-es-sha256: ${{ steps.collect-hashes.outputs.image-raw-gcp-gcp-sev-es-sha256 }} | |
image-raw-qemu-qemu-vtpm-sha256: ${{ steps.collect-hashes.outputs.image-raw-qemu-qemu-vtpm-sha256 }} | |
image-efi-aws-aws-nitro-tpm-sha256: ${{ steps.collect-hashes.outputs.image-efi-aws-aws-nitro-tpm-sha256 }} | |
image-efi-azure-azure-sev-snp-sha256: ${{ steps.collect-hashes.outputs.image-efi-azure-azure-sev-snp-sha256 }} | |
image-efi-gcp-gcp-sev-es-sha256: ${{ steps.collect-hashes.outputs.image-efi-gcp-gcp-sev-es-sha256 }} | |
image-efi-qemu-qemu-vtpm-sha256: ${{ steps.collect-hashes.outputs.image-efi-qemu-qemu-vtpm-sha256 }} | |
image-initrd-aws-aws-nitro-tpm-sha256: ${{ steps.collect-hashes.outputs.image-initrd-aws-aws-nitro-tpm-sha256 }} | |
image-initrd-azure-azure-sev-snp-sha256: ${{ steps.collect-hashes.outputs.image-initrd-azure-azure-sev-snp-sha256 }} | |
image-initrd-gcp-gcp-sev-es-sha256: ${{ steps.collect-hashes.outputs.image-initrd-gcp-gcp-sev-es-sha256 }} | |
image-initrd-qemu-qemu-vtpm-sha256: ${{ steps.collect-hashes.outputs.image-initrd-qemu-qemu-vtpm-sha256 }} | |
image-vmlinuz-aws-aws-nitro-tpm-sha256: ${{ steps.collect-hashes.outputs.image-vmlinuz-aws-aws-nitro-tpm-sha256 }} | |
image-vmlinuz-azure-azure-sev-snp-sha256: ${{ steps.collect-hashes.outputs.image-vmlinuz-azure-azure-sev-snp-sha256 }} | |
image-vmlinuz-gcp-gcp-sev-es-sha256: ${{ steps.collect-hashes.outputs.image-vmlinuz-gcp-gcp-sev-es-sha256 }} | |
image-vmlinuz-qemu-qemu-vtpm-sha256: ${{ steps.collect-hashes.outputs.image-vmlinuz-qemu-qemu-vtpm-sha256 }} | |
image-raw-changelog-aws-aws-nitro-tpm-sha256: ${{ steps.collect-hashes.outputs.image-raw-changelog-aws-aws-nitro-tpm-sha256 }} | |
image-raw-changelog-azure-azure-sev-snp-sha256: ${{ steps.collect-hashes.outputs.image-raw-changelog-azure-azure-sev-snp-sha256 }} | |
image-raw-changelog-gcp-gcp-sev-es-sha256: ${{ steps.collect-hashes.outputs.image-raw-changelog-gcp-gcp-sev-es-sha256 }} | |
image-raw-changelog-qemu-qemu-vtpm-sha256: ${{ steps.collect-hashes.outputs.image-raw-changelog-qemu-qemu-vtpm-sha256 }} | |
image-raw-manifest-aws-aws-nitro-tpm-sha256: ${{ steps.collect-hashes.outputs.image-raw-manifest-aws-aws-nitro-tpm-sha256 }} | |
image-raw-manifest-azure-azure-sev-snp-sha256: ${{ steps.collect-hashes.outputs.image-raw-manifest-azure-azure-sev-snp-sha256 }} | |
image-raw-manifest-gcp-gcp-sev-es-sha256: ${{ steps.collect-hashes.outputs.image-raw-manifest-gcp-gcp-sev-es-sha256 }} | |
image-raw-manifest-qemu-qemu-vtpm-sha256: ${{ steps.collect-hashes.outputs.image-raw-manifest-qemu-qemu-vtpm-sha256 }} | |
strategy: | |
fail-fast: false | |
matrix: | |
include: | |
- csp: aws | |
attestation_variant: aws-nitro-tpm | |
- csp: aws | |
attestation_variant: aws-sev-snp | |
- csp: azure | |
attestation_variant: azure-sev-snp | |
- csp: gcp | |
attestation_variant: gcp-sev-es | |
- csp: gcp | |
attestation_variant: gcp-sev-snp | |
- csp: qemu | |
attestation_variant: qemu-vtpm | |
- csp: openstack | |
attestation_variant: qemu-vtpm | |
steps: | |
- name: Checkout | |
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 | |
with: | |
ref: ${{ inputs.ref || github.head_ref }} | |
- uses: cachix/install-nix-action@v22 | |
- name: Build | |
shell: bash | |
working-directory: ${{ github.workspace }}/image | |
env: | |
TARGET: //image/system:${{ matrix.csp }}_${{ matrix.attestation_variant }}_${{ needs.build-settings.outputs.stream }} | |
run: | | |
echo "::group::Build" | |
bazel build --host_platform=@rules_nixpkgs_core//platforms:host "${TARGET}" | |
mkdir -p build | |
ln -s "$(bazel cquery --host_platform=@rules_nixpkgs_core//platforms:host --output=files "$TARGET")" build/image_dir | |
echo "::endgroup::" | |
- name: Collect hashes | |
id: collect-hashes | |
working-directory: ${{ github.workspace }}/build/image_dir | |
run: | | |
{ | |
echo "image-raw-${{ matrix.csp }}-${{ matrix.attestation_variant }}-sha256=$(sha256sum constellation.raw | head -c 64)" | |
echo "image-efi-${{ matrix.csp }}-${{ matrix.attestation_variant }}-sha256=$(sha256sum constellation.efi | head -c 64)" | |
echo "image-initrd-${{ matrix.csp }}-${{ matrix.attestation_variant }}-sha256=$(sha256sum constellation.initrd | head -c 64)" | |
echo "image-vmlinuz-${{ matrix.csp }}-${{ matrix.attestation_variant }}-sha256=$(sha256sum constellation.vmlinuz | head -c 64)" | |
echo "image-raw-changelog-${{ matrix.csp }}-${{ matrix.attestation_variant }}-sha256=$(sha256sum image.changelog | head -c 64)" | |
echo "image-raw-manifest-${{ matrix.csp }}-${{ matrix.attestation_variant }}-sha256=$(sha256sum image.manifest | head -c 64)" | |
} | tee -a "$GITHUB_OUTPUT" | |
- name: Upload raw OS image as artifact | |
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 | |
with: | |
name: image-${{ matrix.csp }}-${{ matrix.attestation_variant }} | |
path: ${{ github.workspace }}/build/image_dir/constellation.raw | |
- name: Upload individual OS parts as artifacts | |
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 | |
with: | |
name: parts-${{ matrix.csp }}-${{ matrix.attestation_variant }} | |
path: | | |
${{ github.workspace }}/build/image_dir/image.cmdline | |
${{ github.workspace }}/build/image_dir/constellation.efi | |
${{ github.workspace }}/build/image_dir/constellation.initrd | |
${{ github.workspace }}/build/image_dir/constellation.vmlinuz | |
- name: Upload manifest as artifact | |
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 | |
with: | |
name: manifest-${{ matrix.csp }}-${{ matrix.attestation_variant }} | |
path: | | |
${{ github.workspace }}/build/image_dir/image.changelog | |
${{ github.workspace }}/build/image_dir/image.manifest | |
upload-os-image: | |
name: "Upload OS image to CSP" | |
needs: [build-settings, make-os-image] | |
runs-on: ubuntu-22.04 | |
permissions: | |
id-token: write | |
contents: read | |
strategy: | |
fail-fast: false | |
matrix: | |
include: | |
- csp: aws | |
attestation_variant: aws-nitro-tpm | |
- csp: aws | |
attestation_variant: aws-sev-snp | |
- csp: azure | |
attestation_variant: azure-sev-snp | |
- csp: gcp | |
attestation_variant: gcp-sev-es | |
- csp: gcp | |
attestation_variant: gcp-sev-snp | |
- csp: qemu | |
attestation_variant: qemu-vtpm | |
- csp: openstack | |
attestation_variant: qemu-vtpm | |
env: | |
RAW_IMAGE_PATH: mkosi.output.${{ matrix.csp }}_${{ matrix.attestation_variant }}/fedora~38/image.raw | |
JSON_OUTPUT: mkosi.output.${{ matrix.csp }}_${{ matrix.attestation_variant }}/fedora~38/image-upload.json | |
AZURE_IMAGE_PATH: mkosi.output.azure_${{ matrix.attestation_variant }}/fedora~38/image.vhd | |
GCP_IMAGE_PATH: mkosi.output.gcp_${{ matrix.attestation_variant }}/fedora~38/image.tar.gz | |
SHORTNAME: ${{ needs.build-settings.outputs.imageNameShort }} | |
ATTESTATION_VARIANT: ${{ matrix.attestation_variant }} | |
steps: | |
- name: Checkout | |
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 | |
with: | |
ref: ${{ inputs.ref || github.head_ref }} | |
- name: Download OS image artifact | |
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 | |
with: | |
name: image-${{ matrix.csp }}-${{ matrix.attestation_variant }} | |
path: ${{ github.workspace }}/image/mkosi.output.${{ matrix.csp }}_${{ matrix.attestation_variant }}/fedora~38 | |
- name: Install tools | |
shell: bash | |
run: | | |
echo "::group::Install tools" | |
sudo apt-get update | |
sudo apt-get install -y \ | |
pigz \ | |
qemu-utils \ | |
python3-pip | |
echo "::endgroup::" | |
- name: Login to AWS | |
uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 | |
with: | |
role-to-assume: arn:aws:iam::795746500882:role/GitHubConstellationImagePipeline | |
aws-region: eu-central-1 | |
- name: Login to Azure | |
if: matrix.csp == 'azure' | |
uses: ./.github/actions/login_azure | |
with: | |
azure_credentials: ${{ secrets.AZURE_CREDENTIALS }} | |
- name: Login to GCP | |
if: matrix.csp == 'gcp' | |
uses: ./.github/actions/login_gcp | |
with: | |
service_account: "constellation-cos-builder@constellation-331613.iam.gserviceaccount.com" | |
- name: Upload AWS image | |
if: matrix.csp == 'aws' | |
shell: bash | |
working-directory: ${{ github.workspace }}/image | |
run: | | |
echo "::group::Upload AWS image" | |
bazel run //image/upload -- image aws \ | |
--verbose \ | |
--raw-image "${RAW_IMAGE_PATH}" \ | |
--attestation-variant "${ATTESTATION_VARIANT}" \ | |
--version "${SHORTNAME}" \ | |
--out "${JSON_OUTPUT}" | |
echo -e "Uploaded AWS image: \n\n\`\`\`\n$(jq < "${JSON_OUTPUT}")\n\`\`\`\n" >> "$GITHUB_STEP_SUMMARY" | |
echo "::endgroup::" | |
- name: Upload GCP image | |
if: matrix.csp == 'gcp' | |
shell: bash | |
working-directory: ${{ github.workspace }}/image | |
run: | | |
echo "::group::Upload GCP image" | |
upload/pack.sh gcp "${RAW_IMAGE_PATH}" "${GCP_IMAGE_PATH}" | |
bazel run //image/upload -- image gcp \ | |
--verbose \ | |
--raw-image "${GCP_IMAGE_PATH}" \ | |
--attestation-variant "${ATTESTATION_VARIANT}" \ | |
--version "${SHORTNAME}" \ | |
--out "${JSON_OUTPUT}" | |
echo -e "Uploaded GCP image: \n\n\`\`\`\n$(jq < "${JSON_OUTPUT}")\n\`\`\`\n" >> "$GITHUB_STEP_SUMMARY" | |
echo "::endgroup::" | |
- name: Upload Azure image | |
if: matrix.csp == 'azure' | |
shell: bash | |
working-directory: ${{ github.workspace }}/image | |
run: | | |
echo "::group::Upload Azure image" | |
upload/pack.sh azure "${RAW_IMAGE_PATH}" "${AZURE_IMAGE_PATH}" | |
bazel run //image/upload -- image azure \ | |
--verbose \ | |
--raw-image "${AZURE_IMAGE_PATH}" \ | |
--attestation-variant "${ATTESTATION_VARIANT}" \ | |
--version "${SHORTNAME}" \ | |
--out "${JSON_OUTPUT}" | |
echo -e "Uploaded Azure image: \n\n\`\`\`\n$(jq < "${JSON_OUTPUT}")\n\`\`\`\n" >> "$GITHUB_STEP_SUMMARY" | |
echo "::endgroup::" | |
- name: Upload OpenStack image | |
if: matrix.csp == 'openstack' | |
shell: bash | |
working-directory: ${{ github.workspace }}/image | |
run: | | |
echo "::group::Upload OpenStack image" | |
bazel run //image/upload -- image openstack \ | |
--verbose \ | |
--raw-image "${RAW_IMAGE_PATH}" \ | |
--attestation-variant "${ATTESTATION_VARIANT}" \ | |
--version "${SHORTNAME}" \ | |
--out "${JSON_OUTPUT}" | |
echo -e "Uploaded OpenStack image: \n\n\`\`\`\n$(jq < "${JSON_OUTPUT}")\n\`\`\`\n" >> "$GITHUB_STEP_SUMMARY" | |
echo "::endgroup::" | |
- name: Upload QEMU image | |
if: matrix.csp == 'qemu' | |
shell: bash | |
working-directory: ${{ github.workspace }}/image | |
run: | | |
echo "::group::Upload QEMU image" | |
bazel run //image/upload -- image qemu \ | |
--verbose \ | |
--raw-image "${RAW_IMAGE_PATH}" \ | |
--attestation-variant "${ATTESTATION_VARIANT}" \ | |
--version "${SHORTNAME}" \ | |
--out "${JSON_OUTPUT}" | |
echo -e "Uploaded QEMU image: \n\n\`\`\`\n$(jq < "${JSON_OUTPUT}")\n\`\`\`\n" >> "$GITHUB_STEP_SUMMARY" | |
echo "::endgroup::" | |
- name: Upload image lookup table as artifact | |
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 | |
with: | |
name: lookup-table | |
path: ${{ github.workspace }}/image/mkosi.output.*/*/image-upload*.json | |
calculate-pcrs: | |
name: "Calculate PCRs" | |
needs: [build-settings, make-os-image] | |
permissions: | |
id-token: write | |
contents: read | |
runs-on: ubuntu-22.04 | |
strategy: | |
fail-fast: false | |
matrix: | |
include: | |
- csp: aws | |
attestation_variant: aws-nitro-tpm | |
- csp: aws | |
attestation_variant: aws-sev-snp | |
- csp: azure | |
attestation_variant: azure-sev-snp | |
- csp: gcp | |
attestation_variant: gcp-sev-es | |
- csp: gcp | |
attestation_variant: gcp-sev-snp | |
- csp: qemu | |
attestation_variant: qemu-vtpm | |
- csp: openstack | |
attestation_variant: qemu-vtpm | |
steps: | |
- name: Checkout repository | |
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 | |
with: | |
ref: ${{ inputs.ref || github.head_ref }} | |
- name: Download OS image artifact | |
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 | |
with: | |
name: image-${{ matrix.csp }}-${{ matrix.attestation_variant }} | |
- name: Install dependencies | |
run: | | |
echo "::group::Install dependencies" | |
python -m pip install --user --require-hashes -r .github/workflows/build-os-image-requirements.txt | |
sudo apt-get update | |
sudo apt-get install -y systemd-container # for systemd-dissect | |
echo "::endgroup::" | |
- name: Calculate expected PCRs | |
working-directory: ${{ github.workspace }}/image/measured-boot | |
run: | | |
echo "::group::Calculate expected PCRs" | |
{ | |
./precalculate_pcr_4.sh ${{ github.workspace }}/image.raw ${{ github.workspace }}/pcr-4-${{ matrix.csp }}-${{ matrix.attestation_variant }}.json | |
./precalculate_pcr_9.sh ${{ github.workspace }}/image.raw ${{ github.workspace }}/pcr-9-${{ matrix.csp }}-${{ matrix.attestation_variant }}.json | |
./precalculate_pcr_12.sh ${{ github.workspace }}/image.raw ${{ github.workspace }}/pcr-12-${{ matrix.csp }}-${{ matrix.attestation_variant }}.json ${{ matrix.csp }} | |
} >> "$GITHUB_STEP_SUMMARY" | |
cp pcr-stable.json ${{ github.workspace }}/ | |
jq -sSc '.[0] * .[1] * .[2] * .[3]' ${{ github.workspace }}/pcr-* > ${{ github.workspace }}/pcrs-${{ matrix.csp }}-${{ matrix.attestation_variant }}.json | |
echo "::endgroup::" | |
- name: Add static PCRs | |
run: | | |
case ${{ matrix.csp }} in | |
aws) | |
yq e '.csp = "AWS" | | |
.attestationVariant = "${{ matrix.attestation_variant }}" | | |
.measurements.0.warnOnly = true | | |
.measurements.0.expected = "737f767a12f54e70eecbc8684011323ae2fe2dd9f90785577969d7a2013e8c12" | | |
.measurements.2.warnOnly = true | | |
.measurements.2.expected = "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969" | | |
.measurements.3.warnOnly = true | | |
.measurements.3.expected = "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969" | | |
.measurements.4.warnOnly = false | | |
.measurements.6.warnOnly = true | | |
.measurements.6.expected = "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969" | | |
.measurements.8.warnOnly = false | | |
.measurements.9.warnOnly = false | | |
.measurements.11.warnOnly = false | | |
.measurements.12.warnOnly = false | | |
.measurements.13.warnOnly = false | | |
.measurements.14.warnOnly = true | | |
.measurements.14.expected = "d7c4cc7ff7933022f013e03bdee875b91720b5b86cf1753cad830f95e791926f" | | |
.measurements.15.warnOnly = false' \ | |
-I 0 -o json -i "${{ github.workspace }}/pcrs-${{ matrix.csp }}-${{ matrix.attestation_variant }}.json" | |
;; | |
azure) | |
yq e '.csp = "Azure" | | |
.attestationVariant = "${{ matrix.attestation_variant }}" | | |
.measurements.1.warnOnly = true | | |
.measurements.1.expected = "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969" | | |
.measurements.2.warnOnly = true | | |
.measurements.2.expected = "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969" | | |
.measurements.3.warnOnly = true | | |
.measurements.3.expected = "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969" | | |
.measurements.4.warnOnly = false | | |
.measurements.8.warnOnly = false | | |
.measurements.9.warnOnly = false | | |
.measurements.11.warnOnly = false | | |
.measurements.12.warnOnly = false | | |
.measurements.13.warnOnly = false | | |
.measurements.14.warnOnly = true | | |
.measurements.14.expected = "d7c4cc7ff7933022f013e03bdee875b91720b5b86cf1753cad830f95e791926f" | | |
.measurements.15.warnOnly = false' \ | |
-I 0 -o json -i "${{ github.workspace }}/pcrs-${{ matrix.csp }}-${{ matrix.attestation_variant }}.json" | |
;; | |
gcp) | |
yq e '.csp = "GCP" | | |
.attestationVariant = "${{ matrix.attestation_variant }}" | | |
.measurements.1.warnOnly = true | | |
.measurements.1.expected = "745f2fb4235e4647aa0ad5ace781cd929eb68c28870e7dd5d1a1535854325e56" | | |
.measurements.2.warnOnly = true | | |
.measurements.2.expected = "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969" | | |
.measurements.3.warnOnly = true | | |
.measurements.3.expected = "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969" | | |
.measurements.4.warnOnly = false | | |
.measurements.6.warnOnly = true | | |
.measurements.6.expected = "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969" | | |
.measurements.8.warnOnly = false | | |
.measurements.9.warnOnly = false | | |
.measurements.11.warnOnly = false | | |
.measurements.12.warnOnly = false | | |
.measurements.13.warnOnly = false | | |
.measurements.14.warnOnly = true | | |
.measurements.14.expected = "d7c4cc7ff7933022f013e03bdee875b91720b5b86cf1753cad830f95e791926f" | | |
.measurements.15.warnOnly = false' \ | |
-I 0 -o json -i "${{ github.workspace }}/pcrs-${{ matrix.csp }}-${{ matrix.attestation_variant }}.json" | |
;; | |
openstack) | |
yq e '.csp = "OpenStack" | | |
.attestationVariant = "${{ matrix.attestation_variant }}" | | |
.measurements.4.warnOnly = false | | |
.measurements.8.warnOnly = false | | |
.measurements.9.warnOnly = false | | |
.measurements.11.warnOnly = false | | |
.measurements.12.warnOnly = false | | |
.measurements.13.warnOnly = false | | |
.measurements.15.warnOnly = false' \ | |
-I 0 -o json -i "${{ github.workspace }}/pcrs-${{ matrix.csp }}-${{ matrix.attestation_variant }}.json" | |
;; | |
qemu) | |
yq e '.csp = "QEMU" | | |
.attestationVariant = "${{ matrix.attestation_variant }}" | | |
.measurements.4.warnOnly = false | | |
.measurements.8.warnOnly = false | | |
.measurements.9.warnOnly = false | | |
.measurements.11.warnOnly = false | | |
.measurements.12.warnOnly = false | | |
.measurements.13.warnOnly = false | | |
.measurements.15.warnOnly = false' \ | |
-I 0 -o json -i "${{ github.workspace }}/pcrs-${{ matrix.csp }}-${{ matrix.attestation_variant }}.json" | |
;; | |
*) | |
echo "Unknown CSP: ${{ matrix.csp }}" | |
exit 1 | |
;; | |
esac | |
# TODO (malt3): Calculate PCR from firmware blob. | |
# AWS SNP machines have a different expected value for PCR 0. | |
if [[ ${{ matrix.attestation_variant }} = "aws-sev-snp" ]] | |
then | |
yq e '.csp = "AWS" | | |
.measurements.0.expected = "7b068c0c3ac29afe264134536b9be26f1d4ccd575b88d3c3ceabf36ac99c0278"' \ | |
-I 0 -o json -i "${{ github.workspace }}/pcrs-${{ matrix.csp }}-${{ matrix.attestation_variant }}.json" | |
fi | |
- name: Envelope measurements | |
shell: bash | |
run: | | |
echo "::group::Envelope measurements" | |
bazel run //image/upload -- measurements envelope \ | |
--in "${{ github.workspace }}/pcrs-${{ matrix.csp }}-${{ matrix.attestation_variant }}.json" \ | |
--out "${{ github.workspace }}/pcrs-${{ matrix.csp }}-${{ matrix.attestation_variant }}.json" \ | |
--version "${{ needs.build-settings.outputs.imageNameShort }}" \ | |
--csp "${{ matrix.csp }}" \ | |
--attestation-variant "${{ matrix.attestation_variant }}" | |
echo "::endgroup::" | |
- name: Upload expected measurements as artifact | |
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 | |
with: | |
name: measurements | |
path: pcrs-${{ matrix.csp }}-${{ matrix.attestation_variant }}.json | |
upload-pcrs: | |
name: "Sign & upload PCRs" | |
needs: [build-settings, calculate-pcrs] | |
permissions: | |
id-token: write | |
contents: read | |
runs-on: ubuntu-22.04 | |
steps: | |
- name: Checkout repository | |
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 | |
with: | |
ref: ${{ inputs.ref || github.head_ref }} | |
- name: Download measurements | |
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 | |
with: | |
name: measurements | |
- name: Login to AWS | |
uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 | |
with: | |
role-to-assume: arn:aws:iam::795746500882:role/GitHubConstellationImagePipeline | |
aws-region: eu-central-1 | |
- name: Install Cosign | |
uses: sigstore/cosign-installer@c85d0e205a72a294fe064f618a87dbac13084086 # v2.8.1 | |
- name: Install Rekor | |
shell: bash | |
run: | | |
curl -fsSLO https://github.com/sigstore/rekor/releases/download/v0.12.0/rekor-cli-linux-amd64 | |
sudo install rekor-cli-linux-amd64 /usr/local/bin/rekor-cli | |
rm rekor-cli-linux-amd64 | |
- name: Merge measurements | |
shell: bash | |
run: | | |
echo "::group::Merge measurements" | |
bazel run //image/upload -- measurements merge \ | |
--out measurements.json \ | |
pcrs-*.json | |
echo "::endgroup::" | |
- name: Sign measurements | |
if: inputs.stream != 'debug' | |
shell: bash | |
env: | |
COSIGN_PUBLIC_KEY: ${{ inputs.isRelease && secrets.COSIGN_PUBLIC_KEY || secrets.COSIGN_DEV_PUBLIC_KEY }} | |
COSIGN_PRIVATE_KEY: ${{ inputs.isRelease && secrets.COSIGN_PRIVATE_KEY || secrets.COSIGN_DEV_PRIVATE_KEY }} | |
COSIGN_PASSWORD: ${{ inputs.isRelease && secrets.COSIGN_PASSWORD || secrets.COSIGN_DEV_PASSWORD }} | |
run: | | |
echo "${COSIGN_PUBLIC_KEY}" > cosign.pub | |
# Enabling experimental mode also publishes signature to Rekor | |
COSIGN_EXPERIMENTAL=1 cosign sign-blob --key env://COSIGN_PRIVATE_KEY \ | |
"${{ github.workspace }}/measurements.json" > "${{ github.workspace }}/measurements.json.sig" | |
# Verify - As documentation & check | |
# Local Signature (input: artifact, key, signature) | |
cosign verify-blob --key cosign.pub \ | |
--signature "measurements.json.sig" \ | |
"measurements.json" | |
# Transparency Log Signature (input: artifact, key) | |
uuid=$(rekor-cli search --artifact "${{ github.workspace }}/measurements.json" | tail -n 1) | |
sig=$(rekor-cli get --uuid="${uuid}" --format=json | jq -r .Body.HashedRekordObj.signature.content) | |
cosign verify-blob --key cosign.pub --signature <(echo "${sig}") "${{ github.workspace }}/measurements.json" | |
- name: Create stub signature file | |
if: inputs.stream == 'debug' | |
shell: bash | |
run: | | |
echo "THOSE MEASUREMENTS BELONG TO A DEBUG IMAGE. THOSE ARE NOT SINGED BY ANY KEY." > "${{ github.workspace }}/measurements.json.sig" | |
- name: Upload measurements | |
shell: bash | |
run: | | |
echo "::group::Upload measurements" | |
bazel run //image/upload -- measurements upload \ | |
--measurements measurements.json \ | |
--signature measurements.json.sig | |
echo "::endgroup::" | |
generate-sbom: | |
name: "Generate SBOM" | |
needs: [build-settings, make-os-image] | |
permissions: | |
id-token: write | |
contents: read | |
runs-on: ubuntu-22.04 | |
steps: | |
- name: Login to AWS | |
uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 | |
with: | |
role-to-assume: arn:aws:iam::795746500882:role/GitHubConstellationImagePipeline | |
aws-region: eu-central-1 | |
- name: Install squashfs tools | |
run: | | |
echo "::group::Install squashfs tools" | |
sudo apt-get update | |
sudo apt-get install -y squashfs-tools | |
echo "::endgroup::" | |
- name: Download rootfs | |
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 | |
with: | |
# downloading / using only the QEMU rootfs is fine | |
# since the images only differ in the ESP partition | |
name: parts-qemu-qemu-vtpm | |
- name: Download manifest | |
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 | |
with: | |
# downloading / using only the QEMU manifest is fine | |
# since the images only differ in the ESP partition | |
name: manifest-qemu-qemu-vtpm | |
- name: Unpack squashfs | |
run: | | |
echo "::group::Unpack squashfs" | |
unsquashfs -user-xattrs -d image.root.tree image.root-x86-64.raw | |
echo "::endgroup::" | |
- name: Create SBOM in SPDX fromat | |
uses: anchore/sbom-action@78fc58e266e87a38d4194b2137a3d4e9bcaf7ca1 # v0.14.3 | |
with: | |
path: image.root.tree | |
artifact-name: sbom.spdx.json | |
output-file: sbom.spdx.json | |
format: spdx-json | |
- name: Create SBOM in CycloneDX fromat | |
uses: anchore/sbom-action@78fc58e266e87a38d4194b2137a3d4e9bcaf7ca1 # v0.14.3 | |
with: | |
path: image.root.tree | |
artifact-name: sbom.cyclonedx.json | |
output-file: sbom.cyclonedx.json | |
format: cyclonedx-json | |
- name: Create SBOM in Syft fromat | |
uses: anchore/sbom-action@78fc58e266e87a38d4194b2137a3d4e9bcaf7ca1 # v0.14.3 | |
with: | |
path: image.root.tree | |
artifact-name: sbom.syft.json | |
output-file: sbom.syft.json | |
format: syft-json | |
- name: Combine hashes | |
run: | | |
cat > SHA256SUMS <<EOF | |
${{ needs.make-os-image.outputs.image-raw-aws-aws-nitro-tpm-sha256 }} aws/image.raw | |
${{ needs.make-os-image.outputs.image-raw-changelog-aws-aws-nitro-tpm-sha256 }} aws/image.changelog | |
${{ needs.make-os-image.outputs.image-raw-manifest-aws-aws-nitro-tpm-sha256 }} aws/image.manifest | |
${{ needs.make-os-image.outputs.image-efi-aws-aws-nitro-tpm-sha256 }} aws/constellation.efi | |
${{ needs.make-os-image.outputs.image-initrd-aws-aws-nitro-tpm-sha256 }} aws/image.initrd | |
${{ needs.make-os-image.outputs.image-vmlinuz-aws-aws-nitro-tpm-sha256 }} aws/constellation.vmlinuz | |
${{ needs.make-os-image.outputs.image-raw-azure-azure-sev-snp-sha256 }} azure/image.raw | |
${{ needs.make-os-image.outputs.image-raw-changelog-azure-azure-sev-snp-sha256 }} azure/image.changelog | |
${{ needs.make-os-image.outputs.image-raw-manifest-azure-azure-sev-snp-sha256 }} azure/image.manifest | |
${{ needs.make-os-image.outputs.image-efi-azure-azure-sev-snp-sha256 }} azure/constellation.efi | |
${{ needs.make-os-image.outputs.image-initrd-azure-azure-sev-snp-sha256 }} azure/image.initrd | |
${{ needs.make-os-image.outputs.image-vmlinuz-azure-azure-sev-snp-sha256 }} azure/constellation.vmlinuz | |
${{ needs.make-os-image.outputs.image-raw-gcp-gcp-sev-es-sha256 }} gcp/image.raw | |
${{ needs.make-os-image.outputs.image-raw-changelog-gcp-gcp-sev-es-sha256 }} gcp/image.changelog | |
${{ needs.make-os-image.outputs.image-raw-manifest-gcp-gcp-sev-es-sha256 }} gcp/image.manifest | |
${{ needs.make-os-image.outputs.image-efi-gcp-gcp-sev-es-sha256 }} gcp/constellation.efi | |
${{ needs.make-os-image.outputs.image-initrd-gcp-gcp-sev-es-sha256 }} gcp/image.initrd | |
${{ needs.make-os-image.outputs.image-vmlinuz-gcp-gcp-sev-es-sha256 }} gcp/constellation.vmlinuz | |
${{ needs.make-os-image.outputs.image-raw-qemu-qemu-vtpm-sha256 }} qemu/image.raw | |
${{ needs.make-os-image.outputs.image-raw-changelog-qemu-qemu-vtpm-sha256 }} qemu/image.changelog | |
${{ needs.make-os-image.outputs.image-raw-manifest-qemu-qemu-vtpm-sha256 }} qemu/image.manifest | |
${{ needs.make-os-image.outputs.image-efi-qemu-qemu-vtpm-sha256 }} qemu/constellation.efi | |
${{ needs.make-os-image.outputs.image-initrd-qemu-qemu-vtpm-sha256 }} qemu/image.initrd | |
${{ needs.make-os-image.outputs.image-vmlinuz-qemu-qemu-vtpm-sha256 }} qemu/constellation.vmlinuz | |
EOF | |
cat SHA256SUMS | |
echo -e "SHA256SUMS:\n\`\`\`\n$(cat SHA256SUMS)\n\`\`\`" >> "$GITHUB_STEP_SUMMARY" | |
- name: Upload SBOMs to S3 | |
shell: bash | |
run: | | |
sboms='sbom.spdx.json sbom.cyclonedx.json sbom.syft.json' | |
manifests='image.manifest image.changelog' | |
hashes='SHA256SUMS' | |
for file in ${sboms} ${manifests} ${hashes}; do | |
aws s3 cp \ | |
"${file}" \ | |
"s3://cdn-constellation-backend/${{needs.build-settings.outputs.imageApiBasePath}}/${file}" \ | |
--no-progress | |
done | |
upload-artifacts: | |
name: "Upload image lookup table and CLI compatibility info" | |
runs-on: ubuntu-22.04 | |
needs: [build-settings, upload-os-image] | |
permissions: | |
id-token: write | |
contents: read | |
steps: | |
- name: Checkout repository | |
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 | |
with: | |
ref: ${{ inputs.ref || github.head_ref }} | |
- name: Download image lookup table | |
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3 | |
with: | |
name: lookup-table | |
- name: Login to AWS | |
uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2.2.0 | |
with: | |
role-to-assume: arn:aws:iam::795746500882:role/GitHubConstellationImagePipeline | |
aws-region: eu-central-1 | |
- name: Upload lookup table to S3 | |
shell: bash | |
run: bazel run //image/upload -- info --verbose mkosi.output.*/*/image-upload*.json | |
- name: Checkout | |
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 | |
with: | |
ref: ${{ inputs.ref || github.head_ref }} | |
- name: Setup Go environment | |
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 | |
with: | |
go-version: "1.20.7" | |
cache: true | |
- name: Create CLI compatibility information artifact | |
shell: bash | |
run: | | |
go run ./hack/cli-k8s-compatibility/main.go \ | |
--ref=${{ needs.build-settings.outputs.ref }} \ | |
--stream=${{ needs.build-settings.outputs.stream }} \ | |
--version=${{ needs.build-settings.outputs.imageVersion }} \ | |
add-image-version-to-versionsapi: | |
needs: [upload-artifacts, build-settings] | |
name: "Add image version to versionsapi" | |
if: needs.build-settings.outputs.ref != '-' | |
permissions: | |
contents: read | |
id-token: write | |
uses: ./.github/workflows/versionsapi.yml | |
with: | |
command: add | |
ref: ${{ needs.build-settings.outputs.ref }} | |
stream: ${{ needs.build-settings.outputs.stream }} | |
version: ${{ needs.build-settings.outputs.imageVersion }} | |
kind: "image" | |
add_latest: true | |
add-cli-version-to-versionsapi: | |
needs: [upload-artifacts, build-settings, add-image-version-to-versionsapi] | |
name: "Add CLI version to versionsapi" | |
if: needs.build-settings.outputs.ref != '-' | |
permissions: | |
contents: read | |
id-token: write | |
uses: ./.github/workflows/versionsapi.yml | |
with: | |
command: add | |
ref: ${{ needs.build-settings.outputs.ref }} | |
stream: ${{ needs.build-settings.outputs.stream }} | |
version: ${{ needs.build-settings.outputs.imageVersion }} | |
kind: "cli" | |
add_latest: true |