From 34367ea3cc5ab21a32fb01f830c095f39b032e31 Mon Sep 17 00:00:00 2001 From: Malte Poll Date: Wed, 19 Oct 2022 13:10:15 +0200 Subject: [PATCH] Create mkosi image build pipeline --- .github/actions/setup_mkosi/action.yaml | 42 +++ .github/workflows/build-os-image.yml | 327 ++++++++++++++++++ .../internal/kubernetes/k8sapi/constants.go | 5 +- cli/internal/cloudcmd/create.go | 3 + cli/internal/libvirt/Dockerfile | 5 + .../nvram/constellation_vars.testing.fd | Bin 0 -> 131072 bytes .../terraform/terraform/azure/main.tf | 2 + .../terraform/azure/modules/scale_set/main.tf | 2 +- .../azure/modules/scale_set/variables.tf | 6 + .../terraform/terraform/azure/variables.tf | 6 + cli/internal/terraform/terraform/qemu/main.tf | 4 + .../qemu/modules/instance_group/domain.xsl | 23 +- .../qemu/modules/instance_group/main.tf | 15 +- .../qemu/modules/instance_group/variables.tf | 11 + .../terraform/terraform/qemu/variables.tf | 11 + cli/internal/terraform/variables.go | 18 + debugd/internal/debugd/constants.go | 10 +- .../internal/debugd/deploy/download_test.go | 2 +- debugd/internal/debugd/deploy/service.go | 2 +- debugd/internal/debugd/server/server_test.go | 4 +- image/README.md | 246 ++++++++----- image/mkosi/.gitattributes | 0 image/mkosi/.gitignore | 5 + image/mkosi/Makefile | 54 +++ image/mkosi/README.md | 187 ++++++++++ image/mkosi/mkosi.cache/.gitkeep | 0 image/mkosi/mkosi.conf.d/azure.conf | 3 + image/mkosi/mkosi.conf.d/containers.conf | 9 + image/mkosi/mkosi.conf.d/gcp.conf | 3 + image/mkosi/mkosi.conf.d/mkosi.conf | 22 ++ image/mkosi/mkosi.conf.d/network.conf | 8 + image/mkosi/mkosi.conf.d/secure-boot-tpm.conf | 8 + image/mkosi/mkosi.conf.d/tools.conf | 8 + image/mkosi/mkosi.files/mkosi.azure.conf | 3 + image/mkosi/mkosi.files/mkosi.gcp.conf | 3 + image/mkosi/mkosi.files/mkosi.qemu.conf | 3 + image/mkosi/mkosi.finalize | 12 + image/mkosi/mkosi.postinst | 22 ++ .../etc/dracut.conf.d/90-networkd.conf | 4 + .../etc/dracut.conf.d/azure.conf | 3 + .../mkosi.skeleton/etc/dracut.conf.d/gce.conf | 2 + image/mkosi/mkosi.skeleton/etc/fstab | 5 + .../etc/profile.d/constellation.sh | 4 + .../usr/etc/containerd/config.toml | 216 ++++++++++++ .../configure-constel-csp.service | 1 + .../constellation-state-disk-generator | 0 .../google-nvme-disk.service | 15 + .../39constellation-mount/google-nvme-disk.sh | 23 ++ .../39constellation-mount/module-setup.sh | 56 +++ .../prepare-state-disk.service | 17 + .../prepare-state-disk.sh | 11 + .../lib/environment.d/99-constellation.conf | 2 + .../usr/lib/modules-load.d/k8s.conf | 2 + .../usr/lib/sysctl.d/10-cilium.conf | 3 + .../usr/lib/sysctl.d/10-k8s.conf | 9 + .../usr/lib/systemd/network/20-wired.network | 5 + .../usr/lib/systemd/network/21-azure.network | 6 + .../system-preset/30-constellation.preset | 5 + .../system/configure-constel-csp.service | 10 + .../system/constellation-bootstrapper.service | 15 + .../system/containerd.service.d/local.conf | 3 + .../usr/lib/systemd/system/tpm-pcrs.service | 11 + .../usr/lib/sysusers.d/constellation.conf | 2 + .../usr/lib/tmpfiles.d/constellation.conf | 8 + .../usr/lib/udev/google_nvme_id | 245 +++++++++++++ .../udev/rules.d/64-gce-disk-removal.rules | 17 + .../lib/udev/rules.d/65-gce-disk-naming.rules | 37 ++ .../udev/rules.d/98-override-systemd.rules | 3 + .../usr/libexec/constellation-pcrs | 10 + image/mkosi/pki_testing/KEK.auth | Bin 0 -> 4143 bytes image/mkosi/pki_testing/KEK.cer | Bin 0 -> 995 bytes image/mkosi/pki_testing/KEK.crt | 23 ++ image/mkosi/pki_testing/KEK.esl | Bin 0 -> 2599 bytes .../MicCorKEKCA2011_2011-06-24.crt | Bin 0 -> 1516 bytes .../MicCorKEKCA2011_2011-06-24.esl | Bin 0 -> 1560 bytes .../MicCorUEFCA2011_2011-06-27.crt | Bin 0 -> 1556 bytes .../MicCorUEFCA2011_2011-06-27.esl | Bin 0 -> 1600 bytes .../MicWinProPCA2011_2011-10-19.crt | Bin 0 -> 1499 bytes .../MicWinProPCA2011_2011-10-19.esl | Bin 0 -> 1543 bytes image/mkosi/pki_testing/PK.auth | Bin 0 -> 2585 bytes image/mkosi/pki_testing/PK.cer | Bin 0 -> 997 bytes image/mkosi/pki_testing/PK.crt | 23 ++ image/mkosi/pki_testing/PK.esl | Bin 0 -> 1041 bytes image/mkosi/pki_testing/db.auth | Bin 0 -> 5717 bytes image/mkosi/pki_testing/db.cer | Bin 0 -> 989 bytes image/mkosi/pki_testing/db.crt | 23 ++ image/mkosi/pki_testing/db.esl | Bin 0 -> 4176 bytes image/mkosi/secure-boot/azure/delete.sh | 74 ++++ image/mkosi/secure-boot/azure/extract_vmgs.sh | 65 ++++ image/mkosi/secure-boot/azure/launch.sh | 101 ++++++ .../mkosi/secure-boot/generate_nvram_vars.sh | 89 +++++ image/mkosi/secure-boot/genkeys.sh | 65 ++++ image/mkosi/secure-boot/signed-shim.sh | 45 +++ .../mkosi/secure-boot/templates/dev_KEK.conf | 20 ++ image/mkosi/secure-boot/templates/dev_PK.conf | 20 ++ image/mkosi/secure-boot/templates/dev_db.conf | 20 ++ .../mkosi/secure-boot/templates/prod_KEK.conf | 20 ++ .../mkosi/secure-boot/templates/prod_PK.conf | 20 ++ .../mkosi/secure-boot/templates/prod_db.conf | 20 ++ .../secure-boot/templates/testing_KEK.conf | 20 ++ .../secure-boot/templates/testing_PK.conf | 20 ++ .../secure-boot/templates/testing_db.conf | 20 ++ image/mkosi/upload/pack.sh | 57 +++ image/mkosi/upload/upload_azure.sh | 190 ++++++++++ image/mkosi/upload/upload_gcp.sh | 27 ++ internal/config/config.go | 13 +- internal/config/config_doc.go | 19 +- 107 files changed, 2733 insertions(+), 105 deletions(-) create mode 100644 .github/actions/setup_mkosi/action.yaml create mode 100644 .github/workflows/build-os-image.yml create mode 100644 cli/internal/libvirt/nvram/constellation_vars.testing.fd create mode 100644 image/mkosi/.gitattributes create mode 100644 image/mkosi/.gitignore create mode 100644 image/mkosi/Makefile create mode 100644 image/mkosi/README.md create mode 100644 image/mkosi/mkosi.cache/.gitkeep create mode 100644 image/mkosi/mkosi.conf.d/azure.conf create mode 100644 image/mkosi/mkosi.conf.d/containers.conf create mode 100644 image/mkosi/mkosi.conf.d/gcp.conf create mode 100644 image/mkosi/mkosi.conf.d/mkosi.conf create mode 100644 image/mkosi/mkosi.conf.d/network.conf create mode 100644 image/mkosi/mkosi.conf.d/secure-boot-tpm.conf create mode 100644 image/mkosi/mkosi.conf.d/tools.conf create mode 100644 image/mkosi/mkosi.files/mkosi.azure.conf create mode 100644 image/mkosi/mkosi.files/mkosi.gcp.conf create mode 100644 image/mkosi/mkosi.files/mkosi.qemu.conf create mode 100755 image/mkosi/mkosi.finalize create mode 100755 image/mkosi/mkosi.postinst create mode 100644 image/mkosi/mkosi.skeleton/etc/dracut.conf.d/90-networkd.conf create mode 100644 image/mkosi/mkosi.skeleton/etc/dracut.conf.d/azure.conf create mode 100644 image/mkosi/mkosi.skeleton/etc/dracut.conf.d/gce.conf create mode 100644 image/mkosi/mkosi.skeleton/etc/fstab create mode 100755 image/mkosi/mkosi.skeleton/etc/profile.d/constellation.sh create mode 100644 image/mkosi/mkosi.skeleton/usr/etc/containerd/config.toml create mode 120000 image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/configure-constel-csp.service create mode 100755 image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/constellation-state-disk-generator create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/google-nvme-disk.service create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/google-nvme-disk.sh create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/module-setup.sh create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/prepare-state-disk.service create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/prepare-state-disk.sh create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/environment.d/99-constellation.conf create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/modules-load.d/k8s.conf create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/sysctl.d/10-cilium.conf create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/sysctl.d/10-k8s.conf create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/systemd/network/20-wired.network create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/systemd/network/21-azure.network create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/systemd/system-preset/30-constellation.preset create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/systemd/system/configure-constel-csp.service create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/systemd/system/constellation-bootstrapper.service create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/systemd/system/containerd.service.d/local.conf create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/systemd/system/tpm-pcrs.service create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/sysusers.d/constellation.conf create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/tmpfiles.d/constellation.conf create mode 100755 image/mkosi/mkosi.skeleton/usr/lib/udev/google_nvme_id create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/udev/rules.d/64-gce-disk-removal.rules create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/udev/rules.d/65-gce-disk-naming.rules create mode 100644 image/mkosi/mkosi.skeleton/usr/lib/udev/rules.d/98-override-systemd.rules create mode 100755 image/mkosi/mkosi.skeleton/usr/libexec/constellation-pcrs create mode 100644 image/mkosi/pki_testing/KEK.auth create mode 100644 image/mkosi/pki_testing/KEK.cer create mode 100644 image/mkosi/pki_testing/KEK.crt create mode 100644 image/mkosi/pki_testing/KEK.esl create mode 100644 image/mkosi/pki_testing/MicCorKEKCA2011_2011-06-24.crt create mode 100644 image/mkosi/pki_testing/MicCorKEKCA2011_2011-06-24.esl create mode 100644 image/mkosi/pki_testing/MicCorUEFCA2011_2011-06-27.crt create mode 100644 image/mkosi/pki_testing/MicCorUEFCA2011_2011-06-27.esl create mode 100644 image/mkosi/pki_testing/MicWinProPCA2011_2011-10-19.crt create mode 100644 image/mkosi/pki_testing/MicWinProPCA2011_2011-10-19.esl create mode 100644 image/mkosi/pki_testing/PK.auth create mode 100644 image/mkosi/pki_testing/PK.cer create mode 100644 image/mkosi/pki_testing/PK.crt create mode 100644 image/mkosi/pki_testing/PK.esl create mode 100644 image/mkosi/pki_testing/db.auth create mode 100644 image/mkosi/pki_testing/db.cer create mode 100644 image/mkosi/pki_testing/db.crt create mode 100644 image/mkosi/pki_testing/db.esl create mode 100755 image/mkosi/secure-boot/azure/delete.sh create mode 100755 image/mkosi/secure-boot/azure/extract_vmgs.sh create mode 100755 image/mkosi/secure-boot/azure/launch.sh create mode 100755 image/mkosi/secure-boot/generate_nvram_vars.sh create mode 100755 image/mkosi/secure-boot/genkeys.sh create mode 100755 image/mkosi/secure-boot/signed-shim.sh create mode 100644 image/mkosi/secure-boot/templates/dev_KEK.conf create mode 100644 image/mkosi/secure-boot/templates/dev_PK.conf create mode 100644 image/mkosi/secure-boot/templates/dev_db.conf create mode 100644 image/mkosi/secure-boot/templates/prod_KEK.conf create mode 100644 image/mkosi/secure-boot/templates/prod_PK.conf create mode 100644 image/mkosi/secure-boot/templates/prod_db.conf create mode 100644 image/mkosi/secure-boot/templates/testing_KEK.conf create mode 100644 image/mkosi/secure-boot/templates/testing_PK.conf create mode 100644 image/mkosi/secure-boot/templates/testing_db.conf create mode 100755 image/mkosi/upload/pack.sh create mode 100755 image/mkosi/upload/upload_azure.sh create mode 100755 image/mkosi/upload/upload_gcp.sh diff --git a/.github/actions/setup_mkosi/action.yaml b/.github/actions/setup_mkosi/action.yaml new file mode 100644 index 000000000..d7ab102e3 --- /dev/null +++ b/.github/actions/setup_mkosi/action.yaml @@ -0,0 +1,42 @@ +name: Setup mkosi +description: Install mkosi and all its dependencies +inputs: + version: + description: "Version (commit hash) of mkosi to install." + required: true +runs: + using: composite + steps: + - name: Dependencies + shell: bash + run: | + echo "::group::Dependencies" + echo "deb-src http://archive.ubuntu.com/ubuntu/ $(lsb_release -cs) main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list + sudo add-apt-repository ppa:michel-slm/kernel-utils + sudo apt-get update + sudo apt-get install --assume-yes --no-install-recommends \ + dnf \ + makepkg \ + systemd-container \ + qemu-system-x86 \ + ovmf \ + e2fsprogs \ + squashfs-tools + echo "::endgroup::" + # Try to eliminate "Failed to dissect image: Connection timed out" errors from nspawn by compiling + # systemd-nspawn from v251 from source. + - name: Update systemd-nspawn + shell: bash + working-directory: ${{ github.action_path }} + run: | + echo "::group::Update systemd-nspawn" + sudo apt-get build-dep systemd + git clone https://github.com/systemd/systemd-stable --branch v251.2 --depth=1 + meson systemd-stable/build systemd-stable + ninja -C systemd-stable/build systemd-nspawn + sudo ln -svf $PWD/systemd-stable/build/systemd-nspawn $(which systemd-nspawn) + systemd-nspawn --version + echo "::endgroup::" + - name: Install + shell: bash + run: sudo python3 -m pip install git+https://github.com/systemd/mkosi.git@${{ inputs.version }} diff --git a/.github/workflows/build-os-image.yml b/.github/workflows/build-os-image.yml new file mode 100644 index 000000000..2285be363 --- /dev/null +++ b/.github/workflows/build-os-image.yml @@ -0,0 +1,327 @@ +name: Build and Upload OS image +on: + workflow_dispatch: + inputs: + imageVersion: + description: "Semantic version including patch e.g. v.. (only used for releases)" + required: false + debug: + description: "Build debug image" + type: boolean + default: false + required: false + +jobs: + build-dependencies: + name: "Build binaries for embedding in the OS" + runs-on: ubuntu-22.04 + permissions: + contents: read + packages: read + steps: + - name: Checkout + uses: actions/checkout@e2f20e631ae6d7dd3b768f56a5d2af784dd54791 + + - name: Build bootstrapper + if: ${{ inputs.debug == false }} + uses: ./.github/actions/build_bootstrapper + with: + outputPath: ${{ github.workspace }}/build/bootstrapper + + - name: Build debugd + if: ${{ inputs.debug == true }} + uses: ./.github/actions/build_debugd + with: + outputPath: ${{ github.workspace }}/build/bootstrapper + + - name: Build disk-mapper + uses: ./.github/actions/build_disk_mapper + with: + outputPath: ${{ github.workspace }}/build/disk-mapper + + - name: Upload dependencies + uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 + with: + name: dependencies + path: | + ${{ github.workspace }}/build/bootstrapper + ${{ github.workspace }}/build/disk-mapper + + - name: Collect hashes + run: | + echo "::set-output name=bootstrapper-sha256::$(sha256sum bootstrapper)" + echo "::set-output name=disk-mapper-sha256::$(sha256sum disk-mapper)" + working-directory: ${{ github.workspace }}/build + + make-os-image: + name: "Build OS using mkosi" + needs: build-dependencies + runs-on: ubuntu-22.04 + strategy: + matrix: + csp: [azure, gcp, qemu] + steps: + - name: Checkout + uses: actions/checkout@e2f20e631ae6d7dd3b768f56a5d2af784dd54791 + + - name: Download build dependencies + uses: actions/download-artifact@fb598a63ae348fa914e94cd0ff38f362e927b741 + with: + name: dependencies + path: ${{ github.workspace }}/build + + - name: Mark bootstrapper and disk-mapper as executable + run: | + chmod +x ${{ github.workspace }}/build/bootstrapper + chmod +x ${{ github.workspace }}/build/disk-mapper + + - name: Setup mkosi + uses: ./.github/actions/setup_mkosi + with: + version: 1750fc261a071f39c54f8b64ce2424195f750ee0 + + - name: Prepare PKI for secure boot signing + shell: bash + run: | + ln -s pki_testing pki + echo "${DB_KEY}" > pki/db.key + working-directory: ${{ github.workspace }}/image/mkosi + env: + DB_KEY: ${{ secrets.SECURE_BOOT_TESTING_DB_KEY }} + + - name: Build + shell: bash + run: | + echo "::group::Build" + sudo make "${CSP}" + echo "::endgroup::" + working-directory: ${{ github.workspace }}/image/mkosi + env: + BOOTSTRAPPER_BINARY: ${{ github.workspace }}/build/bootstrapper + DISK_MAPPER_BINARY: ${{ github.workspace }}/build/disk-mapper + CSP: ${{ matrix.csp }} + + - name: Upload raw OS image as artifact + uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 + with: + name: image-${{ matrix.csp }} + path: ${{ github.workspace }}/image/mkosi/mkosi.output.${{ matrix.csp }}/fedora~36/image.raw + if: always() + continue-on-error: true + + - name: Upload individual OS parts as artifacts + uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 + with: + name: parts-${{ matrix.csp }} + path: | + ${{ github.workspace }}/image/mkosi/mkosi.output.${{ matrix.csp }}/fedora~36/image.cmdline + ${{ github.workspace }}/image/mkosi/mkosi.output.${{ matrix.csp }}/fedora~36/image.efi + ${{ github.workspace }}/image/mkosi/mkosi.output.${{ matrix.csp }}/fedora~36/image.initrd + ${{ github.workspace }}/image/mkosi/mkosi.output.${{ matrix.csp }}/fedora~36/image.root.raw + ${{ github.workspace }}/image/mkosi/mkosi.output.${{ matrix.csp }}/fedora~36/image.root.roothash + ${{ github.workspace }}/image/mkosi/mkosi.output.${{ matrix.csp }}/fedora~36/image.root.verity + ${{ github.workspace }}/image/mkosi/mkosi.output.${{ matrix.csp }}/fedora~36/image.vmlinuz + if: always() + continue-on-error: true + + - name: Upload manifest as artifact + uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 + with: + name: manifest-${{ matrix.csp }} + path: | + ${{ github.workspace }}/image/mkosi/mkosi.output.${{ matrix.csp }}/fedora~36/image.raw.changelog + ${{ github.workspace }}/image/mkosi/mkosi.output.${{ matrix.csp }}/fedora~36/image.raw.manifest + if: always() + continue-on-error: true + + upload-os-image: + name: "Upload OS image to CSP" + needs: make-os-image + runs-on: ubuntu-22.04 + strategy: + matrix: + csp: [azure, gcp] + upload-variant: [""] + include: + - csp: azure + upload-variant: TrustedLaunch + steps: + - name: Checkout + uses: actions/checkout@e2f20e631ae6d7dd3b768f56a5d2af784dd54791 + + - name: Download OS image artifact + uses: actions/download-artifact@fb598a63ae348fa914e94cd0ff38f362e927b741 + with: + name: image-${{ matrix.csp }} + path: ${{ github.workspace }}/image/mkosi/mkosi.output.${{ matrix.csp }}/fedora~36 + + - name: Install tools + shell: bash + run: | + echo "::group::Install tools" + sudo apt-get update + sudo apt-get install -y pigz qemu-utils + echo "::endgroup::" + + - name: Login to Azure + uses: azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 + if: ${{ matrix.csp == 'azure' }} + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Login to GCP + uses: ./.github/actions/gcp_login + if: ${{ matrix.csp == 'gcp' }} + with: + gcp_service_account_json: ${{ secrets.GCP_IMAGE_UPLOAD_SERVICE_ACCOUNT }} + + - name: Prepare PKI for image upload + shell: bash + run: ln -s pki_testing pki + working-directory: ${{ github.workspace }}/image/mkosi + + - name: Determine version + id: version + uses: ./.github/actions/pseudo_version + + # Make sure to set valid names for GCP and Azure + # Azure + # gallery name may include alphanumeric characters, dots and underscores. Must end and begin with an alphanumeric character + # image definition may include alphanumeric characters, dots, dashes and underscores. Must end and begin with an alphanumeric character + # image version has to be semantic version in the form .. . uint may not be larger than 2,147,483,647 + # + # GCP + # image family and image name may include lowercase alphanumeric characters and dashes. Must not end or begin with a dash + - name: Configure input variables + shell: bash + run: | + timestamp=${{ steps.version.outputs.timestamp }} + semver=${{ steps.version.outputs.semanticVersion }} + imageVersion=${{ inputs.imageVersion }} + pseudover=${{ steps.version.outputs.pseudoVersion }} + echo "PKI=${{ github.workspace }}/image/mkosi/pki" >> $GITHUB_ENV + echo "GCP_PROJECT=constellation-images" >> $GITHUB_ENV + echo "GCP_BUCKET=constellation-images" >> $GITHUB_ENV + echo "GCP_REGION=europe-west3" >> $GITHUB_ENV + echo "GCP_RAW_IMAGE_PATH=${{ github.workspace }}/image/mkosi/mkosi.output.gcp/fedora~36/image.raw" >> $GITHUB_ENV + echo "GCP_IMAGE_PATH=${{ github.workspace }}/image/mkosi/mkosi.output.gcp/fedora~36/image.tar.gz" >> $GITHUB_ENV + echo "AZURE_RESOURCE_GROUP_NAME=constellation-images" >> $GITHUB_ENV + echo "AZURE_REGION=northeurope" >> $GITHUB_ENV + echo "AZURE_REPLICATION_REGIONS=northeurope eastus westeurope westus" >> $GITHUB_ENV + echo "AZURE_SKU=constellation" >> $GITHUB_ENV + echo "AZURE_PUBLISHER=edgelesssys" >> $GITHUB_ENV + echo "AZURE_RAW_IMAGE_PATH=${{ github.workspace }}/image/mkosi/mkosi.output.azure/fedora~36/image.raw" >> $GITHUB_ENV + echo "AZURE_IMAGE_PATH=${{ github.workspace }}/image/mkosi/mkosi.output.azure/fedora~36/image.vhd" >> $GITHUB_ENV + # TODO: set default security type to "ConfidentialVM" once replication is possible + AZURE_SECURITY_TYPE=${{ matrix.upload-variant }} + if [ -z "${AZURE_SECURITY_TYPE}" ]; then + AZURE_SECURITY_TYPE=ConfidentialVMSupported + fi + echo "AZURE_SECURITY_TYPE=${AZURE_SECURITY_TYPE}" >> $GITHUB_ENV + echo "AZURE_DISK_NAME=constellation-${pseudover//./-}-${AZURE_SECURITY_TYPE,,}" >> $GITHUB_ENV + if [ "${{ startsWith(github.ref, 'refs/heads/release/') && (inputs.debug == false) }}" = true ] + then + GCP_IMAGE_NAME=constellation-${imageVersion//./-} + echo "GCP_IMAGE_FAMILY=constellation" >> $GITHUB_ENV + AZURE_IMAGE_DEFINITION=constellation + echo "AZURE_IMAGE_VERSION=${imageVersion:1}" >> $GITHUB_ENV + AZURE_GALLERY_NAME=Constellation + elif [ "${{ ((github.ref == 'refs/heads/main') || startsWith(github.ref, 'refs/heads/release/')) && (inputs.debug == true) }}" = true ] + then + GCP_IMAGE_NAME=constellation-${{ steps.version.outputs.timestamp }} + echo "GCP_IMAGE_FAMILY=constellation-debug-${semver//./-}" >> $GITHUB_ENV + AZURE_IMAGE_DEFINITION=${semver} + echo "AZURE_IMAGE_VERSION=${timestamp:0:4}.${timestamp:4:4}.${timestamp:8}" >> $GITHUB_ENV + AZURE_GALLERY_NAME=Constellation_Debug + else + GCP_IMAGE_NAME=constellation-${{ steps.version.outputs.timestamp }} + echo "GCP_IMAGE_FAMILY=constellation-${{ steps.version.outputs.branchName }}" >> $GITHUB_ENV + AZURE_IMAGE_DEFINITION=${{ steps.version.outputs.branchName }} + echo "AZURE_IMAGE_VERSION=${timestamp:0:4}.${timestamp:4:4}.${timestamp:8}" >> $GITHUB_ENV + AZURE_GALLERY_NAME=Constellation_Testing + fi + # TODO: enable VMGS upload for ConfidentialVM images once replication is possible + if [ "${AZURE_SECURITY_TYPE}" == "ConfidentialVMSupported" ]; then + echo "AZURE_GALLERY_NAME=${AZURE_GALLERY_NAME}_CVM" >> $GITHUB_ENV + echo "AZURE_VMGS_PATH=" >> $GITHUB_ENV + else + echo "AZURE_GALLERY_NAME=${AZURE_GALLERY_NAME}" >> $GITHUB_ENV + echo "AZURE_VMGS_PATH=${{ github.workspace }}/image/mkosi/pki/${AZURE_SECURITY_TYPE}.vmgs" >> $GITHUB_ENV + fi + echo "AZURE_IMAGE_DEFINITION=${AZURE_IMAGE_DEFINITION}" >> $GITHUB_ENV + echo "AZURE_IMAGE_OFFER=${AZURE_IMAGE_DEFINITION}" >> $GITHUB_ENV + echo "GCP_IMAGE_NAME=${GCP_IMAGE_NAME}" >> $GITHUB_ENV + echo "GCP_IMAGE_FILENAME=${GCP_IMAGE_NAME}.tar.gz" >> $GITHUB_ENV + + - name: Download VMGS blob + run: aws s3 cp \ + s3://constellation-secure-boot/pki_testing/${AZURE_SECURITY_TYPE}.vmgs \ + pki_testing/${AZURE_SECURITY_TYPE}.vmgs \ + --no-progress + working-directory: ${{ github.workspace }}/image/mkosi + if: ${{ matrix.csp == 'azure' }} + + - name: Upload GCP image + shell: bash + run: | + echo "::group::Upload GCP image" + upload/pack.sh gcp "${GCP_RAW_IMAGE_PATH}" "${GCP_IMAGE_PATH}" + upload/upload_gcp.sh + echo -e "Uploaded GCP image: \`projects/${GCP_PROJECT}/global/images/${GCP_IMAGE_NAME}\`" >> $GITHUB_STEP_SUMMARY + echo "::endgroup::" + working-directory: ${{ github.workspace }}/image/mkosi + if: ${{ matrix.csp == 'gcp' }} + + - name: Upload Azure image + shell: bash + run: | + echo "::group::Upload Azure image" + upload/pack.sh azure "${AZURE_RAW_IMAGE_PATH}" "${AZURE_IMAGE_PATH}" + upload/upload_azure.sh -g --disk-name "${AZURE_DISK_NAME}" "${AZURE_VMGS_PATH}" + echo -e "Uploaded Azure ${AZURE_SECURITY_TYPE} image: \`/subscriptions/0d202bbb-4fa7-4af8-8125-58c269a05435/resourceGroups/${AZURE_RESOURCE_GROUP_NAME^^}/providers/Microsoft.Compute/galleries/${AZURE_GALLERY_NAME}/images/${AZURE_IMAGE_DEFINITION}/versions/${AZURE_IMAGE_VERSION}\`" >> $GITHUB_STEP_SUMMARY + echo "::endgroup::" + working-directory: ${{ github.workspace }}/image/mkosi + if: ${{ matrix.csp == 'azure' }} + + generate-sbom: + name: "Generate SBOM" + needs: make-os-image + runs-on: ubuntu-22.04 + steps: + - 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@fb598a63ae348fa914e94cd0ff38f362e927b741 + with: + # downloading / using only the QEMU rootfs is fine + # since the images only differ in the ESP partition + name: parts-qemu + + - name: Unpack squashfs + run: | + echo "::group::Unpack squashfs" + unsquashfs -user-xattrs -d image.root.tree image.root.raw + echo "::endgroup::" + + - uses: anchore/sbom-action@eda59434a8e5ce9bda93a202dfe50f6a2e637bb6 + with: + path: image.root.tree + artifact-name: sbom.spdx.json + format: spdx-json + + - uses: anchore/sbom-action@eda59434a8e5ce9bda93a202dfe50f6a2e637bb6 + with: + path: image.root.tree + artifact-name: sbom.cyclonedx.json + format: cyclonedx-json + + - uses: anchore/sbom-action@eda59434a8e5ce9bda93a202dfe50f6a2e637bb6 + with: + path: image.root.tree + artifact-name: sbom.syft.json + format: syft-json diff --git a/bootstrapper/internal/kubernetes/k8sapi/constants.go b/bootstrapper/internal/kubernetes/k8sapi/constants.go index 779bebc6f..0c701a295 100644 --- a/bootstrapper/internal/kubernetes/k8sapi/constants.go +++ b/bootstrapper/internal/kubernetes/k8sapi/constants.go @@ -12,9 +12,10 @@ const ( binDir = "/run/state/bin" kubeadmPath = "/run/state/bin/kubeadm" kubeletPath = "/run/state/bin/kubelet" - kubeletServiceEtcPath = "/etc/systemd/system/kubelet.service" + kubectlPath = "/run/state/bin/kubectl" + kubeletServiceEtcPath = "/run/systemd/system/kubelet.service" kubeletServiceStatePath = "/run/state/systemd/system/kubelet.service" - kubeadmConfEtcPath = "/etc/systemd/system/kubelet.service.d/10-kubeadm.conf" + kubeadmConfEtcPath = "/run/systemd/system/kubelet.service.d/10-kubeadm.conf" kubeadmConfStatePath = "/run/state/systemd/system/kubelet.service.d/10-kubeadm.conf" executablePerm = 0o544 systemdUnitPerm = 0o644 diff --git a/cli/internal/cloudcmd/create.go b/cli/internal/cloudcmd/create.go index 4c65198da..aa65b4041 100644 --- a/cli/internal/cloudcmd/create.go +++ b/cli/internal/cloudcmd/create.go @@ -128,6 +128,7 @@ func (c *Creator) createAzure(ctx context.Context, cl terraformClient, config *c StateDiskType: config.Provider.Azure.StateDiskType, ImageID: config.Provider.Azure.Image, ConfidentialVM: *config.Provider.Azure.ConfidentialVM, + SecureBoot: *config.Provider.Azure.SecureBoot, Debug: config.IsDebugCluster(), } @@ -210,6 +211,8 @@ func (c *Creator) createQEMU(ctx context.Context, cl terraformClient, lv libvirt MemorySizeMiB: config.Provider.QEMU.Memory, MetadataAPIImage: config.Provider.QEMU.MetadataAPIImage, MetadataLibvirtURI: metadataLibvirtURI, + NVRAM: config.Provider.QEMU.NVRAM, + Firmware: config.Provider.QEMU.Firmware, } ip, err := cl.CreateCluster(ctx, name, &vars) diff --git a/cli/internal/libvirt/Dockerfile b/cli/internal/libvirt/Dockerfile index f769c6bab..05764c80d 100644 --- a/cli/internal/libvirt/Dockerfile +++ b/cli/internal/libvirt/Dockerfile @@ -17,6 +17,11 @@ RUN echo "cgroup_controllers = []" >> /etc/libvirt/qemu.conf && \ echo "listen_addr = \"localhost\"" >> /etc/libvirt/libvirtd.conf && \ echo "auth_tcp = \"none\"" >> /etc/libvirt/libvirtd.conf +# Copy nvram templates +COPY ./cli/internal/libvirt/nvram/constellation_vars.testing.fd /usr/share/OVMF/constellation_vars.testing.fd +# TODO: Uncomment this line when we have a production template +# COPY ./cli/internal/libvirt/nvram/constellation_vars.production.fd /usr/share/OVMF/constellation_vars.production.fd + COPY --chmod=755 ./cli/internal/libvirt/start.sh /start.sh ENTRYPOINT ["/start.sh"] diff --git a/cli/internal/libvirt/nvram/constellation_vars.testing.fd b/cli/internal/libvirt/nvram/constellation_vars.testing.fd new file mode 100644 index 0000000000000000000000000000000000000000..95ea75dca87677a6a5744c8bc310f536f9ca555a GIT binary patch literal 131072 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 literal 0 HcmV?d00001 diff --git a/cli/internal/terraform/terraform/azure/main.tf b/cli/internal/terraform/terraform/azure/main.tf index 445c35695..135a3dd9e 100644 --- a/cli/internal/terraform/terraform/azure/main.tf +++ b/cli/internal/terraform/terraform/azure/main.tf @@ -193,6 +193,7 @@ module "scale_set_control_plane" { location = var.location instance_type = var.instance_type confidential_vm = var.confidential_vm + secure_boot = var.secure_boot tags = merge(local.tags, { role = "control-plane" }) image_id = var.image_id user_assigned_identity = var.user_assigned_identity @@ -215,6 +216,7 @@ module "scale_set_worker" { location = var.location instance_type = var.instance_type confidential_vm = var.confidential_vm + secure_boot = var.secure_boot tags = merge(local.tags, { role = "worker" }) image_id = var.image_id user_assigned_identity = var.user_assigned_identity diff --git a/cli/internal/terraform/terraform/azure/modules/scale_set/main.tf b/cli/internal/terraform/terraform/azure/modules/scale_set/main.tf index 4504a2a03..f2228735e 100644 --- a/cli/internal/terraform/terraform/azure/modules/scale_set/main.tf +++ b/cli/internal/terraform/terraform/azure/modules/scale_set/main.tf @@ -27,7 +27,7 @@ resource "azurerm_linux_virtual_machine_scale_set" "scale_set" { vtpm_enabled = true disable_password_authentication = false upgrade_mode = "Manual" - secure_boot_enabled = true + secure_boot_enabled = var.secure_boot source_image_id = var.image_id tags = var.tags diff --git a/cli/internal/terraform/terraform/azure/modules/scale_set/variables.tf b/cli/internal/terraform/terraform/azure/modules/scale_set/variables.tf index 47b1d5942..151b5cb11 100644 --- a/cli/internal/terraform/terraform/azure/modules/scale_set/variables.tf +++ b/cli/internal/terraform/terraform/azure/modules/scale_set/variables.tf @@ -71,3 +71,9 @@ variable "confidential_vm" { default = true description = "Whether to deploy the cluster nodes as confidential VMs." } + +variable "secure_boot" { + type = bool + default = false + description = "Whether to deploy the cluster nodes with secure boot." +} diff --git a/cli/internal/terraform/terraform/azure/variables.tf b/cli/internal/terraform/terraform/azure/variables.tf index f52e33bf5..59c062047 100644 --- a/cli/internal/terraform/terraform/azure/variables.tf +++ b/cli/internal/terraform/terraform/azure/variables.tf @@ -57,6 +57,12 @@ variable "confidential_vm" { description = "Whether to deploy the cluster nodes as confidential VMs." } +variable "secure_boot" { + type = bool + default = false + description = "Whether to deploy the cluster nodes with secure boot." +} + variable "debug" { type = bool default = false diff --git a/cli/internal/terraform/terraform/qemu/main.tf b/cli/internal/terraform/terraform/qemu/main.tf index 1ecb72e2b..679b66334 100644 --- a/cli/internal/terraform/terraform/qemu/main.tf +++ b/cli/internal/terraform/terraform/qemu/main.tf @@ -59,6 +59,8 @@ module "control_plane" { pool = libvirt_pool.cluster.name boot_volume_id = libvirt_volume.constellation_coreos_image.id machine = var.machine + firmware = var.firmware + nvram = var.nvram name = var.name } @@ -74,6 +76,8 @@ module "worker" { pool = libvirt_pool.cluster.name boot_volume_id = libvirt_volume.constellation_coreos_image.id machine = var.machine + firmware = var.firmware + nvram = var.nvram name = var.name } diff --git a/cli/internal/terraform/terraform/qemu/modules/instance_group/domain.xsl b/cli/internal/terraform/terraform/qemu/modules/instance_group/domain.xsl index 854e4f168..982a5664d 100644 --- a/cli/internal/terraform/terraform/qemu/modules/instance_group/domain.xsl +++ b/cli/internal/terraform/terraform/qemu/modules/instance_group/domain.xsl @@ -6,10 +6,31 @@ - + + + + + + + + + + + + + + + + + + + + + + diff --git a/cli/internal/terraform/terraform/qemu/modules/instance_group/main.tf b/cli/internal/terraform/terraform/qemu/modules/instance_group/main.tf index 61693a91e..ae54d595d 100644 --- a/cli/internal/terraform/terraform/qemu/modules/instance_group/main.tf +++ b/cli/internal/terraform/terraform/qemu/modules/instance_group/main.tf @@ -13,11 +13,16 @@ locals { } resource "libvirt_domain" "instance_group" { - name = "${var.name}-${var.role}-${count.index}" - count = var.amount - memory = var.memory - vcpu = var.vcpus - machine = var.machine + name = "${var.name}-${var.role}-${count.index}" + count = var.amount + memory = var.memory + vcpu = var.vcpus + machine = var.machine + firmware = var.firmware + nvram { + file = "/var/lib/libvirt/qemu/nvram/${var.role}-${count.index}_VARS.fd" + template = var.nvram + } tpm { backend_type = "emulator" backend_version = "2.0" diff --git a/cli/internal/terraform/terraform/qemu/modules/instance_group/variables.tf b/cli/internal/terraform/terraform/qemu/modules/instance_group/variables.tf index 159496ce5..09f02b06e 100644 --- a/cli/internal/terraform/terraform/qemu/modules/instance_group/variables.tf +++ b/cli/internal/terraform/terraform/qemu/modules/instance_group/variables.tf @@ -48,7 +48,18 @@ variable "machine" { description = "machine type. use 'q35' for secure boot and 'pc' for non secure boot. See 'qemu-system-x86_64 -machine help'" } +variable "firmware" { + type = string + description = "path to UEFI firmware file." +} + +variable "nvram" { + type = string + description = "path to UEFI NVRAM template file. Used for secure boot." +} + variable "name" { type = string description = "name prefix of the cluster VMs" } + diff --git a/cli/internal/terraform/terraform/qemu/variables.tf b/cli/internal/terraform/terraform/qemu/variables.tf index c7226ec26..a1b8007fd 100644 --- a/cli/internal/terraform/terraform/qemu/variables.tf +++ b/cli/internal/terraform/terraform/qemu/variables.tf @@ -45,6 +45,17 @@ variable "machine" { description = "machine type. use 'q35' for secure boot and 'pc' for non secure boot. See 'qemu-system-x86_64 -machine help'" } +variable "firmware" { + type = string + default = "/usr/share/OVMF/OVMF_CODE.secboot.fd" + description = "path to UEFI firmware file. Use \"OVMF_CODE_4M.ms.fd\" on Ubuntu and \"OVMF_CODE.secboot.fd\" on Fedora." +} + +variable "nvram" { + type = string + description = "path to UEFI NVRAM template file. Used for secure boot." +} + variable "metadata_api_image" { type = string description = "container image of the QEMU metadata api server" diff --git a/cli/internal/terraform/variables.go b/cli/internal/terraform/variables.go index 8135e0eb4..8f5187554 100644 --- a/cli/internal/terraform/variables.go +++ b/cli/internal/terraform/variables.go @@ -97,6 +97,8 @@ type AzureVariables struct { ImageID string // ConfidentialVM sets the VM to be confidential. ConfidentialVM bool + // SecureBoot sets the VM to use secure boot. + SecureBoot bool // Debug is true if debug mode is enabled. Debug bool } @@ -112,6 +114,7 @@ func (v *AzureVariables) String() string { writeLinef(b, "state_disk_type = %q", v.StateDiskType) writeLinef(b, "image_id = %q", v.ImageID) writeLinef(b, "confidential_vm = %t", v.ConfidentialVM) + writeLinef(b, "secure_boot = %t", v.SecureBoot) writeLinef(b, "debug = %t", v.Debug) return b.String() @@ -140,6 +143,10 @@ type QEMUVariables struct { // In case of unix socket, this should be "qemu:///system". // Other wise it should be the same as LibvirtURI. MetadataLibvirtURI string + // NVRAM is the path to the NVRAM template. + NVRAM string + // Firmware is the path to the firmware. + Firmware string } // String returns a string representation of the variables, formatted as Terraform variables. @@ -154,6 +161,17 @@ func (v *QEMUVariables) String() string { writeLinef(b, "memory = %d", v.MemorySizeMiB) writeLinef(b, "metadata_api_image = %q", v.MetadataAPIImage) writeLinef(b, "metadata_libvirt_uri = %q", v.MetadataLibvirtURI) + switch v.NVRAM { + case "production": + b.WriteString("nvram = \"/usr/share/OVMF/constellation_vars.production.fd\"\n") + case "testing": + b.WriteString("nvram = \"/usr/share/OVMF/constellation_vars.testing.fd\"\n") + default: + writeLinef(b, "nvram = %q", v.NVRAM) + } + if v.Firmware != "" { + writeLinef(b, "firmware = %q", v.Firmware) + } return b.String() } diff --git a/debugd/internal/debugd/constants.go b/debugd/internal/debugd/constants.go index c58c44b0c..47e6d6758 100644 --- a/debugd/internal/debugd/constants.go +++ b/debugd/internal/debugd/constants.go @@ -14,7 +14,7 @@ const ( SSHCheckInterval = 30 * time.Second DiscoverDebugdInterval = 30 * time.Second BootstrapperDownloadRetryBackoff = 1 * time.Minute - BootstrapperDeployFilename = "/opt/bootstrapper" + BootstrapperDeployFilename = "/run/state/bin/bootstrapper" Chunksize = 1024 BootstrapperSystemdUnitName = "bootstrapper.service" BootstrapperSystemdUnitContents = `[Unit] @@ -25,12 +25,10 @@ After=network-online.target Type=simple RemainAfterExit=yes Restart=on-failure -EnvironmentFile=/etc/constellation.env +EnvironmentFile=/run/constellation.env +Environment=PATH=/run/state/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin ExecStartPre=-setenforce Permissive -ExecStartPre=/usr/bin/mkdir -p /opt/cni/bin/ -# merge all CNI binaries in writable folder until containerd can use multiple CNI bins: https://github.com/containerd/containerd/issues/6600 -ExecStartPre=/bin/sh -c "/usr/bin/cp /usr/libexec/cni/* /opt/cni/bin/" -ExecStart=/opt/bootstrapper +ExecStart=/run/state/bin/bootstrapper [Install] WantedBy=multi-user.target ` diff --git a/debugd/internal/debugd/deploy/download_test.go b/debugd/internal/debugd/deploy/download_test.go index 4e63071fe..86ff84ca2 100644 --- a/debugd/internal/debugd/deploy/download_test.go +++ b/debugd/internal/debugd/deploy/download_test.go @@ -36,7 +36,7 @@ func TestMain(m *testing.M) { } func TestDownloadBootstrapper(t *testing.T) { - filename := "/opt/bootstrapper" + filename := "/run/state/bin/bootstrapper" someErr := errors.New("failed") testCases := map[string]struct { diff --git a/debugd/internal/debugd/deploy/service.go b/debugd/internal/debugd/deploy/service.go index fb2989583..4112f2c35 100644 --- a/debugd/internal/debugd/deploy/service.go +++ b/debugd/internal/debugd/deploy/service.go @@ -18,7 +18,7 @@ import ( ) const ( - systemdUnitFolder = "/etc/systemd/system" + systemdUnitFolder = "/run/systemd/system" ) //go:generate stringer -type=SystemdAction diff --git a/debugd/internal/debugd/server/server_test.go b/debugd/internal/debugd/server/server_test.go index 86142c6ae..75b4ed9d4 100644 --- a/debugd/internal/debugd/server/server_test.go +++ b/debugd/internal/debugd/server/server_test.go @@ -188,7 +188,7 @@ func TestUploadBootstrapper(t *testing.T) { assert.Equal(tc.wantResponseStatus, resp.Status) if tc.wantFile { assert.Equal(tc.wantChunks, tc.streamer.writeStreamChunks) - assert.Equal("/opt/bootstrapper", tc.streamer.writeStreamFilename) + assert.Equal("/run/state/bin/bootstrapper", tc.streamer.writeStreamFilename) } else { assert.Empty(tc.streamer.writeStreamChunks) assert.Empty(tc.streamer.writeStreamFilename) @@ -256,7 +256,7 @@ func TestDownloadBootstrapper(t *testing.T) { } require.NoError(err) assert.Equal(tc.wantChunks, chunks) - assert.Equal("/opt/bootstrapper", tc.streamer.readStreamFilename) + assert.Equal("/run/state/bin/bootstrapper", tc.streamer.readStreamFilename) }) } } diff --git a/image/README.md b/image/README.md index 371e456d7..f0936ccf2 100644 --- a/image/README.md +++ b/image/README.md @@ -1,113 +1,193 @@ -# Constellation images - -We use the [Fedora CoreOS Assembler](https://coreos.github.io/coreos-assembler/) to build the base image for Constellation nodes. - ## Setup -1. Install prerequisites: - - [Docker](https://docs.docker.com/engine/install/) or [Podman](https://podman.io/getting-started/installation) - - [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-linux) - - [azcopy](https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-v10) - - [Google Cloud CLI](https://cloud.google.com/sdk/docs/install) - - [gsutil](https://cloud.google.com/storage/docs/gsutil_install#linux) - - Ubuntu: +- Install mkosi (from git): - ```shell-session - sudo apt install -y bash coreutils cryptsetup-bin grep libguestfs-tools make parted pv qemu-system qemu-utils sed tar util-linux wget - ``` - -2. Log in to GCP and Azure - - ```shell-session - gcloud auth login - az login - ``` - -3. [Log in to the ghcr.io package registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry#authenticating-to-the-container-registry) -4. Ensure read and write access to `/dev/kvm` (and repeat after every reboot) - - ```shell-session - sudo chmod 666 /dev/kvm + ```sh + cd /tmp/ + git clone https://github.com/systemd/mkosi + cd mkosi + tools/generate-zipapp.sh + cp builddir/mkosi /usr/local/bin/ ``` -## Configuration +- Install tools: -Create a configuration file in `image/config.mk` to override any of the variables found at the top of the [Makefile](Makefile). -Important settings are: +
+ Ubuntu / Debian -- `BOOTSTRAPPER_BINARY`: path to a bootstrapper binary. Can be substituted with a path to a `debugd` binary if a debug image should be built. The binary has to be built before! -- `CONTAINER_ENGINE`: container engine used to run COSA. either `podman` or `docker`. -- `COSA_INIT_REPO`: Git repository containing CoreOS config. Cloned in `cosa-init` target. -- `COSA_INIT_BRANCH`: Git branch checked out from `COSA_INIT_REPO`. Can be used to test out changes on another branch before merging. -- `NETRC` path to a netrc file containing a GitHub PAT. Used to authenticate to GitHub from within the COSA container. -- `GCP_IMAGE_NAME`: Image name for the GCP image. Set to include a timestamp when using the build pipeline. Can be set to a custom value if you want to upload a custom image for testing on GCP. -- `AZURE_IMAGE_NAME`: Image name for the Azure image. Can be set to a custom value if you want to upload a custom image for testing on Azure. + ```sh + sudo apt-get update + sudo apt-get install --assume-yes --no-install-recommends \ + dnf \ + systemd-container \ + qemu-system-x86 \ + qemu-utils \ + ovmf \ + e2fsprogs \ + squashfs-tools \ + efitools \ + sbsigntool \ + coreutils \ + curl \ + jq \ + util-linux \ + virt-manager + ``` -Example `config.mk` to create a debug image with docker and name it `my-custom-image`: +
-```Makefile -BOOTSTRAPPER_BINARY = ../build/debugd -CONTAINER_ENGINE = docker -GCP_IMAGE_NAME = my-custom-image -AZURE_IMAGE_NAME = my-custom-image +
+ Fedora + + ```sh + sudo dnf install -y \ + edk2-ovmf \ + systemd-container \ + qemu \ + e2fsprogs \ + squashfs-tools \ + efitools \ + sbsigntools \ + coreutils \ + curl \ + jq \ + util-linux \ + virt-manager + ``` + +
+ +- Prepare secure boot PKI (see `secure-boot/genkeys.sh`) + +## Build + +When building your first image, prepare the secure boot PKI (see `secure-boot/genkeys.sh`) for self-signed, locally built images. + +After that, you can build the image with: + +```sh +# OPTIONAL: to create a debug image, export the following line +# export BOOTSTRAPPER_BINARY=$(realpath ${PWD}/../../build/debugd) +# OPTIONAL: symlink custom path to secure boot PKI to ./pki +# ln -s /path/to/pki/folder ./pki +sudo make -j $(nproc) ``` -## Build an image +Raw images will be placed in `mkosi.output./fedora~36/image.raw`. -Ensure you have the modified cosa container image installed: +## Prepare Secure Boot -```shell-session -docker image ls | grep localhost/coreos-assembler +The generated images are partially signed by Microsoft ([shim loader](https://github.com/rhboot/shim)), and partially signed by Edgeless Systems (systemd-boot and unified kernel images consisting of the linux kernel, initramfs and kernel commandline). + +For QEMU and Azure, you can pre-generate the NVRAM variables for secure boot. This is not necessary for GCP, as you can specify secure boot parameters via the GCP API on image creation. + +
+libvirt / QEMU / KVM + +```sh +secure-boot/generate_nvram_vars.sh mkosi.output.qemu/fedora~36/image.raw ``` -or +
-```shell-session -podman image ls | grep localhost/coreos-assembler +
+Azure + +These steps only have to performed once for a fresh set of secure boot certificates. +VMGS blobs for testing and release images already exist. + +First, create a disk without embedded MOK EFI variables. + +```sh +# set these variables +export AZURE_SECURITY_TYPE=ConfidentialVM # or TrustedLaunch +export AZURE_RESOURCE_GROUP_NAME= # e.g. "constellation-images" + +export AZURE_REGION=northeurope +export AZURE_DISK_NAME=constellation-$(date +%s) +export AZURE_SNAPSHOT_NAME=${AZURE_DISK_NAME} +export AZURE_RAW_IMAGE_PATH=${PWD}/mkosi.output.azure/fedora~36/image.raw +export AZURE_IMAGE_PATH=${PWD}/mkosi.output.azure/fedora~36/image.vhd +export AZURE_VMGS_FILENAME=${AZURE_SECURITY_TYPE}.vmgs +export BLOBS_DIR=${PWD}/blobs +upload/pack.sh azure "${AZURE_RAW_IMAGE_PATH}" "${AZURE_IMAGE_PATH}" +upload/upload_azure.sh --disk-name "${AZURE_DISK_NAME}-setup-secure-boot" "" +secure-boot/azure/launch.sh -n "${AZURE_DISK_NAME}-setup-secure-boot" -d --secure-boot true --disk-name "${AZURE_DISK_NAME}-setup-secure-boot" ``` -If not present, install with +Ignore the running launch script and connect to the serial console once available. +The console shows the message "Verification failed: (0x1A) Security Violation". You can import the MOK certificate via the UEFI shell: -```shell-session -make cosa-image +Press OK, then ENTER, then "Enroll key from disk". +Select the following key: `/EFI/loader/keys/auto/db.cer`. +Press Continue, then choose "Yes" to the question "Enroll the key(s)?". +Choose reboot. + +Extract the VMGS from the running VM (this includes the MOK EFI variables) and delete the VM: + +```sh +secure-boot/azure/extract_vmgs.sh --name "${AZURE_DISK_NAME}-setup-secure-boot" +secure-boot/azure/delete.sh --name "${AZURE_DISK_NAME}-setup-secure-boot" ``` -> It is always advisable to create an image from a clean `build` dir. +
-Clean up the `build` dir and remove old images (⚠ this will undo any local changes to the CoreOS configuration!): +## Upload to CSP -```shell-session -sudo make clean +
+GCP + +- Install `gcloud` and `gsutil` (see [here](https://cloud.google.com/sdk/docs/install)) +- Login to GCP (see [here](https://cloud.google.com/sdk/docs/authorizing)) +- Choose secure boot PKI public keys (one of `pki_dev`, `pki_test`, `pki_prod`) + - `pki_dev` can be used for local image builds + - `pki_test` is used by the CI for non-release images + - `pki_prod` is used for release images + +```sh +# set these variables +export GCP_IMAGE_FAMILY= # e.g. "constellation" +export GCP_IMAGE_NAME= # e.g. "constellation-v1.0.0" +export PKI=${PWD}/pki + +export GCP_PROJECT=constellation-images +export GCP_REGION=europe-west3 +export GCP_BUCKET=constellation-images +export GCP_RAW_IMAGE_PATH=${PWD}/mkosi.output.gcp/fedora~36/image.raw +export GCP_IMAGE_FILENAME=$(date +%s).tar.gz +export GCP_IMAGE_PATH=${PWD}/mkosi.output.gcp/fedora~36/image.tar.gz +upload/pack.sh gcp ${GCP_RAW_IMAGE_PATH} ${GCP_IMAGE_PATH} +upload/upload_gcp.sh ``` -- Build QEMU image (for local testing only) +
- ```shell-session - make coreos - ``` +
+Azure -- Build Azure image (without upload) +- Install `az` and `azcopy` (see [here](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli)) +- Login to Azure (see [here](https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli)) +- [Prepare virtual machine guest state (VMGS) with customized NVRAM or use existing VMGS blob](#azure-secure-boot) - ```shell-session - make image-azure - ``` +```sh +# set these variables +export AZURE_GALLERY_NAME= # e.g. "Constellation" +export AZURE_IMAGE_DEFINITION= # e.g. "constellation" +export AZURE_IMAGE_VERSION= # e.g. "1.0.0" +export AZURE_VMGS_PATH= # e.g. "path/to/ConfidentialVM.vmgs" +export AZURE_SECURITY_TYPE=ConfidentialVM # or TrustedLaunch -- Build Azure image (with upload) +export AZURE_RESOURCE_GROUP_NAME=constellation-images +export AZURE_REGION=northeurope +export AZURE_REPLICATION_REGIONS="northeurope eastus westeurope westus" +export AZURE_IMAGE_OFFER=constellation +export AZURE_SKU=constellation +export AZURE_PUBLISHER=edgelesssys +export AZURE_DISK_NAME=constellation-$(date +%s) +export AZURE_RAW_IMAGE_PATH=${PWD}/mkosi.output.azure/fedora~36/image.raw +export AZURE_IMAGE_PATH=${PWD}/mkosi.output.azure/fedora~36/image.vhd +upload/pack.sh azure "${AZURE_RAW_IMAGE_PATH}" "${AZURE_IMAGE_PATH}" +upload/upload_azure.sh -g --disk-name "${AZURE_DISK_NAME}" "${AZURE_VMGS_PATH}" +``` - ```shell-session - make image-azure upload-azure - ``` - -- Build GCP image (without upload) - - ```shell-session - make image-gcp - ``` - -- Build GCP image (with upload) - - ```shell-session - make image-gcp upload-gcp - ``` - -Resulting images for the CSPs can be found under [images](images/). QEMU images are stored at `build/builds/latest/` with a name ending in `.qcow2`. +
diff --git a/image/mkosi/.gitattributes b/image/mkosi/.gitattributes new file mode 100644 index 000000000..e69de29bb diff --git a/image/mkosi/.gitignore b/image/mkosi/.gitignore new file mode 100644 index 000000000..e4edbc530 --- /dev/null +++ b/image/mkosi/.gitignore @@ -0,0 +1,5 @@ +mkosi.cache +mkosi.extra +pki +image.* +mkosi.output.* diff --git a/image/mkosi/Makefile b/image/mkosi/Makefile new file mode 100644 index 000000000..07eb66967 --- /dev/null +++ b/image/mkosi/Makefile @@ -0,0 +1,54 @@ +SHELL = /bin/bash +SRC_PATH = $(CURDIR) +BASE_PATH ?= $(SRC_PATH) +BOOTSTRAPPER_BINARY ?= $(BASE_PATH)/../../build/bootstrapper +DISK_MAPPER_BINARY ?= $(BASE_PATH)/../../build/disk-mapper +PKI ?= $(BASE_PATH)/pki +MKOSI_EXTRA ?= $(BASE_PATH)/mkosi.extra +-include $(CURDIR)/config.mk +csps := qemu gcp azure +certs := $(PKI)/PK.cer $(PKI)/KEK.cer $(PKI)/db.cer + +.PHONY: all clean inject-bins $(csps) + +all: $(csps) + +$(csps): %: mkosi.output.%/fedora~36/image.raw + +mkosi.output.%/fedora~36/image.raw: mkosi.files/mkosi.%.conf inject-bins inject-certs + mkosi --config mkosi.files/mkosi.$*.conf build + secure-boot/signed-shim.sh $@ + @if [ -n $(SUDO_UID) ] && [ -n $(SUDO_GID) ]; then \ + chown -R $(SUDO_UID):$(SUDO_GID) mkosi.output.$*; \ + fi + @echo "Image is ready: $@" + +inject-bins: + mkdir -p $(MKOSI_EXTRA)/usr/bin + mkdir -p $(MKOSI_EXTRA)/usr/sbin + cp $(BOOTSTRAPPER_BINARY) $(MKOSI_EXTRA)/usr/bin/bootstrapper + cp $(DISK_MAPPER_BINARY) $(MKOSI_EXTRA)/usr/sbin/disk-mapper + +inject-certs: $(certs) + # for auto enrollment using systemd-boot (not working yet) + mkdir -p "$(MKOSI_EXTRA)/boot/loader/keys/auto" + cp $(PKI)/{PK,KEK,db}.cer "$(MKOSI_EXTRA)/boot/loader/keys/auto" + cp $(PKI)/{MicWinProPCA2011_2011-10-19,MicCorUEFCA2011_2011-06-27,MicCorKEKCA2011_2011-06-24}.crt "$(MKOSI_EXTRA)/boot/loader/keys/auto" + cp $(PKI)/{PK,KEK,db}.esl "$(MKOSI_EXTRA)/boot/loader/keys/auto" + cp $(PKI)/{PK,KEK,db}.auth "$(MKOSI_EXTRA)/boot/loader/keys/auto" + # for manual enrollment using sbkeysync + mkdir -p $(MKOSI_EXTRA)/etc/secureboot/keys/{db,dbx,KEK,PK} + cp $(PKI)/db.auth "$(MKOSI_EXTRA)/etc/secureboot/keys/db/" + cp $(PKI)/KEK.auth "$(MKOSI_EXTRA)/etc/secureboot/keys/KEK/" + cp $(PKI)/PK.auth "$(MKOSI_EXTRA)/etc/secureboot/keys/PK/" + +clean-cache: + rm -rf mkosi.cache/* + +clean-%: + mkosi --config mkosi.files/mkosi.$*.conf clean + +clean: + rm -rf mkosi.output.* + rm -rf $(MKOSI_EXTRA) + mkdir -p $(MKOSI_EXTRA) diff --git a/image/mkosi/README.md b/image/mkosi/README.md new file mode 100644 index 000000000..de089ff9a --- /dev/null +++ b/image/mkosi/README.md @@ -0,0 +1,187 @@ +## Setup + +- Install mkosi (from git): + + ```sh + cd /tmp/ + git clone https://github.com/systemd/mkosi + cd mkosi + tools/generate-zipapp.sh + cp builddir/mkosi /usr/local/bin/ + ``` + +- Install tools: + +
+ Ubuntu / Debian + + ```sh + sudo apt-get update + sudo apt-get install --assume-yes --no-install-recommends \ + dnf \ + systemd-container \ + qemu-system-x86 \ + qemu-utils \ + ovmf \ + e2fsprogs \ + squashfs-tools \ + efitools \ + sbsigntool \ + coreutils \ + curl \ + jq \ + util-linux \ + virt-manager + ``` + +
+ +
+ Fedora + + ```sh + sudo dnf install -y \ + edk2-ovmf \ + systemd-container \ + qemu \ + e2fsprogs \ + squashfs-tools \ + efitools \ + sbsigntools \ + coreutils \ + curl \ + jq \ + util-linux \ + virt-manager + ``` + +
+ +- Prepare secure boot PKI (see `secure-boot/genkeys.sh`) + +## Build + +```sh +# OPTIONAL: to create a debug image, export the following line +# export BOOTSTRAPPER_BINARY=$(realpath ${PWD}/../../build/debugd) +# OPTIONAL: specify path to secure boot PKI +# export PKI=/path/to/pki/folder +sudo make -j $(nproc) +``` + +Raw images will be placed in `mkosi.output./fedora~36/image.raw`. + +## Prepare Secure Boot + +The generated images are partially signed by Microsoft ([shim loader](https://github.com/rhboot/shim)), and partially signed by Edgeless Systems (systemd-boot and unified kernel images consisting of the linux kernel, initramfs and kernel commandline). + +For QEMU and Azure, you can pre-generate the NVRAM variables for secure boot. This is not necessary for GCP, as you can specify secure boot parameters via the GCP API on image creation. + +
+libvirt / QEMU / KVM + +```sh +secure-boot/generate_nvram_vars.sh mkosi.output.qemu/fedora~36/image.raw +``` + +
+ +
+Azure + +These steps only have to performed once for a fresh set of secure boot certificates. +VMGS blobs for testing and release images already exist. + +First, create a disk without embedded MOK EFI variables. + +```sh +# set these variables +export AZURE_SECURITY_TYPE=ConfidentialVM # or TrustedLaunch +export AZURE_RESOURCE_GROUP_NAME= # e.g. "constellation-images" + +export AZURE_REGION=northeurope +export AZURE_DISK_NAME=constellation-$(date +%s) +export AZURE_SNAPSHOT_NAME=${AZURE_DISK_NAME} +export AZURE_RAW_IMAGE_PATH=${PWD}/mkosi.output.azure/fedora~36/image.raw +export AZURE_IMAGE_PATH=${PWD}/mkosi.output.azure/fedora~36/image.vhd +export AZURE_VMGS_FILENAME=${AZURE_SECURITY_TYPE}.vmgs +export BLOBS_DIR=${PWD}/blobs +upload/pack.sh azure "${AZURE_RAW_IMAGE_PATH}" "${AZURE_IMAGE_PATH}" +upload/upload_azure.sh --disk-name "${AZURE_DISK_NAME}-setup-secure-boot" "" +secure-boot/azure/launch.sh -n "${AZURE_DISK_NAME}-setup-secure-boot" -d --secure-boot true --disk-name "${AZURE_DISK_NAME}-setup-secure-boot" +``` + +Ignore the running launch script and connect to the serial console once available. +The console shows the message "Verification failed: (0x1A) Security Violation". You can import the MOK certificate via the UEFI shell: + +Press OK, then ENTER, then "Enroll key from disk". +Select the following key: `/EFI/loader/keys/auto/db.cer`. +Press Continue, then choose "Yes" to the question "Enroll the key(s)?". +Choose reboot. + +Extract the VMGS from the running VM (this includes the MOK EFI variables) and delete the VM: + +```sh +secure-boot/azure/extract_vmgs.sh --name "${AZURE_DISK_NAME}-setup-secure-boot" +secure-boot/azure/delete.sh --name "${AZURE_DISK_NAME}-setup-secure-boot" +``` + +
+ +## Upload to CSP + +
+GCP + +- Install `gcloud` and `gsutil` (see [here](https://cloud.google.com/sdk/docs/install)) +- Login to GCP (see [here](https://cloud.google.com/sdk/docs/authorizing)) +- Prepare secure boot PKI (see `secure-boot/genkeys.sh`) + +```sh +# set these variables +export GCP_IMAGE_FAMILY= # e.g. "constellation" +export GCP_IMAGE_NAME= # e.g. "constellation-v1.0.0" +export PKI=${PWD}/pki + +export GCP_PROJECT=constellation-images +export GCP_REGION=europe-west3 +export GCP_BUCKET=constellation-images +export GCP_RAW_IMAGE_PATH=${PWD}/mkosi.output.gcp/fedora~36/image.raw +export GCP_IMAGE_FILENAME=$(date +%s).tar.gz +export GCP_IMAGE_PATH=${PWD}/mkosi.output.gcp/fedora~36/image.tar.gz +upload/pack.sh gcp ${GCP_RAW_IMAGE_PATH} ${GCP_IMAGE_PATH} +upload/upload_gcp.sh +``` + +
+ +
+Azure + +- Install `az` and `azcopy` (see [here](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli)) +- Login to Azure (see [here](https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli)) +- Prepare secure boot PKI (see `secure-boot/genkeys.sh`) +- [Prepare virtual machine guest state (VMGS) with customized NVRAM or use existing VMGS blob](#azure-secure-boot) + +```sh +# set these variables +export AZURE_GALLERY_NAME= # e.g. "Constellation" +export AZURE_IMAGE_DEFINITION= # e.g. "constellation" +export AZURE_IMAGE_VERSION= # e.g. "1.0.0" +export AZURE_VMGS_PATH= # e.g. "path/to/ConfidentialVM.vmgs" +export AZURE_SECURITY_TYPE=ConfidentialVM # or TrustedLaunch + +export AZURE_RESOURCE_GROUP_NAME=constellation-images +export AZURE_REGION=northeurope +export AZURE_REPLICATION_REGIONS="northeurope eastus westeurope westus" +export AZURE_IMAGE_OFFER=constellation +export AZURE_SKU=constellation +export AZURE_PUBLISHER=edgelesssys +export AZURE_DISK_NAME=constellation-$(date +%s) +export AZURE_RAW_IMAGE_PATH=${PWD}/mkosi.output.azure/fedora~36/image.raw +export AZURE_IMAGE_PATH=${PWD}/mkosi.output.azure/fedora~36/image.vhd +upload/pack.sh azure "${AZURE_RAW_IMAGE_PATH}" "${AZURE_IMAGE_PATH}" +upload/upload_azure.sh -g --disk-name "${AZURE_DISK_NAME}" "${AZURE_VMGS_PATH}" +``` + +
diff --git a/image/mkosi/mkosi.cache/.gitkeep b/image/mkosi/mkosi.cache/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/image/mkosi/mkosi.conf.d/azure.conf b/image/mkosi/mkosi.conf.d/azure.conf new file mode 100644 index 000000000..bc4b707b4 --- /dev/null +++ b/image/mkosi/mkosi.conf.d/azure.conf @@ -0,0 +1,3 @@ +[Content] +Packages= + WALinuxAgent-udev diff --git a/image/mkosi/mkosi.conf.d/containers.conf b/image/mkosi/mkosi.conf.d/containers.conf new file mode 100644 index 000000000..c2f8a0e2c --- /dev/null +++ b/image/mkosi/mkosi.conf.d/containers.conf @@ -0,0 +1,9 @@ +[Content] +Packages= + containerd, + containernetworking-plugins, + iptables-nft, + ethtool, + socat, + iproute-tc, + conntrack-tools diff --git a/image/mkosi/mkosi.conf.d/gcp.conf b/image/mkosi/mkosi.conf.d/gcp.conf new file mode 100644 index 000000000..0c72df1b9 --- /dev/null +++ b/image/mkosi/mkosi.conf.d/gcp.conf @@ -0,0 +1,3 @@ +[Content] +Packages= + nvme-cli diff --git a/image/mkosi/mkosi.conf.d/mkosi.conf b/image/mkosi/mkosi.conf.d/mkosi.conf new file mode 100644 index 000000000..de8f304cf --- /dev/null +++ b/image/mkosi/mkosi.conf.d/mkosi.conf @@ -0,0 +1,22 @@ +[Distribution] +Distribution=fedora +Release=36 + +[Output] +Format=gpt_squashfs +ManifestFormat=json,changelog +Bootable=yes +KernelCommandLine=mitigations=auto,nosmt preempt=full +WithUnifiedKernelImages=yes +Verity=yes +CompressFs=zstd +SplitArtifacts=yes +# Enable Secure Boot with own PKI +SecureBoot=yes +SecureBootKey=pki/db.key +SecureBootCertificate=pki/db.crt +# TODO: Wait for systemd 252 to bring systemd-measure +# Measure=yes + +[Host] +QemuHeadless=yes diff --git a/image/mkosi/mkosi.conf.d/network.conf b/image/mkosi/mkosi.conf.d/network.conf new file mode 100644 index 000000000..ee7dad6ee --- /dev/null +++ b/image/mkosi/mkosi.conf.d/network.conf @@ -0,0 +1,8 @@ +[Content] +Packages= + iproute, + dbus-broker, + systemd-networkd, + systemd-resolved, + dracut-network, + dhclient, # prevent NetworkManager from being pulled in by dracut-network diff --git a/image/mkosi/mkosi.conf.d/secure-boot-tpm.conf b/image/mkosi/mkosi.conf.d/secure-boot-tpm.conf new file mode 100644 index 000000000..d9d006e4a --- /dev/null +++ b/image/mkosi/mkosi.conf.d/secure-boot-tpm.conf @@ -0,0 +1,8 @@ +[Content] +# Secure Boot / EFI related packages for manual enrollment / verification of Secure Boot +Packages= + e2fsprogs, + sbsigntools, + efitools, + mokutil, + tpm2-tools diff --git a/image/mkosi/mkosi.conf.d/tools.conf b/image/mkosi/mkosi.conf.d/tools.conf new file mode 100644 index 000000000..c3f7f1e32 --- /dev/null +++ b/image/mkosi/mkosi.conf.d/tools.conf @@ -0,0 +1,8 @@ +[Content] +Packages= + passwd, + nano, + nano-default-editor, + vim, + curl, + wget diff --git a/image/mkosi/mkosi.files/mkosi.azure.conf b/image/mkosi/mkosi.files/mkosi.azure.conf new file mode 100644 index 000000000..b9af2db26 --- /dev/null +++ b/image/mkosi/mkosi.files/mkosi.azure.conf @@ -0,0 +1,3 @@ +[Output] +KernelCommandLine=constel.csp=azure +OutputDirectory=mkosi.output.azure diff --git a/image/mkosi/mkosi.files/mkosi.gcp.conf b/image/mkosi/mkosi.files/mkosi.gcp.conf new file mode 100644 index 000000000..07314201a --- /dev/null +++ b/image/mkosi/mkosi.files/mkosi.gcp.conf @@ -0,0 +1,3 @@ +[Output] +KernelCommandLine=constel.csp=gcp +OutputDirectory=mkosi.output.gcp diff --git a/image/mkosi/mkosi.files/mkosi.qemu.conf b/image/mkosi/mkosi.files/mkosi.qemu.conf new file mode 100644 index 000000000..e11730abc --- /dev/null +++ b/image/mkosi/mkosi.files/mkosi.qemu.conf @@ -0,0 +1,3 @@ +[Output] +KernelCommandLine=constel.csp=qemu +OutputDirectory=mkosi.output.qemu diff --git a/image/mkosi/mkosi.finalize b/image/mkosi/mkosi.finalize new file mode 100755 index 000000000..b87dcabe8 --- /dev/null +++ b/image/mkosi/mkosi.finalize @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euxo pipefail + +# recreate kubelet systemd unit after reboot. +# tmpfile config has to be written late as it interferes with the systemd-nspawn build environment +cat >"${BUILDROOT}/usr/lib/tmpfiles.d/kubelet-service.conf" < CHANGES WITH 252 in spe: +# > [...] +# > * sd-boot can automatically enroll SecureBoot keys from files found on +# > the ESP. This enrollment can be either automatic ('force' mode) or +# > controlled by the user ('manual' mode). +# > [...] +# +# echo "secure-boot-enroll force" >> /boot/loader/loader.conf + +# create mountpoints in /etc +mkdir -p /etc/{cni,kubernetes} + +# move issue files away from /etc +# to allow /run/issue and /run/issue.d to take precedence +mv /etc/issue.d /usr/lib/issue.d || true +rm -f /etc/issue +rm -f /etc/issue.net diff --git a/image/mkosi/mkosi.skeleton/etc/dracut.conf.d/90-networkd.conf b/image/mkosi/mkosi.skeleton/etc/dracut.conf.d/90-networkd.conf new file mode 100644 index 000000000..a8bf6a8b4 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/etc/dracut.conf.d/90-networkd.conf @@ -0,0 +1,4 @@ +# enable networking in initrd (initramfs) with dracut and systemd-networkd +install_items+=" /usr/lib/systemd/network/20-wired.network " +install_items+=" /usr/lib/systemd/network/21-azure.network " +add_dracutmodules+=" systemd-networkd " diff --git a/image/mkosi/mkosi.skeleton/etc/dracut.conf.d/azure.conf b/image/mkosi/mkosi.skeleton/etc/dracut.conf.d/azure.conf new file mode 100644 index 000000000..41eb5d0ab --- /dev/null +++ b/image/mkosi/mkosi.skeleton/etc/dracut.conf.d/azure.conf @@ -0,0 +1,3 @@ +# add hyperv drivers to initramfs +# (important for early networking) +force_drivers+=" hv_netvsc hv_sock hv_storvsc hv_vmbus " diff --git a/image/mkosi/mkosi.skeleton/etc/dracut.conf.d/gce.conf b/image/mkosi/mkosi.skeleton/etc/dracut.conf.d/gce.conf new file mode 100644 index 000000000..cae7ce6d5 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/etc/dracut.conf.d/gce.conf @@ -0,0 +1,2 @@ +# Include NVMe driver in initrd to boot on NVMe devices. +force_drivers+=" nvme " diff --git a/image/mkosi/mkosi.skeleton/etc/fstab b/image/mkosi/mkosi.skeleton/etc/fstab new file mode 100644 index 000000000..e22f0b247 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/etc/fstab @@ -0,0 +1,5 @@ +/dev/mapper/state /run/state ext4 defaults,x-systemd.makefs,x-mount.mkdir 0 0 +/run/state/var /var none defaults,bind,x-mount.mkdir 0 0 +/run/state/kubernetes /etc/kubernetes none defaults,bind,x-mount.mkdir 0 0 +/run/state/etccni /etc/cni/ none defaults,bind,x-mount.mkdir 0 0 +/run/state/opt /opt none defaults,bind,x-mount.mkdir 0 0 diff --git a/image/mkosi/mkosi.skeleton/etc/profile.d/constellation.sh b/image/mkosi/mkosi.skeleton/etc/profile.d/constellation.sh new file mode 100755 index 000000000..17ca70374 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/etc/profile.d/constellation.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +export PATH=/run/state/bin:${PATH} +export KUBECONFIG=/etc/kubernetes/admin.conf +alias k=kubectl diff --git a/image/mkosi/mkosi.skeleton/usr/etc/containerd/config.toml b/image/mkosi/mkosi.skeleton/usr/etc/containerd/config.toml new file mode 100644 index 000000000..d0d931827 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/etc/containerd/config.toml @@ -0,0 +1,216 @@ +disabled_plugins = [] +imports = [] +oom_score = 0 +plugin_dir = "" +required_plugins = [] +root = "/var/lib/containerd" +state = "/run/containerd" +version = 2 + +[cgroup] + path = "" + +[debug] + address = "" + format = "" + gid = 0 + level = "" + uid = 0 + +[grpc] + address = "/run/containerd/containerd.sock" + gid = 0 + max_recv_message_size = 16777216 + max_send_message_size = 16777216 + tcp_address = "" + tcp_tls_cert = "" + tcp_tls_key = "" + uid = 0 + +[metrics] + address = "" + grpc_histogram = false + +[plugins] + + [plugins."io.containerd.gc.v1.scheduler"] + deletion_threshold = 0 + mutation_threshold = 100 + pause_threshold = 0.02 + schedule_delay = "0s" + startup_delay = "100ms" + + [plugins."io.containerd.grpc.v1.cri"] + disable_apparmor = false + disable_cgroup = false + disable_hugetlb_controller = true + disable_proc_mount = false + disable_tcp_service = true + enable_selinux = false + enable_tls_streaming = false + ignore_image_defined_volumes = false + max_concurrent_downloads = 3 + max_container_log_line_size = 16384 + netns_mounts_under_state_dir = false + restrict_oom_score_adj = false + sandbox_image = "k8s.gcr.io/pause:3.5" + selinux_category_range = 1024 + stats_collect_period = 10 + stream_idle_timeout = "4h0m0s" + stream_server_address = "127.0.0.1" + stream_server_port = "0" + systemd_cgroup = false + tolerate_missing_hugetlb_controller = true + unset_seccomp_profile = "" + + [plugins."io.containerd.grpc.v1.cri".cni] + bin_dir = "/opt/cni/bin" + conf_dir = "/etc/cni/net.d" + conf_template = "" + max_conf_num = 1 + + [plugins."io.containerd.grpc.v1.cri".containerd] + default_runtime_name = "runc" + disable_snapshot_annotations = true + discard_unpacked_layers = false + no_pivot = false + snapshotter = "overlayfs" + + [plugins."io.containerd.grpc.v1.cri".containerd.default_runtime] + base_runtime_spec = "" + container_annotations = [] + pod_annotations = [] + privileged_without_host_devices = false + runtime_engine = "" + runtime_root = "" + runtime_type = "" + + [plugins."io.containerd.grpc.v1.cri".containerd.default_runtime.options] + + [plugins."io.containerd.grpc.v1.cri".containerd.runtimes] + + [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] + base_runtime_spec = "" + container_annotations = [] + pod_annotations = [] + privileged_without_host_devices = false + runtime_engine = "" + runtime_root = "" + runtime_type = "io.containerd.runc.v2" + + [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] + BinaryName = "" + CriuImagePath = "" + CriuPath = "" + CriuWorkPath = "" + IoGid = 0 + IoUid = 0 + NoNewKeyring = false + NoPivotRoot = false + Root = "" + ShimCgroup = "" + SystemdCgroup = true + + [plugins."io.containerd.grpc.v1.cri".containerd.untrusted_workload_runtime] + base_runtime_spec = "" + container_annotations = [] + pod_annotations = [] + privileged_without_host_devices = false + runtime_engine = "" + runtime_root = "" + runtime_type = "" + + [plugins."io.containerd.grpc.v1.cri".containerd.untrusted_workload_runtime.options] + + [plugins."io.containerd.grpc.v1.cri".image_decryption] + key_model = "node" + + [plugins."io.containerd.grpc.v1.cri".registry] + config_path = "" + + [plugins."io.containerd.grpc.v1.cri".registry.auths] + + [plugins."io.containerd.grpc.v1.cri".registry.configs] + + [plugins."io.containerd.grpc.v1.cri".registry.headers] + + [plugins."io.containerd.grpc.v1.cri".registry.mirrors] + + [plugins."io.containerd.grpc.v1.cri".x509_key_pair_streaming] + tls_cert_file = "" + tls_key_file = "" + + [plugins."io.containerd.internal.v1.opt"] + path = "/opt/containerd" + + [plugins."io.containerd.internal.v1.restart"] + interval = "10s" + + [plugins."io.containerd.metadata.v1.bolt"] + content_sharing_policy = "shared" + + [plugins."io.containerd.monitor.v1.cgroups"] + no_prometheus = false + + [plugins."io.containerd.runtime.v1.linux"] + no_shim = false + runtime = "runc" + runtime_root = "" + shim = "containerd-shim" + shim_debug = false + + [plugins."io.containerd.runtime.v2.task"] + platforms = ["linux/amd64"] + + [plugins."io.containerd.service.v1.diff-service"] + default = ["walking"] + + [plugins."io.containerd.snapshotter.v1.aufs"] + root_path = "" + + [plugins."io.containerd.snapshotter.v1.btrfs"] + root_path = "" + + [plugins."io.containerd.snapshotter.v1.devmapper"] + async_remove = false + base_image_size = "" + pool_name = "" + root_path = "" + + [plugins."io.containerd.snapshotter.v1.native"] + root_path = "" + + [plugins."io.containerd.snapshotter.v1.overlayfs"] + root_path = "" + + [plugins."io.containerd.snapshotter.v1.zfs"] + root_path = "" + +[proxy_plugins] + +[stream_processors] + + [stream_processors."io.containerd.ocicrypt.decoder.v1.tar"] + accepts = ["application/vnd.oci.image.layer.v1.tar+encrypted"] + args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"] + env = ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"] + path = "ctd-decoder" + returns = "application/vnd.oci.image.layer.v1.tar" + + [stream_processors."io.containerd.ocicrypt.decoder.v1.tar.gzip"] + accepts = ["application/vnd.oci.image.layer.v1.tar+gzip+encrypted"] + args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"] + env = ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"] + path = "ctd-decoder" + returns = "application/vnd.oci.image.layer.v1.tar+gzip" + +[timeouts] + "io.containerd.timeout.shim.cleanup" = "5s" + "io.containerd.timeout.shim.load" = "5s" + "io.containerd.timeout.shim.shutdown" = "3s" + "io.containerd.timeout.task.state" = "2s" + +[ttrpc] + address = "" + gid = 0 + uid = 0 diff --git a/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/configure-constel-csp.service b/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/configure-constel-csp.service new file mode 120000 index 000000000..47ba0ea98 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/configure-constel-csp.service @@ -0,0 +1 @@ +../../../systemd/system/configure-constel-csp.service \ No newline at end of file diff --git a/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/constellation-state-disk-generator b/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/constellation-state-disk-generator new file mode 100755 index 000000000..e69de29bb diff --git a/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/google-nvme-disk.service b/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/google-nvme-disk.service new file mode 100644 index 000000000..b87812cea --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/google-nvme-disk.service @@ -0,0 +1,15 @@ +[Unit] +Description=Force symlink creation for GCP nvme disks +Before=prepare-state-disk.service +After=network-online.target +Wants=network-online.target +ConditionKernelCommandLine=constel.csp=gcp + +[Service] +Type=oneshot +ExecStart=/bin/bash /usr/sbin/google-nvme-disk +RemainAfterExit=yes +StandardOutput=tty +StandardInput=tty +StandardError=tty +TimeoutSec=infinity diff --git a/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/google-nvme-disk.sh b/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/google-nvme-disk.sh new file mode 100644 index 000000000..4c02bc65f --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/google-nvme-disk.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -euo pipefail +shopt -s extglob nullglob + +GCP_STATE_DISK_SYMLINK="/dev/disk/by-id/google-state-disk" + +# hack: google nvme udev rules are never executed. Create symlinks for the nvme devices manually. +while [ ! -L "${GCP_STATE_DISK_SYMLINK}" ] +do + for nvmedisk in /dev/nvme0n+([0-9]) + do + /usr/lib/udev/google_nvme_id -s -d "${nvmedisk}" || true + done + if [ -L "${GCP_STATE_DISK_SYMLINK}" ]; then + break + fi + echo "Waiting for state disk to appear.." + sleep 2 +done + +echo "Google state disk found" +echo ${GCP_STATE_DISK_SYMLINK} → $(readlink -f "${GCP_STATE_DISK_SYMLINK}") +sleep 2 diff --git a/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/module-setup.sh b/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/module-setup.sh new file mode 100644 index 000000000..9f9f3899a --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/module-setup.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +depends() { + echo systemd +} + +install_and_enable_unit() { + unit="$1"; shift + target="$1"; shift + inst_simple "$moddir/$unit" "$systemdsystemunitdir/$unit" + mkdir -p "${initdir}${systemdsystemconfdir}/${target}.wants" + ln_r "${systemdsystemunitdir}/${unit}" \ + "${systemdsystemconfdir}/${target}.wants/${unit}" +} + +install() { + inst_multiple \ + bash + inst_script "/usr/sbin/disk-mapper" \ + "/usr/sbin/disk-mapper" + + inst_script "$moddir/prepare-state-disk.sh" \ + "/usr/sbin/prepare-state-disk" + install_and_enable_unit "prepare-state-disk.service" \ + "basic.target" + inst_script "$moddir/google-nvme-disk.sh" \ + "/usr/sbin/google-nvme-disk" + install_and_enable_unit "google-nvme-disk.service" \ + "basic.target" + install_and_enable_unit "configure-constel-csp.service" \ + "basic.target" + + # azure scsi disks + inst_multiple \ + cut \ + readlink + + # gcp nvme disks + inst_multiple \ + date \ + xxd \ + grep \ + sed \ + ln \ + command \ + readlink + + inst_script "/usr/sbin/nvme" \ + "/usr/sbin/nvme" + inst_script "/usr/lib/udev/google_nvme_id" \ + "/usr/lib/udev/google_nvme_id" + inst_simple "/usr/lib/udev/rules.d/64-gce-disk-removal.rules" \ + "/usr/lib/udev/rules.d/64-gce-disk-removal.rules" + inst_simple "/usr/lib/udev/rules.d/65-gce-disk-naming.rules" \ + "/usr/lib/udev/rules.d/65-gce-disk-naming.rules" +} diff --git a/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/prepare-state-disk.service b/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/prepare-state-disk.service new file mode 100644 index 000000000..a280336b8 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/prepare-state-disk.service @@ -0,0 +1,17 @@ +[Unit] +Description=Prepare encrypted state disk +Before=initrd-fs.target +After=network-online.target configure-constel-csp.service +Wants=network-online.target +Requires=initrd-root-fs.target +FailureAction=reboot-immediate + +[Service] +Type=oneshot +EnvironmentFile=/run/constellation.env +ExecStart=/bin/bash /usr/sbin/prepare-state-disk +RemainAfterExit=yes +StandardOutput=tty +StandardInput=tty +StandardError=tty +TimeoutSec=infinity diff --git a/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/prepare-state-disk.sh b/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/prepare-state-disk.sh new file mode 100644 index 000000000..245310fe7 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/dracut/modules.d/39constellation-mount/prepare-state-disk.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -euo pipefail + +# Prepare the encrypted volume by either initializing it with a random key or by aquiring the key from another bootstrapper. +# Store encryption key (random or recovered key) in /run/cryptsetup-keys.d/state.key +disk-mapper -csp "${CONSTEL_CSP}" +if [[ $? -ne 0 ]]; then + echo "Failed to prepare state disk" + sleep 2 # give the serial console time to print the error message + exit $? # exit with the same error code as disk-mapper +fi diff --git a/image/mkosi/mkosi.skeleton/usr/lib/environment.d/99-constellation.conf b/image/mkosi/mkosi.skeleton/usr/lib/environment.d/99-constellation.conf new file mode 100644 index 000000000..0ac42f7dc --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/environment.d/99-constellation.conf @@ -0,0 +1,2 @@ +PATH=/run/state/bin:$PATH +KUBECONFIG=/etc/kubernetes/admin.conf diff --git a/image/mkosi/mkosi.skeleton/usr/lib/modules-load.d/k8s.conf b/image/mkosi/mkosi.skeleton/usr/lib/modules-load.d/k8s.conf new file mode 100644 index 000000000..43dd5433b --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/modules-load.d/k8s.conf @@ -0,0 +1,2 @@ +overlay +br_netfilter diff --git a/image/mkosi/mkosi.skeleton/usr/lib/sysctl.d/10-cilium.conf b/image/mkosi/mkosi.skeleton/usr/lib/sysctl.d/10-cilium.conf new file mode 100644 index 000000000..715ce12a2 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/sysctl.d/10-cilium.conf @@ -0,0 +1,3 @@ +# See https://github.com/cilium/cilium/issues/10645 +net.ipv4.conf.lxc*.rp_filter = 0 +net.ipv4.conf.cilium_*.rp_filter = 0 diff --git a/image/mkosi/mkosi.skeleton/usr/lib/sysctl.d/10-k8s.conf b/image/mkosi/mkosi.skeleton/usr/lib/sysctl.d/10-k8s.conf new file mode 100644 index 000000000..0a4dc6e62 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/sysctl.d/10-k8s.conf @@ -0,0 +1,9 @@ +net.bridge.bridge-nf-call-ip6tables = 1 +net.bridge.bridge-nf-call-iptables = 1 +net.ipv4.ip_forward = 1 +fs.inotify.max_user_instances = 8192 +fs.inotify.max_user_watches = 524288 +# kubernetes hardening (protectKernelDefaults=true) +vm.overcommit_memory = 1 +kernel.panic = 10 +kernel.panic_on_oops = 1 diff --git a/image/mkosi/mkosi.skeleton/usr/lib/systemd/network/20-wired.network b/image/mkosi/mkosi.skeleton/usr/lib/systemd/network/20-wired.network new file mode 100644 index 000000000..aec1849a8 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/systemd/network/20-wired.network @@ -0,0 +1,5 @@ +[Match] +Name=en* + +[Network] +DHCP=yes diff --git a/image/mkosi/mkosi.skeleton/usr/lib/systemd/network/21-azure.network b/image/mkosi/mkosi.skeleton/usr/lib/systemd/network/21-azure.network new file mode 100644 index 000000000..e1fe7785d --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/systemd/network/21-azure.network @@ -0,0 +1,6 @@ +# Used as a fallback rule for Azure NICs as they are not named with "en*" +[Match] +Driver=hv_netvsc + +[Network] +DHCP=yes diff --git a/image/mkosi/mkosi.skeleton/usr/lib/systemd/system-preset/30-constellation.preset b/image/mkosi/mkosi.skeleton/usr/lib/systemd/system-preset/30-constellation.preset new file mode 100644 index 000000000..b14d3bc93 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/systemd/system-preset/30-constellation.preset @@ -0,0 +1,5 @@ +enable constellation-bootstrapper.service +enable configure-constel-csp.service +enable containerd.service +enable tpm-pcrs.service +enable systemd-networkd.service diff --git a/image/mkosi/mkosi.skeleton/usr/lib/systemd/system/configure-constel-csp.service b/image/mkosi/mkosi.skeleton/usr/lib/systemd/system/configure-constel-csp.service new file mode 100644 index 000000000..cdf045764 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/systemd/system/configure-constel-csp.service @@ -0,0 +1,10 @@ +[Unit] +Description=Configures constellation cloud service provider environment variable + +[Service] +Type=oneshot +ExecStart=/bin/bash -c "CSP=$(< /proc/cmdline tr ' ' '\n' | grep constel.csp | sed 's/constel.csp=//'); echo CONSTEL_CSP=$CSP >> /run/constellation.env" +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/image/mkosi/mkosi.skeleton/usr/lib/systemd/system/constellation-bootstrapper.service b/image/mkosi/mkosi.skeleton/usr/lib/systemd/system/constellation-bootstrapper.service new file mode 100644 index 000000000..3403e5cd2 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/systemd/system/constellation-bootstrapper.service @@ -0,0 +1,15 @@ +[Unit] +Description=Constellation Bootstrapper +Wants=network-online.target +After=network-online.target configure-constel-csp.service + +[Service] +Type=simple +RemainAfterExit=yes +Restart=on-failure +EnvironmentFile=/run/constellation.env +Environment=PATH=/run/state/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin +ExecStart=/usr/bin/bootstrapper + +[Install] +WantedBy=multi-user.target diff --git a/image/mkosi/mkosi.skeleton/usr/lib/systemd/system/containerd.service.d/local.conf b/image/mkosi/mkosi.skeleton/usr/lib/systemd/system/containerd.service.d/local.conf new file mode 100644 index 000000000..e1c02c704 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/systemd/system/containerd.service.d/local.conf @@ -0,0 +1,3 @@ +[Service] +ExecStart= +ExecStart=/usr/bin/containerd --config /usr/etc/containerd/config.toml diff --git a/image/mkosi/mkosi.skeleton/usr/lib/systemd/system/tpm-pcrs.service b/image/mkosi/mkosi.skeleton/usr/lib/systemd/system/tpm-pcrs.service new file mode 100644 index 000000000..87800121c --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/systemd/system/tpm-pcrs.service @@ -0,0 +1,11 @@ +[Unit] +Description=Print PCR state on startup +Before=constellation-bootstrapper.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/libexec/constellation-pcrs + +[Install] +WantedBy=multi-user.target diff --git a/image/mkosi/mkosi.skeleton/usr/lib/sysusers.d/constellation.conf b/image/mkosi/mkosi.skeleton/usr/lib/sysusers.d/constellation.conf new file mode 100644 index 000000000..98de75087 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/sysusers.d/constellation.conf @@ -0,0 +1,2 @@ +#Type Name ID GECOS Home directory Shell +u etcd 998:997 "etcd user" /var/lib/etcd diff --git a/image/mkosi/mkosi.skeleton/usr/lib/tmpfiles.d/constellation.conf b/image/mkosi/mkosi.skeleton/usr/lib/tmpfiles.d/constellation.conf new file mode 100644 index 000000000..4d11a5e22 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/tmpfiles.d/constellation.conf @@ -0,0 +1,8 @@ +#Type Path Mode User Group Age Argument +d /var/lib/etcd 0700 998 997 - - +d /var/log/kubernetes/audit/ 0700 0 0 - - +d /run/state/bin 0755 0 0 - - +d /run/issue.d 0755 0 0 - - +C /run/issue - - - - /usr/lib/issue +# merge all CNI binaries in writable folder until containerd can use multiple CNI bins: https://github.com/containerd/containerd/issues/6600 +C /opt/cni/bin - - - - /usr/libexec/cni/ diff --git a/image/mkosi/mkosi.skeleton/usr/lib/udev/google_nvme_id b/image/mkosi/mkosi.skeleton/usr/lib/udev/google_nvme_id new file mode 100755 index 000000000..4f8c43f40 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/udev/google_nvme_id @@ -0,0 +1,245 @@ +#!/bin/bash +# Copyright 2020 Google Inc. All Rights Reserved. +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Used to generate symlinks for PD-NVMe devices using the disk names reported by +# the metadata server + +# Locations of the script's dependencies +readonly nvme_cli_bin=/usr/sbin/nvme + +# Bash regex to parse device paths and controller identification +readonly NAMESPACE_NUMBER_REGEX="/dev/nvme[[:digit:]]+n([[:digit:]]+).*" +readonly PARTITION_NUMBER_REGEX="/dev/nvme[[:digit:]]+n[[:digit:]]+p([[:digit:]]+)" +readonly PD_NVME_REGEX="sn[[:space:]]+:[[:space]]+nvme_card-pd" + +# Globals used to generate the symlinks for a PD-NVMe disk. These are populated +# by the identify_pd_disk function and exported for consumption by udev rules. +ID_SERIAL='' +ID_SERIAL_SHORT='' + +####################################### +# Helper function to log an error message to stderr. +# Globals: +# None +# Arguments: +# String to print as the log message +# Outputs: +# Writes error to STDERR +####################################### +function err() { + echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2 +} + +####################################### +# Retrieves the device name for an NVMe namespace using nvme-cli. +# Globals: +# Uses nvme_cli_bin +# Arguments: +# The path to the nvme namespace (/dev/nvme0n?) +# Outputs: +# The device name parsed from the JSON in the vendor ext of the ns-id command. +# Returns: +# 0 if the device name for the namespace could be retrieved, 1 otherwise +####################################### +function get_namespace_device_name() { + local nvme_json + nvme_json="$("$nvme_cli_bin" id-ns -b "$1" | xxd -p -seek 384 | xxd -p -r)" + if [[ $? -ne 0 ]]; then + return 1 + fi + + if [[ -z "$nvme_json" ]]; then + err "NVMe Vendor Extension disk information not present" + return 1 + fi + + local device_name + device_name="$(echo "$nvme_json" | grep device_name | sed -e 's/.*"device_name":[ \t]*"\([a-zA-Z0-9_-]\+\)".*/\1/')" + + # Error if our device name is empty + if [[ -z "$device_name" ]]; then + err "Empty name" + return 1 + fi + + echo "$device_name" + return 0 +} + +####################################### +# Retrieves the nsid for an NVMe namespace +# Globals: +# None +# Arguments: +# The path to the nvme namespace (/dev/nvme0n*) +# Outputs: +# The namespace number/id +# Returns: +# 0 if the namespace id could be retrieved, 1 otherwise +####################################### +function get_namespace_number() { + local dev_path="$1" + local namespace_number + if [[ "$dev_path" =~ $NAMESPACE_NUMBER_REGEX ]]; then + namespace_number="${BASH_REMATCH[1]}" + else + return 1 + fi + + echo "$namespace_number" + return 0 +} + +####################################### +# Retrieves the partition number for a device path if it exists +# Globals: +# None +# Arguments: +# The path to the device partition (/dev/nvme0n*p*) +# Outputs: +# The value after 'p' in the device path, or an empty string if the path has +# no partition. +####################################### +function get_partition_number() { + local dev_path="$1" + local partition_number + if [[ "$dev_path" =~ $PARTITION_NUMBER_REGEX ]]; then + partition_number="${BASH_REMATCH[1]}" + echo "$partition_number" + else + echo '' + fi + return 0 +} + +####################################### +# Generates a symlink for a PD-NVMe device using the metadata's disk name. +# Primarily used for testing but can be used if the script is directly invoked. +# Globals: +# Uses ID_SERIAL_SHORT (can be populated by identify_pd_disk) +# Arguments: +# The device path for the disk +####################################### +function gen_symlink() { + local dev_path="$1" + local partition_number="$(get_partition_number "$dev_path")" + + if [[ -n "$partition_number" ]]; then + ln -s "$dev_path" /dev/disk/by-id/google-"$ID_SERIAL_SHORT"-part"$partition_number" > /dev/null 2>&1 + else + ln -s "$dev_path" /dev/disk/by-id/google-"$ID_SERIAL_SHORT" > /dev/null 2>&1 + fi + + return 0 +} + +####################################### +# Populates the ID_* global variables with a disk's device name and namespace +# Globals: +# Populates ID_SERIAL_SHORT, and ID_SERIAL +# Arguments: +# The device path for the disk +# Returns: +# 0 on success and 1 if an error occurrs +####################################### +function identify_pd_disk() { + local dev_path="$1" + local dev_name + dev_name="$(get_namespace_device_name "$dev_path")" + if [[ $? -ne 0 ]]; then + return 1 + fi + + ID_SERIAL_SHORT="$dev_name" + ID_SERIAL="Google_PersistentDisk_${ID_SERIAL_SHORT}" + return 0 +} + +function print_help_message() { + echo "Usage: google_nvme_id [-s] [-h] -d device_path" + echo " -d (Required): Specifies the path to generate a name" + echo " for. This needs to be a path to an nvme device or namespace" + echo " -s: Create symbolic link for the disk under /dev/disk/by-id." + echo " Otherwise, the disk name will be printed to STDOUT" + echo " -h: Print this help message" +} + +function main() { + local opt_gen_symlink='false' + local device_path='' + + while getopts :d:sh flag; do + case "$flag" in + d) device_path="$OPTARG";; + s) opt_gen_symlink='true';; + h) print_help_message + return 0 + ;; + :) echo "Invalid option: ${OPTARG} requires an argument" 1>&2 + return 1 + ;; + *) return 1 + esac + done + + if [[ -z "$device_path" ]]; then + echo "Device path (-d) argument required. Use -h for full usage." 1>&2 + exit 1 + fi + + # Ensure the nvme-cli command is installed + command -v "$nvme_cli_bin" > /dev/null 2>&1 + if [[ $? -ne 0 ]]; then + err "The nvme utility (/usr/sbin/nvme) was not found. You may need to run \ +with sudo or install nvme-cli." + return 1 + fi + + # Ensure the passed device is actually an NVMe device + "$nvme_cli_bin" id-ctrl "$device_path" &>/dev/null + if [[ $? -ne 0 ]]; then + err "Passed device was not an NVMe device. (You may need to run this \ +script as root/with sudo)." + return 1 + fi + + # Detect the type of attached nvme device + local controller_id + controller_id=$("$nvme_cli_bin" id-ctrl "$device_path") + if [[ ! "$controller_id" =~ nvme_card-pd ]] ; then + err "Device is not a PD-NVMe device" + return 1 + fi + + # Fill the global variables for the id command for the given disk type + # Error messages will be printed closer to error, no need to reprint here + identify_pd_disk "$device_path" + if [[ $? -ne 0 ]]; then + return $? + fi + + # Gen symlinks or print out the globals set by the identify command + if [[ "$opt_gen_symlink" == 'true' ]]; then + gen_symlink "$device_path" + else + # These will be consumed by udev + echo "ID_SERIAL_SHORT=${ID_SERIAL_SHORT}" + echo "ID_SERIAL=${ID_SERIAL}" + fi + + return $? + +} +main "$@" diff --git a/image/mkosi/mkosi.skeleton/usr/lib/udev/rules.d/64-gce-disk-removal.rules b/image/mkosi/mkosi.skeleton/usr/lib/udev/rules.d/64-gce-disk-removal.rules new file mode 100644 index 000000000..dee719afe --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/udev/rules.d/64-gce-disk-removal.rules @@ -0,0 +1,17 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# When a disk is removed, unmount any remaining attached volumes. + +ACTION=="remove", SUBSYSTEM=="block", KERNEL=="sd*|vd*|nvme*", RUN+="/bin/sh -c '/bin/umount -fl /dev/$name && /usr/bin/logger -p daemon.warn -s WARNING: hot-removed /dev/$name that was still mounted, data may have been corrupted'" diff --git a/image/mkosi/mkosi.skeleton/usr/lib/udev/rules.d/65-gce-disk-naming.rules b/image/mkosi/mkosi.skeleton/usr/lib/udev/rules.d/65-gce-disk-naming.rules new file mode 100644 index 000000000..9258b92e1 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/udev/rules.d/65-gce-disk-naming.rules @@ -0,0 +1,37 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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 +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Name the attached disks as the specified by deviceName. + +ACTION!="add|change", GOTO="gce_disk_naming_end" +SUBSYSTEM!="block", GOTO="gce_disk_naming_end" + +# SCSI naming +KERNEL=="sd*|vd*", IMPORT{program}="scsi_id --export --whitelisted -d $tempnode" + +# NVME Local SSD naming +KERNEL=="nvme*n*", ATTRS{model}=="nvme_card", PROGRAM="/bin/sh -c 'nsid=$$(echo %k|sed -re s/nvme[0-9]+n\([0-9]+\).\*/\\1/); echo $$((nsid-1))'", ENV{ID_SERIAL_SHORT}="local-nvme-ssd-%c" +KERNEL=="nvme*", ATTRS{model}=="nvme_card", ENV{ID_SERIAL}="Google_EphemeralDisk_$env{ID_SERIAL_SHORT}" + +# NVME Persistent Disk IO Timeout +KERNEL=="nvme*n*", ENV{DEVTYPE}=="disk", ATTRS{model}=="nvme_card-pd", ATTR{queue/io_timeout}="4294967295" + +# NVME Persistent Disk Naming +KERNEL=="nvme*n*", ATTRS{model}=="nvme_card-pd", IMPORT{program}="google_nvme_id -d $tempnode" + +# Symlinks +KERNEL=="sd*|vd*|nvme*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/google-$env{ID_SERIAL_SHORT}" +KERNEL=="sd*|vd*|nvme*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/google-$env{ID_SERIAL_SHORT}-part%n" + +LABEL="gce_disk_naming_end" diff --git a/image/mkosi/mkosi.skeleton/usr/lib/udev/rules.d/98-override-systemd.rules b/image/mkosi/mkosi.skeleton/usr/lib/udev/rules.d/98-override-systemd.rules new file mode 100644 index 000000000..e5a704e2d --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/lib/udev/rules.d/98-override-systemd.rules @@ -0,0 +1,3 @@ +# prevent systemd udev rules from marking unformatted device mapper device as unready (SYSTEMD_READY=0) +# this is the offending rule from systemd: SUBSYSTEM=="block", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0" +SUBSYSTEM=="block", ENV{DM_NAME}=="state", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}="constellation-state" diff --git a/image/mkosi/mkosi.skeleton/usr/libexec/constellation-pcrs b/image/mkosi/mkosi.skeleton/usr/libexec/constellation-pcrs new file mode 100755 index 000000000..d95091275 --- /dev/null +++ b/image/mkosi/mkosi.skeleton/usr/libexec/constellation-pcrs @@ -0,0 +1,10 @@ +#!/usr/bin/bash +# This script reads the PCR state of the system +# and prints the message to the serial console + +main() { + pcr_state="$(tpm2_pcrread sha256)" + echo -e "PCR state:\n${pcr_state}\n" > /run/issue.d/35_constellation_pcrs.issue +} + +main diff --git a/image/mkosi/pki_testing/KEK.auth b/image/mkosi/pki_testing/KEK.auth new file mode 100644 index 0000000000000000000000000000000000000000..4cca39eaa8a99f75883d8432019ed57bc212bacb GIT binary patch literal 4143 zcmd6pcT`i^7RGZ^=+)3`1nB}dp$jO86h%O~Fe)t(5=t5=bU@a&d#@g_j}99EiNR)4g2=` z4Fz4n-wWh*pWpT}U}|gfIo((TH$o{$M?HrF09Fv>=iv5c+5iLu5)PnXATI~EI@5+Z z&kt|{g>(cPq$6H|bojkO1RQ|FMVva8x&v{T_f9+9HvK z4Y>Hw_GAj454)(RdYJh61^9Vi#3vviF9u(vgMkI$|T%aw9 zA^sRwORKFI3v&z(#Nj|WaenC22&aS9#p;9lo~t1i{2uhE`?Xm@J&TwGC#&~|cLre&H zq(xz~3^~w8bR$L!=N;d5nKYfHtY=^L&^zl`0cIk(kN*X>c)Ic>xjNTl(xIzH)_>fF zYhLMDqV!#bp1cr1W;WM{{S$sx6(ujEMGs9b>!huP~S3FWp^L=3tsG3JI^PRgb zOtz!w0*3 zbyBHt1ONlhYywR|Sx5k~0!T5Wi0Sf)3cr3VV{ZR&^DhjQx1oe$0Z?#t8Vvv|NEC>G zz93OU1A<5-q+#ZdC5F@rl^B3IPsy2Obw47N#s7N!`sOZaqbXkcfk#Rc^CN=_atZnZ zIUKv}2;RK_bI&@uhWQMC0a!oUBSU6Xu`H66r{o;6vGNJ>H{xvv#w4REMA6;@5ic~+ zBUcN}%qFRAg!Io@lUWbjRs8*>YjgI+J;zOxip55iGyH)9CMh;D;X-e-9K9q@=f(C1 z;uJ(r>xI)T<>GHY9;$h8#{_S{Asdl35!>1TeAa-_#U;Pn;j2^#g#Qu0hfPSnY{5Iq5E! zx4&@gc$rK}KAfWLMG7zpYw9Vz@zi{`^C@NN7>_i!)2fR>!dn%Zwx~+TxX4WibC%_& z4eHn2Exor8c*D!_r!GNs)Gx?U~j*{M{*zk?;nd|E5&`3Gj2=kMlc= zUD}?xSIxe=**Pv6u)SVr-mQ{J@?+<$Bp4P&^lQ;k8H@sHh39vlbm{}7j)s+E!+f5m zK^_|oB@`c&7D^bsxU4Km+Jj<85PYvTNrkbt$VmlwB3E(|hxR)jh&I?A(QO%KoUm6} zU_piRluT9D9@Z6kI7W(@^1dukOsYW1XoYY!SLB&p?oRMon- z2Ptx;xU~JORAdp_y22`or@6P$NAGBq`=fi&p+v$iDIp{J2);CHlNv0ir)?qn=!sIw z8tvOCj>w##4X%o`UcSCwlbf7TSN+>bqtuCM!vYqcia}h17*|~sD(y4jXMmqs%P<4i zPo0j|N)<%${%W@v5!?8`1O9aE7W{9c2`FYPy|O(uGV%z?GhqGwjO-nnxz)QSr7|U9 z_RK-qc(kw+Pa~B_bUCkN@V8Qw%omL!63?8cG9b55Fak0rAYT7tvw`OM#TtBZ-y*xBcW4+|@ z4x5WS5ln{dK(tOPEA3ea(jvr`{TQ!#uyt)xRAVy6*PxD=;HM)z%%PHuJuY@VUWMzB z+qhS2qyWmEJ2Ll9;4g8$S{M0Hw7hZGeSIkgU7&T~(~{~H5wOX+b0E(+J*qH9_G#Mj zG5!M$%YIh6{f#kj*C$W^i~|XduQ>P&*~4qO3y~fOoZU5V)!E^rQMQmZ9D$JV;42Pz ze0Uxn`mz}D7YL;P00CELEE*JE?OHB0kGl^w0J36X zEow*fqmZfOy%u~Ym}SEh8NxUZ-MXTF#g{t9w;psjieYvwYriU3q2HVw?d+O$Ci!mQ zwP<*)w6u)+)N@;;Lin{J>u_j&v8>%hHT%?p*sZ>%_MVa3+Uyfk>rxOChi6j8nzt=l z2(RIdtFz7sdj1y48lTfajtc?m``DijpiNekxU~Z!tX3Kwu0OBZr@pg%QJ|Y<`sO6T zxI<07;4{UeXuLXO`lB8?p#?ti#;YSQqI23Wqv<@&j6q9^A95-i$&2PB9u@sc0XpCS zRmv6=;^5Zc0FVIPKonT@Z?GTCpYLaj&ccnw?fz@Je|h3s8QpOy*$b5XeuD@c$tTAH zbB2Y(d|?(a^FP|aznDaMNOiJ`NC{9ZLBw*elf|pJox(SI?ei5~xr{d`kjlVas|)0j zuAnpMSm;n_$FvOy3k%(#t?fq%(hB~jWi3B)uy$x5adlKXltRXb`-M@pAz45gholSX z77{I_RWBTf1vQ~JsHX)j1-&`ApdX4taRLC+1#|*;e2YOibIb1sMMg&c>>vW=zc?Z6 zPwk7KL&fZ29GVl!lz_LXn=Gnl$nfqswW6ecAHt;Y|5jb-u&4E2?Tj(er&VB@ZJSP_48{!L*E1x0YX$ z24h!CgAY-03z!TBWA1It@g&LWBOiy*SxK;P%- zHlnm{f52of{C-d--=q6M3bd*V@2(<>th~?N=Df9*{(fm@gog9J(O+4jAY$9r)NeZ; zyUAUz_N_zsuQlEX1?TE?nr!b$b9qswOK9y2em%jM8eK}`ac|>ywDF=^ncYQVmy_;{ zN`I_7u0%F07)oDArsXsf1?tbpU{J?@YZIx4_1*q(Q$#2{P`6OJ?u7S;T{U;y?e)8H Ij2rp?0isP8H2?qr literal 0 HcmV?d00001 diff --git a/image/mkosi/pki_testing/KEK.cer b/image/mkosi/pki_testing/KEK.cer new file mode 100644 index 0000000000000000000000000000000000000000..4892fd5406a2dde761a14b0563d31e399deba3b5 GIT binary patch literal 995 zcmXqLV!m(C#B_WCGZP~dlZc$g?kDT*_Vu2gpvt9Y*w|_6dHTNrFB_*;n@8JsUPeZ4 zRtAH{4nuAOPB!LH7B*of7gs|W11S)PgGbmezbK_BBQ-NmAw0FXBrP!~HP4VAs2wQF z&co)EpPW&eYba+R0}|lk5p_*TPt8d!E>;MxEG|jSEmm;PP4Y0*GSC3YGxI1q=jQ>% zb8-?(GV}8kLV!kQ=A|omyLu})J1Q6%7#SJJiSq(UOCw`L6GJlt^C%G4&;ZUIOipcL zR6-6&Mpg#qCPsb+gC<5UrY1&4hOeAg=bc>=a_V;Y+AkjtoP8~t;j>-fd)S(`tmLON z{x?`GD!ZZA#5$>EzO>Sv<2TQmF=n0F`G4|ro+#U#NIMG&9cY{ZeP2BeQmDT<322CT{*luDunS z-72vfGk0@N>wKKsc4d?DnN6lrxtm(8mD)9Debdl88OI{Bd&%nj`J?W>jUKYQ3Z!y1j@&NHX}fJ&>&rTeS0Fxcr&o?hWU{ zmrZSD-1W};XV)R2mF^+>XYJgkEsks#dD=Fu$MxUgUuJ55Rn7<;^bHq(^=Mt^-Hc9# z>yknL1DBd#)SNr{e|mR_$E?Q(?Oyo`MO%W%5bzIt_zjsy-f5~np MH+I!9h2Fdc0L{K=vH$=8 literal 0 HcmV?d00001 diff --git a/image/mkosi/pki_testing/KEK.crt b/image/mkosi/pki_testing/KEK.crt new file mode 100644 index 000000000..5008fd428 --- /dev/null +++ b/image/mkosi/pki_testing/KEK.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID3zCCAsegAwIBAgIUHii75K8+vo3LkCUKJjGBiTVJy/8wDQYJKoZIhvcNAQEL +BQAwgYgxCzAJBgNVBAYTAkRFMRwwGgYDVQQIDBNOb3JkcmhlaW4gV2VzdGZhbGVu +MQ8wDQYDVQQHDAZCb2NodW0xHjAcBgNVBAoMFUVkZ2VsZXNzIFN5c3RlbXMgR21i +SDEqMCgGA1UEAwwhQ29uc3RlbGxhdGlvbiBUZXN0aW5nIEtFSyBDQSAyMDIyMB4X +DTIyMDkyMzE0MTYwN1oXDTIyMTAyMzE0MTYwN1owgYgxCzAJBgNVBAYTAkRFMRww +GgYDVQQIDBNOb3JkcmhlaW4gV2VzdGZhbGVuMQ8wDQYDVQQHDAZCb2NodW0xHjAc +BgNVBAoMFUVkZ2VsZXNzIFN5c3RlbXMgR21iSDEqMCgGA1UEAwwhQ29uc3RlbGxh +dGlvbiBUZXN0aW5nIEtFSyBDQSAyMDIyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA9QnVns2kVMrbV6308MDN6xVoTLcQ91ashmpj5Zj/gDiidtguggWS +hJ8bItzH2c02AWrMuf+T5wxaPWxZPjgYI9CnoBg53rgmGWpeBeV2ZWK8wRp0iUQe +GmhaBP+aA4h6UYN7N1120kV0O4BmJg76JwecHK2VXom7H4ILD4EKvXgpiyRdKJm7 +CZaJ422G1LIjzLI1Gm2yhTsihyma9iguyV4EFLukp8umGneiE0erRngKw9a6YTWP +eFfTyXtwaWVcGhA5guhkp5U/KQCY1Mr6e4+Zp3ISL8QFBneYbDpVI3nWDNfWPMAH +eLxny2rpc+zvOJ+JDCc3frkWCLV4BZD8ZQIDAQABoz8wPTAdBgNVHQ4EFgQU8iGE +QDAs7qF7LowPBQu0Tft2fbowDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAYYw +DQYJKoZIhvcNAQELBQADggEBAKF9RGT46YAFhn2CrMuMd3eOalpoLM+SllAtmq5c +7RqUGQBOhuAdf1aiucFXH8xzi7DOV6aVhQG67kv5isISqUdUL80+RpajWYcU5YaW +jEX+w/o2Jv0kzBDBTVcX6uKuid1oiQDXGVL/UaU30Smdk/9ni1RImuPBPupNEljU +AjaduiqqcJArLBmXzEizCnaGhEvdezPIiZDbzARDbkvl1WQthcghh3i6iiBiN7Vp +gGMzEecGJ4oxlxa+fycIiFbrX8h3DgVOCXeaxWtbfmIuswwFeZ3rVXHXizfOMEdr +2qWu/xQwwUfN3Z07kXigfB3akJfqDYO5/mNGNNi6fAJV2do= +-----END CERTIFICATE----- diff --git a/image/mkosi/pki_testing/KEK.esl b/image/mkosi/pki_testing/KEK.esl new file mode 100644 index 0000000000000000000000000000000000000000..3a96e7f4864a0abb6ac4956512f33c612ab3d404 GIT binary patch literal 2599 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 literal 0 HcmV?d00001 diff --git a/image/mkosi/pki_testing/MicCorKEKCA2011_2011-06-24.crt b/image/mkosi/pki_testing/MicCorKEKCA2011_2011-06-24.crt new file mode 100644 index 0000000000000000000000000000000000000000..2787083e0cb615ff8c7beaac3b0a598ff5ec5870 GIT binary patch literal 1516 zcmXqLVtrxI#C%}^GZP~d6IUYF#SR7#U^d`oQxhX2!;u$TyY{aQSKFX=_|@~@;Z-h7vFyCJyq=b5 zJ=?(lCinH5`kjxXl8tHv#r^pnb1%0Lo!ocq>w}h!vu5i&|GItRHO_~R4zR3PV<2R91&S9_(-|4 zw_y7cS>HG7p3eCtcIf)S(^p;`(SJJgok}H`B=nQM3VkEpIuxws!gliCC zV&ReFVhCm^Wk_OhW^gp%2I=Hy0U6U~zz^aGGcx{XVKra|QU>xM0c92m1F;4X*R&w# zhjkHx`>*-UQx4^@wo=MkVGsjSAkPwN5Nr^*z<+^nn|DS@Nr9EVesWQcUM?&x>m}#s z>K9~Zf<*NTitQ<3X)E3>+FDvQfnk;IlCr2*mD_ikX9ZRZqL6?=D`>xf9< zxfXsxa&bKCwcE!oWS;ZzHroC=_L9NZ17COSs$gHN{crYdldzUIO{dm5sus-2e)(?# z|Mh9|PoGbb-=xLU>-}FtQ=t0$^_ry@%XYG!sC>&mVbYvK|L*74oX7zgh@9nG?To0`c7HO3KZNRe1+$`~ySEjVd zjf}U~n9k=+;kkT1N2zk{#t(a#7r7;@Ji>lRvFYRAPcJHs687I%vs6jM`_#c3-mh!z z!%a6m^Do`9A%R&bc-_QG*=w^MpcIued0CFhmQ`htXN|pbKm1LTfnT8<$?7l zTK)SK+Rpvce>net(}A}y&z}1doRwt7?Y#4m>fe8?Kd&4SSuOZTxwE%m`x05-H|w6x z`6YJf`oYszUL4VXI`f@MH}jj`Pu;H$d;NA66ymPi>OLvw&NG(I*I$iUUJEd46+Zph zENt^%l~X^X%UETJ!%DMJ{^1Zqoa2ros)!nBF{z zKQp)N?EB)Vs15iX1^#CGb01z;wDCaV2F4d2(WQ#voW$THkpeu zvH(*ggMlnCq-FV7#8^a<{y3jqV7KISy3nQQo1tr}&ur_8H;{yD5Mg5Bk>g?rW+-Jy zVsK_~G~fp5F=%35I%15zN*5^4}^5V*j9fp434MoCG5mA-y*QI1|NEG_FL=jZAdWM_gz^$Uvf zQ%aLdiuHlX0+_~uNf(%Ifr%EFR^x$*!9W*?3{3TaN(~a&IDj5yWo2h%WC<|{G6;b2 z4Vc{yO%O!Pf&{ckHTQU#$Ia_HC1}mN!kO);X#c%*lTFZvy}IY4T5>Pm$lG z#nbEkUqe%%`up{or5DR~vYx1X%Rgb#oJ0Ta=hx-%S6?~kde0GxOV&m$aW=_BW#LN@lv~#Ja{$^}t`RyCf`mD&9u=sttsk6E?{6E-|F-nzKsVyYyU)blkpOAa=*`&n$%=RGRY zp8vO3Z;$1+=g$s5cyd;~<^2?=_nO@k+#IbNrPFWxbdF3t&AaC>!zBMNrPj+=s{9FX zbf|ow>(7;?UX~a1c3Nijdj9Y2tQTAltqm4wl>cqOvdY{n@s?Mnw8@Q(x7V1?=S<L9-QzXoui0Qyv}<~T^@qyWi#Ex`E)v_(e)OgEx2@Av^DX8- zp7^V)a>n6IzU_-;6j-PKI3==<;rfx!2Sfx)vrQIAZ=IR&IcCGra6hw4MlJj20RViQ BVJQFr literal 0 HcmV?d00001 diff --git a/image/mkosi/pki_testing/MicCorUEFCA2011_2011-06-27.crt b/image/mkosi/pki_testing/MicCorUEFCA2011_2011-06-27.crt new file mode 100644 index 0000000000000000000000000000000000000000..9aa6ac6c79b21cf1c23b01b5a747aea6ca15da37 GIT binary patch literal 1556 zcmXqLViPcEV*as!nTe5!i7S!g@(~6QU@_ojd87gG}>Bg0aT9G~N^oLSyHOAfTxvz78VGlrx*5UXc@ zJE@j?Q}KQtu47)Vi3^U3=}x=+ReQm2U(eZ&4HIm3hWvfD=i=NWOC-AL9lK&8n=_1d z_qd;YSGY&fe^yt`e;51Sexprl9_vcCzB}n7=OtP9q-mCHMY%7}hP~hTFNkO^jv05GgVcV&l|i zV`O1$G8biJVFk+>C?mv}Sj1RFejLo+USA&U^;y+i)^DL&HNQeZgMlnCMr8Rw(!y)^ zJ9F-BDwxxA)!#7hs?v-u=_>}3a5F@hSa{^P7=jr}8Il;B85|9`K|1+aSb!Oz&43@o z5oTok&%$cJ45SR?K?2Gw5(Z)oBCcsc&JXJ%1ovO_o2MMgVQr<9wZb3jRSyFfRa;I52$! z6E`qT#{<)hfi4gknCbzQ8YHlB0KUE;q>3&%(?GnJZl9qB1|>ijLOt&-U~UZJ4t)3%5Ajph!hU}{4&C1 znHYD|s@Sznw;Gxq+4{H0eq!GFSt?fgW59%;n?qZiG-MR^Zdw;8a`eEO=~ESDCfw%# zQ$BBM@x+c(d-n$IWDVfGA3kqE;#=OQxvDoE_{AMgoLlU5$anoLAz6-){=LWd?9{gP z)Rs5;lckvHKl?QI|H^}7P`p3e|O3K zJ97OESKmr}(H9ZR*1wn5vqAak@s=BJUmY}VS{vpqq5CmoD*M^8kH{0YRa-%tSY$V?b_=s>rUTrh+NQeajH+!L?x*b*&bVWK9^-r zHq16L-S}%;@Cu#AH%nLxPt4u1>xHyS+7tH>zP_;f&GW@(Y-+oZVK+f}tA1R6Kx^-@ z-lllRgN1MfA-&c}SF>PgInqRZZ2P+zbh(mdgZ#grWnDhht= h@@Z?I^6kMoCf9eVhqf)Q%M>eRpEUdHvOST_5de>mHUa_C*_cCF*o2uvgAIiZ1VJ1Q zVXpAR;*89^^pgBMLjeOmkRZD-dr)dhZhl^hp`3vXNQ6sR)HgG^D8D#Atwg~&zo;O; zD6u3HsKeU85+u(oY=l)_AtWQSC`BP4v8bd{!8freJGG=BCowryAt*n;#6V7**U-?w z%*fox(8$QdG)kP;$PB_Y25}7<8)@QZZ39h+o0YJ;In>q7Q^DC$!N>sUx+X>?${Uaa$b^kPnu@QR+RhlY}osa|FYQSJ-@V<23o{^{k`jU1=H>S zZ@8qVU2WbWDg1KVfog~9hw>WgCx5*Ui<5a)H>K{t2bWEimQQbOO6vCAZ&C0lLq+7I z@e&U6s}Y%Tmuuc0WC`YY?zcg!J((jhKUp;L)h6xA>pY3+UD1Ez*0$I0YD@Poj1W>{ zQBpeB{XV3S;aq@eMA=l1cUc=3Fq@BrUvlzcc6Frh+*=SN#q1 zt}4ywlD=Xf2{%K8iG@dwiy@eylp%@1nZeP38>Ew;g$0-a+6?$X9AQSr|17Kq%s|RO z9wea5B4HrbAmW-9`aiTenC-wN@;RQu|6>Q0P_Mci38I&FmVIZbUZN480Z3# zfvFx)sX+o82QWNXS=kvGSwakg3<6+$1Ew|?s72-F<=8ArEh55(66CZA%;wBZOpFYs z98UiY&Yb&R#?h`(pQU1@KL$+rxjD4ONkc|q@1}KuB1aFbnLbrfX2Na$KjrhL7EkOrwRdmO zPSyb4`{DBzB);W+nyY%#fnVI=#JR;@hkV!15|ZTz>EC;N&rWSyPi=XlKUs>I{l-#lMz#-_Fl8Fmwtx9Z3B2ekGc>urj6T=+$g_rc6d zIi*jwWo}h$`^A3o+auqLx7O;E2g|7%nIF#yDw^81;iG9{mgLt>){OyS%ZzmYE$aN~ z)TS;Gy0Ga~)a)MyGeSg`xldEoKcV)-af(z7ll{|ak6WW{?Cf{Dixq`FQdQb`v-&wR zo7Up*aueJRGw@!M?0n2;s-DDLD7x(Z1@#3BBFz(iSWMaRprYW%E}ypcDc>HfV{(0$ WdT86?x=gWB_DQq9F545?9035V8Amh# literal 0 HcmV?d00001 diff --git a/image/mkosi/pki_testing/MicWinProPCA2011_2011-10-19.crt b/image/mkosi/pki_testing/MicWinProPCA2011_2011-10-19.crt new file mode 100644 index 0000000000000000000000000000000000000000..a6d001c219389bbdd9f011ccac1b620defcd44bd GIT binary patch literal 1499 zcmXqLV!dwA#Jqn2GZP~d6IUX8Sr`Kda2W8iacZ@Bw0-AgWaMULFlg*BBvrw&v?L?HD6^ze z!N|bSz(7u%*U-?=z|hjr!o<+TC`z2y$PB_Y1#t};TWI1`Jp&zxQ&ka84bRL=$uBQf z2q?-=DNP3XNFl)45#&rmgC<5L{yk8AUeRmzWhZyaSqGceJiYuzeP_GO zznv$QIrCSzO+1)4&BpQa>BaW3Oj*8fGUZh@V$A;kbr$8C@<4LS`TK{29vzBSf2Uqy z&>gMCnXS|roFJxiAVW5I*Bj5za}#@7GdPP~Vrv(LXy2{;E_&WHHb+J~=G>k+%H8>S zTh(rw2_N>qroL{ck+tI_orlNImcLjP;`cpmjt1Nyo%}2yW7-V(K^$R5#{Vp=2FyUpKprHZ z%pzeR)*y2ATiEIT7mH$&GA`OqnGk*b+$@PB24Nrt@+|%az6Rb4JQujPxn`7<6jrfX!Z2UKJb#l`{j zA}cF9BO{BSfscU~jBmiyW(T#Ryu2Kn6~N4Z&+HQ9ga*v5%uT=m6!}wA7`U|ZP~N8Z zmUeq=g81{a?FEF3|EFLizEK78Zu;`nWUQnsi*c*pB~ z$qyde8m4Y&eEMn4S+OPaZC7lZeaPv;gqHXa+5erdcFDR=$lp-x=Q!VCe*DvgTAKtX z7I!IXd^mTn*fQR3bxgvW`^*9>E_1&8@@-n{w)()1Ge@>ec3(c~3GG&F?i{ z{8lQ-ntpk5c$}uR<%xH?56?bvEsnl$>0H%nG07&khzoIZ8#kw~&oTY9=c&EQBhy7( zrEK3M!e(Bn(7DJe{rW-&EB)G3mq&^vrrU323H zMVl`&2aoQYFqyBzb#mLwjS4gO%{YB@>XO)`YYUP&6!w-1l-JsRcHKFD`ux-34f)0^ NSjq8C z`xh`XF)}f6C9;==fz@&t@Un4gwRyCC=VfH%W@RvF>@egu;ACSCWnmL$3Jo?CHV_1H zIE1;v6N@u4^U_Q5^9%(H_&|c}!t6n*DY^N1DTZv}YxZR)cgk4@o7OzN{6>9eyUf3xCzUz#SGY|) zm^aPF@$%`#_OVP^zHc(+RW)MF{{M9r<(l$9a?APqhlCy-idKK8USZH3t;LzG)ES&0 zrgI=eHh9+?&(Cucds;I%i(O)C7lmlwt^6)}-ZVBxMmy%*o;k|h`FUH_Zkh=n_P?gS zZl{s8<0PGj$Iq6(SQX;;J%*d5J#~w-#EMN1awW^(M5+ApU}j=wWMEv}#OMqR5qkpx zHco9eMi#~HZgsVv;g0+D@4eef``li6aJKAO-R){sz7V-U~bzxVO1xl#~=$>FXyK<>=+YlCfTL zey)B&b|y$vzW@^d#rnXc0ZhKY#0yNb@u1YIYhb2pWUL2NWDv#10rVm(D?1}2i=Tmy zfftN#z|>|3wW7Sd9Gexu%z)4A66Ayi%&p8#zyK8aQ&SkYwDM5iruUY1du)RE^R(>+ zgp2>J$hhFK%*3~A8mrnnL$?WumDm1T=(%QpIq+0t$1U0ZuG^f~rH=b>nWbg*ypg`n zGGT>;_>$Q>A2}GAl^r=4b!`6=mIJTEF0VP9@jhwI-H@CBgNS9XYyM4H?$`I_O-);I z_@N-hVw0%Pi@U;3u-szjeEXyO@wqQ`ed|7as6Ked>wU=&9@`qGZfJb^ zY0X)&CG%}pY@B__>B5AT_z>Cuov(Jux=+a8Q0(V8-(i0I(}h}_1Sb}EDQbK;cdyto z-fneF!khcd0xK?azWnlSTI;s@z>YL`$=*d9glrqNGFZ!ZPxMKu-gc1v_^zsU6J|c| zq^g-OPyIRPWqwk3NqCLSKifMy_@jPZJF=OnmC5SW=9_s>G8N75HD3HyD#@CDd2)E1 zrnKdWce)SHK5;FMzHsSW)oL-xCbx(SadR6tr?1a3{j}$)y~-ogMO>w9-z36jUa8Qz z$SVE%LI>mARRSMb@9(P9N#4#jTUqhQ&x)K!5#nrS+7pGC&n&t5Nq5)JDRUj(O1OSJ z*AD+J1K3Ie+^6)8P&I#w%IQmoG_@iL3(v D6(vW! literal 0 HcmV?d00001 diff --git a/image/mkosi/pki_testing/PK.auth b/image/mkosi/pki_testing/PK.auth new file mode 100644 index 0000000000000000000000000000000000000000..5097d54122e30ca83fb25ba3f5e154264450f55c GIT binary patch literal 2585 zcmaFH&M7V+z{vmuKUje*rjLAcFRk~wpYhJKYo$r8d06UlgC^EHOpJ_%{06*ioC$3n zjH%2lOpL4y2Hb3%T5TR}-+39?85cA$KQ(A#erV9dbaDYR6C)FoNYI(Tm-yHCHvYTG z$dmf-fo8%Z9v_eqP(6&?KqDGE4Y>_C*_cCF*o2u}Tn%Lmq(B@F9$~-yqLiYH)XY4E z@YLdxw8Wg$Jg^IZvg|x;PWj0hrMZT31~MS!Ts)$#De0*>sl~+#!Ii}&sky}p?zu@G zhS~<2AbDmUCFlG+pmzbSz`29Utxb$d$UzB=4dy0Beg=akMlPl%Mn;AmwV4ZF)xPRk+36)~yyv=Y z-L`bWGxN2poISK-TdpYnbFTbqarc*p^>-crn!NlM$CR98^0N~~?G*Hk66(+G$a+6j z&D3wj#e}Jo=PSJFy3TvgaLM~M_w(1yihS#TZi8(4YY&d^s<#`Zk1Ji7o5v{gWme+T zTg;mm$jZ)d?PF>>ZBRR#+2WFd>X#^du-<=F!}&=e$zCGj@v(Xs^`l zl%Ke+$9Uqm))}o@$+)MOiJ6gsak0ID zt${2s0m$;Ph_Q&+{+qcv`G#T3*Q)1-qg&LU6{IfVGvEhF3o|nQXJIv922#L84HV#K zVF9M$Hsl}%rdD7OGcp9flXIAQ>2lVJ`YrqRIh~WXe8=6?d|CC)_ZJV8QKA(sumBJKtdY%PTVZEo(cSyVTyv`A;*HZ;;<#?|t``WW{Px;e@+o_jH9{ z>{;O8@V59=>cl@&-%h=FT0K2odee-;x;sYivzCaxRGXB}IKM5cw!C5EwZn2vOXnKj z^SK~i#C+w%#)ZdLi9h?+vEjl|n-p_4Y4*D01TD7;^#?%`nRnb9S6Bb+z52NL&NlV8 zVsXO4tBY#X9k`E%Nf$qy=rQ+>|2>yQX0qLj|GoU<&@!)3z2_;@1eQGJ%8)eGo-@hJ zi+?Kk={3FbUMl1;t!SR!eey`>jwS_ORu)@%SOHq z`V@Y}^>S(lxA1&esricdsb%efz literal 0 HcmV?d00001 diff --git a/image/mkosi/pki_testing/PK.cer b/image/mkosi/pki_testing/PK.cer new file mode 100644 index 0000000000000000000000000000000000000000..90dce747f316946ec0f761d553af6707c2589568 GIT binary patch literal 997 zcmXqLVt#1Q#B_22GZP~dlSt5+znA#e_%{B#$;gxX?}28*BOV_EUN%mxHjlRNyo`+8 ztPBQ?orc^7oNUaYENsF|F0O_$22vmn2am8{eo;zMMrvlBLU?L%Nm^n~YMvoKP&-hT zorldSKRKf`*HF$t1|-16BkG!xo|=(JE+{+ z#HfTEl#Hwl%uS5^3hc9dHFAnDLKjHXD5o=qr+Ua8qBKXF};@x*VfGg`IE zrIH_Xy2W`-TlN0L-JDZ9kLSLv72H){`rurWaZfQ5Gb01zVtWHy16g1KkmX|$V-d0a zH*oZW@P-&!fL<_qzt%00{kp2z%<;39K^uX3JhXK zhTwN{4pT2(&RS8wW#2xhbJCXYxSN_UtG@aE;(?M}gBjlpwiw^kglmj#aVkyPj-Pnv z8*G1hMJB&xZKrdW+B-S_X@>F*^84$(@4k|(SS>1?aJTH9uJDUJ3mhEY7N1I;_-E?d zsTWVHr>9GAno(GH$LM|560w(RlhPUIw`J9qH*CCiSgvX5T;qE_7sQL0ubkMp@YpKx zXWu$DTsUfzV$LSbUYDGpYu$=9~a-*rv6qePFQ$#QH{C-_t7xv z;)fGG=HBtY=d#F5wtMlvmwy~u<`t^>dD6<#GuC literal 0 HcmV?d00001 diff --git a/image/mkosi/pki_testing/PK.crt b/image/mkosi/pki_testing/PK.crt new file mode 100644 index 000000000..5636665fc --- /dev/null +++ b/image/mkosi/pki_testing/PK.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID4TCCAsmgAwIBAgIUUsz90g+sTYH+2QEMZf7gKWDiDEwwDQYJKoZIhvcNAQEL +BQAwgYkxCzAJBgNVBAYTAkRFMRwwGgYDVQQIDBNOb3JkcmhlaW4gV2VzdGZhbGVu +MQ8wDQYDVQQHDAZCb2NodW0xHjAcBgNVBAoMFUVkZ2VsZXNzIFN5c3RlbXMgR21i +SDErMCkGA1UEAwwiQ29uc3RlbGxhdGlvbiBUZXN0aW5nIFVFRkkgQ0EgMjAyMjAe +Fw0yMjA5MjMxNDE2MDZaFw0yMjEwMjMxNDE2MDZaMIGJMQswCQYDVQQGEwJERTEc +MBoGA1UECAwTTm9yZHJoZWluIFdlc3RmYWxlbjEPMA0GA1UEBwwGQm9jaHVtMR4w +HAYDVQQKDBVFZGdlbGVzcyBTeXN0ZW1zIEdtYkgxKzApBgNVBAMMIkNvbnN0ZWxs +YXRpb24gVGVzdGluZyBVRUZJIENBIDIwMjIwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQC4fWmh6n3qjKmJSh0zvNc9frZnEcyfK3pDSCtdhNQh/kN59Tjd ++kg79yxPfG5v6MYiQhxva2EVPiAuMmB/zrhq75UmNU6o0WCVk58g7IrXDd4xpO+s +32+umlntT86wHWfrSAj3JduBG8ci1J1uARz0mmHl2gOzoB0dn4WOAoLLMH2bAzjS +ICX0giXiY6Q66JQya4OPMvdwSAW78H6JgTtNIsYKn2clnA3VJZWXIzYl6Bd92zjC +6RFrhzu7WYw9nmIA0HMtjpSeU9JDPUmedU7MPqLAK6kpiR+RrowzkfaFmIUqdxpj +4IlGXkqWqu/I3WzKucdt7X0Run914M5iM4xzAgMBAAGjPzA9MB0GA1UdDgQWBBQ9 +/pmrY9gxhPV658NbhCfmcGWkDjAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB +hjANBgkqhkiG9w0BAQsFAAOCAQEAU+4eQJXS02qof7S+vkLOGznuC4KD0yXs9+jg +Ih6ANg6YBlxNZWDWAYZeJIIrQfINnzC36dQcb4StiUOKJu4eT5YxH4Afv39L3eoZ +eKsVE2Dddt4tE+i8oEBA7XPKZZH8le2V0csnZ2cbsphxftwy72qkFukmkmcBn4Zq +fXeAsdbDHoKlnTPeTNAXcgPUyLGhxqoX5vaIsNDFPGQ3BhsHfmNgKkZ4J+BSGGnc +R4Gre/mN1eNz3LYn7RZeExOrcnwnQAvFVhtz4ZFIndxP3kSiNh2Lo/7p/ECEnnEn +jOUCkARuA3lUZiWMzGMDo/kgTi6C6kulEkCWcp417OeXmThrjA== +-----END CERTIFICATE----- diff --git a/image/mkosi/pki_testing/PK.esl b/image/mkosi/pki_testing/PK.esl new file mode 100644 index 0000000000000000000000000000000000000000..d716f8de72e8efc19652dcb4363f564e2c91a5ce GIT binary patch literal 1041 zcmZ1&d0^?2Da*aux2_hA(f&{*$ie^yUzr&g?tVJ9jZv7xcgokkmItfSwi`4tKQw4! zI=O(EiIIs(Bd#AN85K^Mn-N{27|^RH+8C2PFrx^3OIbip(8wX2*xv}0SYDE@P<{AzLc zmxuLt9sioV{1?ZRoMiH|6GiP5^o$bf&+W*1KUK}tZ^gxgsgvg`yy?2md(Uvm`!)CT z*UgH2>wj*8Z2D^tj_<0s8>NpcU74H5DD!1j;?rBqn-|E+&Ts8wYC3IDJDb_!l7i}& zCe=sDORQc@G0JZ4H~L=S!MgiHU1y`UuhKED`RS^2c(1BXovv)A`a-<+w#A{Bg4ylX zyCZvS=Or;*DAw(pGB5a&v#sa6Qol2HiwxUR=|;&Z(WpbKlkq?y4_+a4yNXrKAo)1^1f zD6G3<^ge5e*h{rZ>5TK+vTDm4HeNd{*R*u5@jagl;zi6?PHbFwY?b)4Zyg&h9JNU? zXOm{HOHR;ot5AOsB$0W?y>WH*&)%z#i|=exe=8OzEWEm?M%{t?Xqa^I!-*bq@A%(y zS!5>Lz4+hDKMpPP3e|g_GEHE~W3CKIQ|&pE%)I!gf}dW~EAOR34%3R}nZ9{GeWpcr F4*>-e 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 b>=Fz==X0~ZIEKU*iawtIp|r*Mu+zT)V`)z< literal 0 HcmV?d00001 diff --git a/image/mkosi/pki_testing/db.cer b/image/mkosi/pki_testing/db.cer new file mode 100644 index 0000000000000000000000000000000000000000..9b4492b6a11971599057f987430c338844e49a96 GIT binary patch literal 989 zcmXqLV!mn6#B^{0GZP~dlZfLq@mDV{<$qz-&#GbV+jjC&y^NayFB_*;n@8JsUPeZ4 zRtAH{Rzq$BPB!LH7B*of7gs|W11S)PgGbmezbK_BBQ-NmAw0FXBrP!~HP4VAs2wQF z&co)EpPW&eYba+R0}|lk5p_*TPt8d!E>;MxEG|jSEmm;PP4X~QH&6x1GxNwf=jQ>% zb8-?(GV}8kLV!kQ=A|nHI6EpB85kKE$cgg;NlPPRLlZ+Y1M?^l*U$jY9W?H2VpKv7 zLPk~w<|amd27@L>E~X|%Muy{^k*1ojq;;JqpD1*wFh0}e#I$$cncu!kKFy6=&#%)~ zS|cc!4`YSV29^&e z7lzed_l|z%*ZuX z!EBF53Jp&zWs4kZcQbEt^l1w^cVO$PZ(C=5Yfakq;!a}WmHGWQb9V@S*yNPHV4B>< z+49~rVH>_}PV<5F1iGULUeBa>d~ z`kvmvZ}wSLwq~#KZ0R*?W)}bA-uPols#|T5-+@h0D>r`ICKB_mL!2$$)3x??_0;sp zC-UkAE8`PabZBdKypz&zFC=>J`mwM zjxT$-)|Z`e^}h3I9GyEiEV^}MtNN64mvj{51jK_@3w;O-Ik&CEIKtWFL4Wnf*v~bK O{n>7o&H9lS+XDdQA$!39 literal 0 HcmV?d00001 diff --git a/image/mkosi/pki_testing/db.crt b/image/mkosi/pki_testing/db.crt new file mode 100644 index 000000000..53b961aec --- /dev/null +++ b/image/mkosi/pki_testing/db.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID2TCCAsGgAwIBAgIUQZYX6ujSb/QFL2p8BY62ydJ/HEYwDQYJKoZIhvcNAQEL +BQAwgYUxCzAJBgNVBAYTAkRFMRwwGgYDVQQIDBNOb3JkcmhlaW4gV2VzdGZhbGVu +MQ8wDQYDVQQHDAZCb2NodW0xHjAcBgNVBAoMFUVkZ2VsZXNzIFN5c3RlbXMgR21i +SDEnMCUGA1UEAwweQ29uc3RlbGxhdGlvbiBUZXN0aW5nIFBDQSAyMDIyMB4XDTIy +MDkyMzE0MTYwN1oXDTIyMTAyMzE0MTYwN1owgYUxCzAJBgNVBAYTAkRFMRwwGgYD +VQQIDBNOb3JkcmhlaW4gV2VzdGZhbGVuMQ8wDQYDVQQHDAZCb2NodW0xHjAcBgNV +BAoMFUVkZ2VsZXNzIFN5c3RlbXMgR21iSDEnMCUGA1UEAwweQ29uc3RlbGxhdGlv +biBUZXN0aW5nIFBDQSAyMDIyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAx4lZNSnqGy1Dk8hxQHgzzIpCAr2+zPtNpPKdXq8PLIZ1fBERYkVW66JHH5Dl +9pzMl8KaJkkRbv5orxzpL0g9qtM+j/JQl1Ap7S9MAXgysATwyaFWfddLW+ZOi/XS +oOhq1JXp0FFFUBQwP56JtqhUEcgaICi41L9S/XMxQaoZfRQu+9ICVlDMLurqVdI4 +Or5mz7eWUqj34Xl5bpjMOZgbyI1pYN4UxvODKFIYhVTmKZOWA0np4JtI4iCA5Dkd +ckF9uwOyQUyGUs7Atar2tZr2hWK66NxhcdSfj9ltuBHwskJnoJYesWPz0QHz26xO +d+a4WwIKhKfchvv5qVq9KFkRpQIDAQABoz8wPTAdBgNVHQ4EFgQUvCP4FCxcypyU +STwBjhtgqnojgaEwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAYYwDQYJKoZI +hvcNAQELBQADggEBAAhpPWCLVl8FvWZOeZA2iOKmLen/c6W0d9WiB9qvj+mI8QBq +kLhkqkxEcXTpaOjCxJLqLU3LsA828yUdfL0zmxusrJlz+gux+KRlRn1yTsCyWqmx +9rYUXO6IFwZnSUV923uVZ1nkHydwqV9hqIgrKYrppzDXOsm+ugz+NP2lxFNp6q8u +MyMsClaTdfPT+EUucp7g1lPVdtWV4RbWK/v3/rp2l5jzs7F0Roa3zc/+YquwB/AA +ZasNpDInz6RlEzhA/GkXEO5Rssem4a1NBwGrvs9mCIm5sKLaxLUnlM7SLCAeEBdS +qxLwUVTOtnQzWEM04I978V3zfKNPBtl2mvhuXYw= +-----END CERTIFICATE----- diff --git a/image/mkosi/pki_testing/db.esl b/image/mkosi/pki_testing/db.esl new file mode 100644 index 0000000000000000000000000000000000000000..89cd6df2311ed893b0af51e6287dda89a784b731 GIT binary patch literal 4176 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 AUH||9 literal 0 HcmV?d00001 diff --git a/image/mkosi/secure-boot/azure/delete.sh b/image/mkosi/secure-boot/azure/delete.sh new file mode 100755 index 000000000..cb11ad9d4 --- /dev/null +++ b/image/mkosi/secure-boot/azure/delete.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [ -z "${CONFIG_FILE-}" ] && [ -f "${CONFIG_FILE-}" ]; then + . "${CONFIG_FILE}" +fi +POSITIONAL_ARGS=() + +while [[ $# -gt 0 ]]; do + case $1 in + -n|--name) + AZURE_VM_NAME="$2" + shift # past argument + shift # past value + ;; + -*|--*) + echo "Unknown option $1" + exit 1 + ;; + *) + POSITIONAL_ARGS+=("$1") # save positional arg + shift # past argument + ;; + esac +done + +set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters + +AZ_VM_INFO=$(az vm show --name "${AZURE_VM_NAME}" --resource-group "${AZURE_RESOURCE_GROUP_NAME}" -o json) +NIC=$(echo "${AZ_VM_INFO}" | jq -r '.networkProfile.networkInterfaces[0].id') +NIC_INFO=$(az network nic show --ids "${NIC}" -o json) +PUBIP=$(echo "${NIC_INFO}" | jq -r '.ipConfigurations[0].publicIpAddress.id') +NSG=$(echo "${NIC_INFO}" | jq -r '.networkSecurityGroup.id') +SUBNET=$(echo "${NIC_INFO}" | jq -r '.ipConfigurations[0].subnet.id') +VNET=$(echo $SUBNET | sed 's#/subnets/.*##') +DISK=$(echo "${AZ_VM_INFO}" | jq -r '.storageProfile.osDisk.managedDisk.id') + + +delete_vm () { + az vm delete -y --name "${AZURE_VM_NAME}" \ + --resource-group "${AZURE_RESOURCE_GROUP_NAME}" || true +} + +delete_vnet () { + az network vnet delete --ids "${VNET}" || true +} + +delete_subnet () { + az network vnet subnet delete --ids "${SUBNET}" || true +} + +delete_nsg () { + az network nsg delete --ids "${NSG}" || true +} + +delete_pubip () { + az network public-ip delete --ids "${PUBIP}" || true +} + +delete_disk () { + az disk delete -y --ids "${DISK}" || true +} + +delete_nic () { + az network nic delete --ids "${NIC}" || true +} + +delete_vm +delete_disk +delete_nic +delete_nsg +delete_subnet +delete_vnet +delete_pubip diff --git a/image/mkosi/secure-boot/azure/extract_vmgs.sh b/image/mkosi/secure-boot/azure/extract_vmgs.sh new file mode 100755 index 000000000..f5f2089ad --- /dev/null +++ b/image/mkosi/secure-boot/azure/extract_vmgs.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [ -z "${CONFIG_FILE-}" ] && [ -f "${CONFIG_FILE-}" ]; then + . "${CONFIG_FILE}" +fi +AZURE_SUBSCRIPTION=$(az account show --query id -o tsv) +POSITIONAL_ARGS=() + +while [[ $# -gt 0 ]]; do + case $1 in + -n|--name) + AZURE_VM_NAME="$2" + shift # past argument + shift # past value + ;; + -*|--*) + echo "Unknown option $1" + exit 1 + ;; + *) + POSITIONAL_ARGS+=("$1") # save positional arg + shift # past argument + ;; + esac +done + +set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters + +VM_DISK=$(az vm show -g "${AZURE_RESOURCE_GROUP_NAME}" --name "${AZURE_VM_NAME}" --query "storageProfile.osDisk.managedDisk.id" -o tsv) +LOCATION=$(az disk show --ids "${VM_DISK}" --query "location" -o tsv) + +az snapshot create \ + -g "${AZURE_RESOURCE_GROUP_NAME}" \ + --source "${VM_DISK}" \ + --name "${AZURE_SNAPSHOT_NAME}" \ + -l "${LOCATION}" + +# Azure CLI does not implement getSecureVMGuestStateSAS for snapshots yet +# az snapshot grant-access \ +# --duration-in-seconds 3600 \ +# --access-level Read \ +# --name "${AZURE_SNAPSHOT_NAME}" \ +# -g "${AZURE_RESOURCE_GROUP_NAME}" + +BEGIN=$(az rest \ + --method post \ + --url "https://management.azure.com/subscriptions/${AZURE_SUBSCRIPTION}/resourceGroups/${AZURE_RESOURCE_GROUP_NAME}/providers/Microsoft.Compute/snapshots/${AZURE_SNAPSHOT_NAME}/beginGetAccess" \ + --uri-parameters api-version="2021-12-01" \ + --body '{"access": "Read", "durationInSeconds": 3600, "getSecureVMGuestStateSAS": true}' \ + --verbose 2>&1) +ASYNC_OPERATION_URI=$(echo "${BEGIN}" | grep Azure-AsyncOperation | cut -d ' ' -f 7 | tr -d "'") +sleep 10 +ACCESS=$(az rest --method get --url "${ASYNC_OPERATION_URI}") +VMGS_URL=$(echo "${ACCESS}" | jq -r '.properties.output.securityDataAccessSAS') + +curl -L -o "${AZURE_VMGS_FILENAME}" "${VMGS_URL}" + +az snapshot revoke-access \ + --name "${AZURE_SNAPSHOT_NAME}" \ + -g "${AZURE_RESOURCE_GROUP_NAME}" +az snapshot delete \ + --name "${AZURE_SNAPSHOT_NAME}" \ + -g "${AZURE_RESOURCE_GROUP_NAME}" +echo "VMGS saved to ${AZURE_VMGS_FILENAME}" diff --git a/image/mkosi/secure-boot/azure/launch.sh b/image/mkosi/secure-boot/azure/launch.sh new file mode 100755 index 000000000..6ddc84d60 --- /dev/null +++ b/image/mkosi/secure-boot/azure/launch.sh @@ -0,0 +1,101 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [ -z "${CONFIG_FILE-}" ] && [ -f "${CONFIG_FILE-}" ]; then + . "${CONFIG_FILE}" +fi +POSITIONAL_ARGS=() + +while [[ $# -gt 0 ]]; do + case $1 in + -n|--name) + AZURE_VM_NAME="$2" + shift # past argument + shift # past value + ;; + -g|--gallery) + CREATE_FROM_GALLERY=YES + shift # past argument + ;; + -d|--disk) + CREATE_FROM_GALLERY=NO + shift # past argument + ;; + --secure-boot) + AZURE_SECURE_BOOT="$2" + shift # past argument + shift # past value + ;; + --disk-name) + AZURE_DISK_NAME="$2" + shift # past argument + shift # past value + ;; + -*|--*) + echo "Unknown option $1" + exit 1 + ;; + *) + POSITIONAL_ARGS+=("$1") # save positional arg + shift # past argument + ;; + esac +done + +set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters + +if [[ "${AZURE_SECURITY_TYPE}" == "ConfidentialVM" ]]; then + VMSIZE="Standard_DC2as_v5" +elif [[ "${AZURE_SECURITY_TYPE}" == "TrustedLaunch" ]]; then + VMSIZE="standard_D2as_v5" +else + echo "Unknown security type: ${AZURE_SECURITY_TYPE}" + exit 1 +fi + +create_vm_from_disk () { + AZURE_DISK_REFERENCE=$(az disk show --resource-group ${AZURE_RESOURCE_GROUP_NAME} --name ${AZURE_DISK_NAME} --query id -o tsv) + az vm create --name "${AZURE_VM_NAME}" \ + --resource-group "${AZURE_RESOURCE_GROUP_NAME}" \ + -l ${AZURE_REGION} \ + --size "${VMSIZE}" \ + --public-ip-sku Standard \ + --os-type Linux \ + --attach-os-disk "${AZURE_DISK_REFERENCE}" \ + --security-type "${AZURE_SECURITY_TYPE}" \ + --os-disk-security-encryption-type VMGuestStateOnly \ + --enable-vtpm true \ + --enable-secure-boot "${AZURE_SECURE_BOOT}" \ + --boot-diagnostics-storage "" \ + --no-wait +} + +create_vm_from_sig () { + AZURE_IMAGE_REFERENCE=$(az sig image-version show \ + --gallery-image-definition "${AZURE_IMAGE_DEFINITION}" \ + --gallery-image-version "${AZURE_IMAGE_VERSION}" \ + --gallery-name "${AZURE_GALLERY_NAME}" \ + -g "${AZURE_RESOURCE_GROUP_NAME}" \ + --query id -o tsv) + az vm create --name "${AZURE_VM_NAME}" \ + --resource-group "${AZURE_RESOURCE_GROUP_NAME}" \ + -l ${AZURE_REGION} \ + --size "${VMSIZE}" \ + --public-ip-sku Standard \ + --image "${AZURE_IMAGE_REFERENCE}" \ + --security-type "${AZURE_SECURITY_TYPE}" \ + --os-disk-security-encryption-type VMGuestStateOnly \ + --enable-vtpm true \ + --enable-secure-boot "${AZURE_SECURE_BOOT}" \ + --boot-diagnostics-storage "" \ + --no-wait +} + +if [ "$CREATE_FROM_GALLERY" = "YES" ]; then + create_vm_from_sig +else + create_vm_from_disk +fi + +sleep 30 +az vm boot-diagnostics enable --name "${AZURE_VM_NAME}" --resource-group "${AZURE_RESOURCE_GROUP_NAME}" diff --git a/image/mkosi/secure-boot/generate_nvram_vars.sh b/image/mkosi/secure-boot/generate_nvram_vars.sh new file mode 100755 index 000000000..a928cdbca --- /dev/null +++ b/image/mkosi/secure-boot/generate_nvram_vars.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +BASE_DIR=$(realpath "${SCRIPT_DIR}/..") + +# Set to qemu+tcp://localhost:16599/system for dockerized libvirt setup +if [[ -z "${LIBVIRT_SOCK}" ]]; then + LIBVIRT_SOCK=qemu:///system +fi + +libvirt_nvram_gen () { + local image_path="${1}" + if test -f "${BASE_DIR}/image.nvram.template"; then + echo "NVRAM template already generated: $(realpath "--relative-to=$(pwd)" ${BASE_DIR}/image.nvram.template)" + return + fi + if ! test -f "${image_path}"; then + echo "Image \"${image_path}\" does not exist yet. To generate nvram, create disk image first." + return + fi + + OVMF_CODE=/usr/share/OVMF/OVMF_CODE_4M.ms.fd + OVMF_VARS=/usr/share/OVMF/OVMF_VARS_4M.ms.fd + if ! test -f "${OVMF_CODE}"; then + OVMF_CODE=/usr/share/OVMF/OVMF_CODE.secboot.fd + fi + if ! test -f "${OVMF_VARS}"; then + OVMF_VARS=/usr/share/OVMF/OVMF_VARS.secboot.fd + fi + + echo "Using OVMF_CODE: ${OVMF_CODE}" + echo "Using OVMF_VARS: ${OVMF_VARS}" + + # generate nvram file using libvirt + virt-install --name constell-nvram-gen \ + --connect ${LIBVIRT_SOCK} \ + --nonetworks \ + --description 'Constellation' \ + --ram 1024 \ + --vcpus 1 \ + --osinfo detect=on,require=off \ + --disk "${image_path},format=raw" \ + --boot "machine=q35,menu=on,loader=${OVMF_CODE},loader.readonly=yes,loader.type=pflash,nvram.template=${OVMF_VARS},nvram=${BASE_DIR}/image.nvram,loader_secure=yes" \ + --features smm.state=on \ + --noautoconsole + echo -e 'connect using' + echo -e ' \u001b[1mvirsh console constell-nvram-gen\u001b[0m' + echo -e '' + echo -e 'Load db cert with MokManager or enroll full PKI with firmware setup' + echo -e '' + echo -e ' \u001b[1mMokManager\u001b[0m' + echo -e ' For mokmanager, try to boot as usual. You will see this message:' + echo -e ' > "Verification failed: (0x1A) Security Violation"' + echo -e ' Press OK, then ENTER, then "Enroll key from disk"' + echo -e ' Select the following key:' + echo -e ' > \u001b[1m/EFI/loader/keys/auto/db.cer\u001b[0m' + echo -e ' Press Continue, then choose "Yes" to the question "Enroll the key(s)?"' + echo -e ' Choose reboot and continue this script.' + echo -e '' + echo -e ' \u001b[1mFirmware setup\u001b[0m' + echo -e ' For firmware setup, press F2.' + echo -e ' Go to "Device Manager">"Secure Boot Configuration">"Secure Boot Mode"' + echo -e ' Choose "Custom Mode"' + echo -e ' Go to "Custom Securee Boot Options"' + echo -e ' Go to "PK Options">"Enroll PK", Press "Y" if queried, "Enroll PK using File"' + echo -e ' Select the following cert: \u001b[1m/EFI/loader/keys/auto/PK.cer\u001b[0m' + echo -e ' Choose "Commit Changes and Exit"' + echo -e ' Go to "KEK Options">"Enroll KEK", Press "Y" if queried, "Enroll KEK using File"' + echo -e ' Select the following cert: \u001b[1m/EFI/loader/keys/auto/KEK.cer\u001b[0m' + echo -e ' Choose "Commit Changes and Exit"' + echo -e ' Go to "DB Options">"Enroll Signature">"Enroll Signature using File"' + echo -e ' Select the following cert: \u001b[1m/EFI/loader/keys/auto/db.cer\u001b[0m' + echo -e ' Choose "Commit Changes and Exit"' + echo -e ' Repeat the last step for the following certs:' + echo -e ' > \u001b[1m/EFI/loader/keys/auto/MicWinProPCA2011_2011-10-19.crt\u001b[0m' + echo -e ' > \u001b[1m/EFI/loader/keys/auto/MicCorUEFCA2011_2011-06-27.crt\u001b[0m' + echo -e ' Reboot and continue this script.' + echo -e '' + echo -e 'Press ENTER to continue after you followed one of the guides from above.' + read + sudo cp "${BASE_DIR}/image.nvram" "${BASE_DIR}/image.nvram.template" + virsh --connect "${LIBVIRT_SOCK}" destroy --domain constell-nvram-gen + virsh --connect "${LIBVIRT_SOCK}" undefine --nvram constell-nvram-gen + rm -f "${BASE_DIR}/image.nvram" + + echo "NVRAM template generated: $(realpath "--relative-to=$(pwd)" ${BASE_DIR}/image.nvram.template)" +} + +libvirt_nvram_gen $1 diff --git a/image/mkosi/secure-boot/genkeys.sh b/image/mkosi/secure-boot/genkeys.sh new file mode 100755 index 000000000..4a19cf2fb --- /dev/null +++ b/image/mkosi/secure-boot/genkeys.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash + +# This script generates a PKI for secure boot. +# It is based on the example from https://github.com/systemd/systemd/blob/main/man/loader.conf.xml +# This is meant to be used for development purposes only. +# Release images are signed using a different set of keys. +# Set PKI to an empty folder and PKI_SET to "dev". + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +TEMPLATES=${SCRIPT_DIR}/templates +BASE_DIR=$(realpath "${SCRIPT_DIR}/..") +if [ -z "${PKI}" ]; then + PKI=${BASE_DIR}/pki +fi +if [ -z "${PKI_SET}" ]; then + PKI_SET=dev +fi + +gen_pki () { + # Only use for non-production images. + # Use real PKI for production images instead. + count=$(ls -1 ${PKI}/*.{key,crt,cer,esl,auth} 2>/dev/null | wc -l) + if [ $count != 0 ] + then + echo PKI files $(ls -1 $(realpath "--relative-to=$(pwd)" ${PKI})/*.{key,crt,cer,esl,auth}) already exist + return + fi + mkdir -p "${PKI}" + pushd "${PKI}" + + uuid=$(systemd-id128 new --uuid) + for key in PK KEK db; do + openssl req -new -x509 -config "${TEMPLATES}/${PKI_SET}_${key}.conf" -keyout "${key}.key" -out "${key}.crt" -nodes + openssl x509 -outform DER -in "${key}.crt" -out "${key}.cer" + cert-to-efi-sig-list -g "${uuid}" "${key}.crt" "${key}.esl" + done + + for key in MicWinProPCA2011_2011-10-19.crt MicCorUEFCA2011_2011-06-27.crt MicCorKEKCA2011_2011-06-24.crt; do + curl -sL "https://www.microsoft.com/pkiops/certs/${key}" --output "${key}" + sbsiglist --owner 77fa9abd-0359-4d32-bd60-28f4e78f784b --type x509 --output "${key%crt}esl" "${key}" + done + + # Optionally add Microsoft Windows Production CA 2011 (needed to boot into Windows). + cat MicWinProPCA2011_2011-10-19.esl >> db.esl + + # Optionally add Microsoft Corporation UEFI CA 2011 (for firmware drivers / option ROMs + # and third-party boot loaders (including shim). This is highly recommended on real + # hardware as not including this may soft-brick your device (see next paragraph). + cat MicCorUEFCA2011_2011-06-27.esl >> db.esl + + # Optionally add Microsoft Corporation KEK CA 2011. Recommended if either of the + # Microsoft keys is used as the official UEFI revocation database is signed with this + # key. The revocation database can be updated with [fwupdmgr(1)](https://www.freedesktop.org/software/systemd/man/fwupdmgr.html#). + cat MicCorKEKCA2011_2011-06-24.esl >> KEK.esl + + sign-efi-sig-list -c PK.crt -k PK.key PK PK.esl PK.auth + sign-efi-sig-list -c PK.crt -k PK.key KEK KEK.esl KEK.auth + sign-efi-sig-list -c KEK.crt -k KEK.key db db.esl db.auth + + popd +} + +# gen_pki generates a PKI for testing purposes only. +# if keys/certs are already present in the pki folder, they are not regenerated. +gen_pki diff --git a/image/mkosi/secure-boot/signed-shim.sh b/image/mkosi/secure-boot/signed-shim.sh new file mode 100755 index 000000000..af8f25b86 --- /dev/null +++ b/image/mkosi/secure-boot/signed-shim.sh @@ -0,0 +1,45 @@ +#!/bin/env bash +set -euo pipefail +# This script is used to add a signed shim to the image.raw file EFI partition after running `mkosi build`. + +if (( $# != 1 )) +then + echo "Usage: $0 " + exit 1 +fi + +# SOURCE is the URL used to download the signed shim RPM +SOURCE=https://kojipkgs.fedoraproject.org/packages/shim/15.6/2/x86_64/shim-x64-15.6-2.x86_64.rpm +# EXPECTED_SHA512 is the SHA512 checksum of the signed shim RPM +EXPECTED_SHA512=971978bddee95a6a134ef05c4d88cf5df41926e631de863b74ef772307f3e106c82c8f6889c18280d47187986abd774d8671c5be4b85b1b0bb3d1858b65d02cf +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +BASE_DIR=$(realpath "${SCRIPT_DIR}/..") +TMPDIR=$(mktemp -d) + +pushd "${TMPDIR}" + +curl -sL -o shim.rpm "${SOURCE}" +echo "Checking SHA512 checksum of signed shim..." +sha512sum -c <<< "${EXPECTED_SHA512} shim.rpm" +rpm2cpio shim.rpm | cpio -idmv +echo $TMPDIR + +popd + +MOUNTPOINT=$(mktemp -d) +sectoroffset=$(sfdisk -J "${1}" | jq -r '.partitiontable.partitions[0].start') +byteoffset=$((sectoroffset * 512)) +mount -o offset="${byteoffset}" "${1}" "${MOUNTPOINT}" + +mkdir -p "${MOUNTPOINT}/EFI/BOOT/" +cp "${TMPDIR}/boot/efi/EFI/BOOT/BOOTX64.EFI" "${MOUNTPOINT}/EFI/BOOT/" +cp "${TMPDIR}/boot/efi/EFI/fedora/mmx64.efi" "${MOUNTPOINT}/EFI/BOOT/" +cp "${MOUNTPOINT}/EFI/systemd/systemd-bootx64.efi" "${MOUNTPOINT}/EFI/BOOT/grubx64.efi" + +# Remove unused kernel and initramfs from EFI to save space +# We boot from unified kernel image anyway +rm -f "${MOUNTPOINT}"/*/*/{linux,initrd} + +umount "${MOUNTPOINT}" +rm -rf ${MOUNTPOINT} +rm -rf "${TMPDIR}" diff --git a/image/mkosi/secure-boot/templates/dev_KEK.conf b/image/mkosi/secure-boot/templates/dev_KEK.conf new file mode 100644 index 000000000..4ec425d77 --- /dev/null +++ b/image/mkosi/secure-boot/templates/dev_KEK.conf @@ -0,0 +1,20 @@ + [ req ] + default_bits = 2048 + distinguished_name = req_distinguished_name + x509_extensions = v3_req + req_extensions = v3_req + prompt = no + + dirstring_type = nobmp + + [ req_distinguished_name ] + C = DE + ST = Nordrhein Westfalen + L = Bochum + O = Edgeless Systems GmbH + CN = Constellation Development KEK CA 2022 + + [ v3_req ] + subjectKeyIdentifier = hash + basicConstraints = critical,CA:true + keyUsage = digitalSignature,keyCertSign,cRLSign diff --git a/image/mkosi/secure-boot/templates/dev_PK.conf b/image/mkosi/secure-boot/templates/dev_PK.conf new file mode 100644 index 000000000..be5d0699d --- /dev/null +++ b/image/mkosi/secure-boot/templates/dev_PK.conf @@ -0,0 +1,20 @@ + [ req ] + default_bits = 2048 + distinguished_name = req_distinguished_name + x509_extensions = v3_req + req_extensions = v3_req + prompt = no + + dirstring_type = nobmp + + [ req_distinguished_name ] + C = DE + ST = Nordrhein Westfalen + L = Bochum + O = Edgeless Systems GmbH + CN = Constellation Development UEFI CA 2022 + + [ v3_req ] + subjectKeyIdentifier = hash + basicConstraints = critical,CA:true + keyUsage = digitalSignature,keyCertSign,cRLSign diff --git a/image/mkosi/secure-boot/templates/dev_db.conf b/image/mkosi/secure-boot/templates/dev_db.conf new file mode 100644 index 000000000..6f2b6fdfb --- /dev/null +++ b/image/mkosi/secure-boot/templates/dev_db.conf @@ -0,0 +1,20 @@ + [ req ] + default_bits = 2048 + distinguished_name = req_distinguished_name + x509_extensions = v3_req + req_extensions = v3_req + prompt = no + + dirstring_type = nobmp + + [ req_distinguished_name ] + C = DE + ST = Nordrhein Westfalen + L = Bochum + O = Edgeless Systems GmbH + CN = Constellation Development PCA 2022 + + [ v3_req ] + subjectKeyIdentifier = hash + basicConstraints = critical,CA:true + keyUsage = digitalSignature,keyCertSign,cRLSign diff --git a/image/mkosi/secure-boot/templates/prod_KEK.conf b/image/mkosi/secure-boot/templates/prod_KEK.conf new file mode 100644 index 000000000..a9e7d3f77 --- /dev/null +++ b/image/mkosi/secure-boot/templates/prod_KEK.conf @@ -0,0 +1,20 @@ + [ req ] + default_bits = 2048 + distinguished_name = req_distinguished_name + x509_extensions = v3_req + req_extensions = v3_req + prompt = no + + dirstring_type = nobmp + + [ req_distinguished_name ] + C = DE + ST = Nordrhein Westfalen + L = Bochum + O = Edgeless Systems GmbH + CN = Constellation KEK CA 2022 + + [ v3_req ] + subjectKeyIdentifier = hash + basicConstraints = critical,CA:true + keyUsage = digitalSignature,keyCertSign,cRLSign diff --git a/image/mkosi/secure-boot/templates/prod_PK.conf b/image/mkosi/secure-boot/templates/prod_PK.conf new file mode 100644 index 000000000..755bf14e4 --- /dev/null +++ b/image/mkosi/secure-boot/templates/prod_PK.conf @@ -0,0 +1,20 @@ + [ req ] + default_bits = 2048 + distinguished_name = req_distinguished_name + x509_extensions = v3_req + req_extensions = v3_req + prompt = no + + dirstring_type = nobmp + + [ req_distinguished_name ] + C = DE + ST = Nordrhein Westfalen + L = Bochum + O = Edgeless Systems GmbH + CN = Constellation UEFI CA 2022 + + [ v3_req ] + subjectKeyIdentifier = hash + basicConstraints = critical,CA:true + keyUsage = digitalSignature,keyCertSign,cRLSign diff --git a/image/mkosi/secure-boot/templates/prod_db.conf b/image/mkosi/secure-boot/templates/prod_db.conf new file mode 100644 index 000000000..99fa7ec48 --- /dev/null +++ b/image/mkosi/secure-boot/templates/prod_db.conf @@ -0,0 +1,20 @@ + [ req ] + default_bits = 2048 + distinguished_name = req_distinguished_name + x509_extensions = v3_req + req_extensions = v3_req + prompt = no + + dirstring_type = nobmp + + [ req_distinguished_name ] + C = DE + ST = Nordrhein Westfalen + L = Bochum + O = Edgeless Systems GmbH + CN = Constellation Production PCA 2022 + + [ v3_req ] + subjectKeyIdentifier = hash + basicConstraints = critical,CA:true + keyUsage = digitalSignature,keyCertSign,cRLSign diff --git a/image/mkosi/secure-boot/templates/testing_KEK.conf b/image/mkosi/secure-boot/templates/testing_KEK.conf new file mode 100644 index 000000000..94efac5ee --- /dev/null +++ b/image/mkosi/secure-boot/templates/testing_KEK.conf @@ -0,0 +1,20 @@ + [ req ] + default_bits = 2048 + distinguished_name = req_distinguished_name + x509_extensions = v3_req + req_extensions = v3_req + prompt = no + + dirstring_type = nobmp + + [ req_distinguished_name ] + C = DE + ST = Nordrhein Westfalen + L = Bochum + O = Edgeless Systems GmbH + CN = Constellation Testing KEK CA 2022 + + [ v3_req ] + subjectKeyIdentifier = hash + basicConstraints = critical,CA:true + keyUsage = digitalSignature,keyCertSign,cRLSign diff --git a/image/mkosi/secure-boot/templates/testing_PK.conf b/image/mkosi/secure-boot/templates/testing_PK.conf new file mode 100644 index 000000000..dd6e60469 --- /dev/null +++ b/image/mkosi/secure-boot/templates/testing_PK.conf @@ -0,0 +1,20 @@ + [ req ] + default_bits = 2048 + distinguished_name = req_distinguished_name + x509_extensions = v3_req + req_extensions = v3_req + prompt = no + + dirstring_type = nobmp + + [ req_distinguished_name ] + C = DE + ST = Nordrhein Westfalen + L = Bochum + O = Edgeless Systems GmbH + CN = Constellation Testing UEFI CA 2022 + + [ v3_req ] + subjectKeyIdentifier = hash + basicConstraints = critical,CA:true + keyUsage = digitalSignature,keyCertSign,cRLSign diff --git a/image/mkosi/secure-boot/templates/testing_db.conf b/image/mkosi/secure-boot/templates/testing_db.conf new file mode 100644 index 000000000..a9bf43a09 --- /dev/null +++ b/image/mkosi/secure-boot/templates/testing_db.conf @@ -0,0 +1,20 @@ + [ req ] + default_bits = 2048 + distinguished_name = req_distinguished_name + x509_extensions = v3_req + req_extensions = v3_req + prompt = no + + dirstring_type = nobmp + + [ req_distinguished_name ] + C = DE + ST = Nordrhein Westfalen + L = Bochum + O = Edgeless Systems GmbH + CN = Constellation Testing PCA 2022 + + [ v3_req ] + subjectKeyIdentifier = hash + basicConstraints = critical,CA:true + keyUsage = digitalSignature,keyCertSign,cRLSign diff --git a/image/mkosi/upload/pack.sh b/image/mkosi/upload/pack.sh new file mode 100755 index 000000000..189febf16 --- /dev/null +++ b/image/mkosi/upload/pack.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Show progress on pipes if `pv` is installed +# Otherwise use plain cat +if ! command -v pv &> /dev/null +then + PV="cat" +else + PV="pv" +fi + +pack () { + local cloudprovider=$1 + local unpacked_image=$2 + local packed_image=$3 + local unpacked_image_dir + unpacked_image_dir=$(mktemp -d) + local unpacked_image_filename + unpacked_image_filename=disk.raw + local tmp_tar_file + tmp_tar_file=$(mktemp -t verity.XXXXXX.tar) + cp ${unpacked_image} "${unpacked_image_dir}/${unpacked_image_filename}" + + case $cloudprovider in + + gcp) + echo "📥 Packing GCP image..." + tar --owner=0 --group=0 -C "${unpacked_image_dir}" -Sch --format=oldgnu -f "${tmp_tar_file}" "${unpacked_image_filename}" + "${PV}" "${tmp_tar_file}" | pigz -9c > "${packed_image}" + rm "${tmp_tar_file}" + echo " Repacked image stored in ${packed_image}" + ;; + + azure) + echo "📥 Packing Azure image..." + truncate -s %1MiB "${unpacked_image_dir}/${unpacked_image_filename}" + qemu-img convert -p -f raw -O vpc -o force_size,subformat=fixed "${unpacked_image_dir}/${unpacked_image_filename}" "$packed_image" + echo " Repacked image stored in ${packed_image}" + ;; + + *) + echo "unknown cloud provider" + exit 1 + ;; + esac + + rm -r ${unpacked_image_dir} + +} + +if [ $# -ne 3 ]; then + echo "Usage: $0 " + exit 1 +fi + +pack "${1}" "${2}" "${3}" diff --git a/image/mkosi/upload/upload_azure.sh b/image/mkosi/upload/upload_azure.sh new file mode 100755 index 000000000..8d0e7f912 --- /dev/null +++ b/image/mkosi/upload/upload_azure.sh @@ -0,0 +1,190 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [ -z "${CONFIG_FILE-}" ] && [ -f "${CONFIG_FILE-}" ]; then + . "${CONFIG_FILE}" +fi + + +CREATE_SIG_VERSION=NO +POSITIONAL_ARGS=() + +while [[ $# -gt 0 ]]; do + case $1 in + -g|--gallery) + CREATE_SIG_VERSION=YES + shift # past argument + ;; + --disk-name) + AZURE_DISK_NAME="$2" + shift # past argument + shift # past value + ;; + -*|--*) + echo "Unknown option $1" + exit 1 + ;; + *) + POSITIONAL_ARGS+=("$1") # save positional arg + shift # past argument + ;; + esac +done + +set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters + +if [[ "${AZURE_SECURITY_TYPE}" == "ConfidentialVM" ]]; then + AZURE_DISK_SECURITY_TYPE=ConfidentialVM_VMGuestStateOnlyEncryptedWithPlatformKey + AZURE_SIG_VERSION_ENCRYPTION_TYPE=EncryptedVMGuestStateOnlyWithPmk +elif [[ "${AZURE_SECURITY_TYPE}" == "ConfidentialVMSupported" ]]; then + AZURE_DISK_SECURITY_TYPE="" +elif [[ "${AZURE_SECURITY_TYPE}" == "TrustedLaunch" ]]; then + AZURE_DISK_SECURITY_TYPE=TrustedLaunch +else + echo "Unknown security type: ${AZURE_SECURITY_TYPE}" + exit 1 +fi + +AZURE_CVM_ENCRYPTION_ARGS="" +if [[ -n "${AZURE_SIG_VERSION_ENCRYPTION_TYPE-}" ]]; then + AZURE_CVM_ENCRYPTION_ARGS=" --target-region-cvm-encryption " + for region in ${AZURE_REPLICATION_REGIONS}; do + AZURE_CVM_ENCRYPTION_ARGS=" ${AZURE_CVM_ENCRYPTION_ARGS} ${AZURE_SIG_VERSION_ENCRYPTION_TYPE}, " + done +fi +echo "Replicating image in ${AZURE_REPLICATION_REGIONS}" + +AZURE_VMGS_PATH=$1 +if [[ -z "${AZURE_VMGS_PATH}" ]] && [[ "${AZURE_SECURITY_TYPE}" == "ConfidentialVM" ]]; then + echo "No VMGS path provided - using default ConfidentialVM VMGS" + AZURE_VMGS_PATH="${BLOBS_DIR}/cvm-vmgs.vhd" +elif [[ -z "${AZURE_VMGS_PATH}" ]] && [[ "${AZURE_SECURITY_TYPE}" == "TrustedLaunch" ]]; then + echo "No VMGS path provided - using default TrsutedLaunch VMGS" + AZURE_VMGS_PATH="${BLOBS_DIR}/trusted-launch-vmgs.vhd" +fi + +SIZE=$(wc -c "${AZURE_IMAGE_PATH}" | cut -d " " -f1) + +create_disk_with_vmgs () { + az disk create \ + -n "${AZURE_DISK_NAME}" \ + -g "${AZURE_RESOURCE_GROUP_NAME}" \ + -l "${AZURE_REGION}" \ + --hyper-v-generation V2 \ + --os-type Linux \ + --upload-size-bytes "${SIZE}" \ + --sku standard_lrs \ + --upload-type UploadWithSecurityData \ + --security-type "${AZURE_DISK_SECURITY_TYPE}" + az disk wait --created -n "${AZURE_DISK_NAME}" -g "${AZURE_RESOURCE_GROUP_NAME}" + az disk list --output table --query "[?name == '${AZURE_DISK_NAME}' && resourceGroup == '${AZURE_RESOURCE_GROUP_NAME^^}']" + DISK_SAS=$(az disk grant-access -n ${AZURE_DISK_NAME} -g ${AZURE_RESOURCE_GROUP_NAME} \ + --access-level Write --duration-in-seconds 86400 \ + ${AZURE_VMGS_PATH+"--secure-vm-guest-state-sas"}) + azcopy copy "${AZURE_IMAGE_PATH}" \ + "$(echo $DISK_SAS | jq -r .accessSas)" \ + --blob-type PageBlob + if [[ -z "${AZURE_VMGS_PATH}" ]]; then + echo "No VMGS path provided - skipping VMGS upload" + else + azcopy copy "${AZURE_VMGS_PATH}" \ + "$(echo $DISK_SAS | jq -r .securityDataAccessSas)" \ + --blob-type PageBlob + fi + az disk revoke-access -n "${AZURE_DISK_NAME}" -g "${AZURE_RESOURCE_GROUP_NAME}" +} + +create_disk_without_vmgs () { + az disk create \ + -n "${AZURE_DISK_NAME}" \ + -g "${AZURE_RESOURCE_GROUP_NAME}" \ + -l "${AZURE_REGION}" \ + --hyper-v-generation V2 \ + --os-type Linux \ + --upload-size-bytes "${SIZE}" \ + --sku standard_lrs \ + --upload-type Upload + az disk wait --created -n "${AZURE_DISK_NAME}" -g "${AZURE_RESOURCE_GROUP_NAME}" + az disk list --output table --query "[?name == '${AZURE_DISK_NAME}' && resourceGroup == '${AZURE_RESOURCE_GROUP_NAME^^}']" + DISK_SAS=$(az disk grant-access -n ${AZURE_DISK_NAME} -g ${AZURE_RESOURCE_GROUP_NAME} \ + --access-level Write --duration-in-seconds 86400) + azcopy copy "${AZURE_IMAGE_PATH}" \ + "$(echo $DISK_SAS | jq -r .accessSas)" \ + --blob-type PageBlob + az disk revoke-access -n "${AZURE_DISK_NAME}" -g "${AZURE_RESOURCE_GROUP_NAME}" +} + +create_disk () { + if [[ -z "${AZURE_VMGS_PATH}" ]]; then + create_disk_without_vmgs + else + create_disk_with_vmgs + fi +} + +delete_disk () { + az disk delete -y -n "${AZURE_DISK_NAME}" -g "${AZURE_RESOURCE_GROUP_NAME}" +} + +create_image () { + if [[ -n "${AZURE_VMGS_PATH}" ]]; then + return + fi + az image create \ + --resource-group ${AZURE_RESOURCE_GROUP_NAME} \ + -l ${AZURE_REGION} \ + -n ${AZURE_DISK_NAME} \ + --hyper-v-generation V2 \ + --os-type Linux \ + --source "$(az disk list --query "[?name == '${AZURE_DISK_NAME}' && resourceGroup == '${AZURE_RESOURCE_GROUP_NAME^^}'] | [0].id" --output tsv)" +} + +delete_image () { + if [[ -n "${AZURE_VMGS_PATH}" ]]; then + return + fi + az image delete -n "${AZURE_DISK_NAME}" -g "${AZURE_RESOURCE_GROUP_NAME}" +} + +create_sig_version () { + if [[ -n "${AZURE_VMGS_PATH}" ]]; then + local DISK="$(az disk list --query "[?name == '${AZURE_DISK_NAME}' && resourceGroup == '${AZURE_RESOURCE_GROUP_NAME^^}'] | [0].id" --output tsv)" + local SOURCE="--os-snapshot ${DISK}" + else + local IMAGE="$(az image list --query "[?name == '${AZURE_DISK_NAME}' && resourceGroup == '${AZURE_RESOURCE_GROUP_NAME^^}'] | [0].id" --output tsv)" + local SOURCE="--managed-image ${IMAGE}" + fi + az sig create -l "${AZURE_REGION}" --gallery-name "${AZURE_GALLERY_NAME}" --resource-group "${AZURE_RESOURCE_GROUP_NAME}" || true + az sig image-definition create \ + --resource-group "${AZURE_RESOURCE_GROUP_NAME}" \ + -l "${AZURE_REGION}" \ + --gallery-name "${AZURE_GALLERY_NAME}" \ + --gallery-image-definition "${AZURE_IMAGE_DEFINITION}" \ + --publisher "${AZURE_PUBLISHER}" \ + --offer "${AZURE_IMAGE_OFFER}" \ + --sku "${AZURE_SKU}" \ + --os-type Linux \ + --os-state generalized \ + --hyper-v-generation V2 \ + --features SecurityType="${AZURE_SECURITY_TYPE}" || true + az sig image-version create \ + --resource-group "${AZURE_RESOURCE_GROUP_NAME}" \ + -l "${AZURE_REGION}" \ + --gallery-name "${AZURE_GALLERY_NAME}" \ + --gallery-image-definition "${AZURE_IMAGE_DEFINITION}" \ + --gallery-image-version "${AZURE_IMAGE_VERSION}" \ + --target-regions ${AZURE_REPLICATION_REGIONS} \ + ${AZURE_CVM_ENCRYPTION_ARGS} \ + --replica-count 1 \ + --replication-mode Full \ + ${SOURCE} +} + +create_disk + +if [ "$CREATE_SIG_VERSION" = "YES" ]; then + create_image + create_sig_version + delete_image + delete_disk +fi diff --git a/image/mkosi/upload/upload_gcp.sh b/image/mkosi/upload/upload_gcp.sh new file mode 100755 index 000000000..e6ecf398f --- /dev/null +++ b/image/mkosi/upload/upload_gcp.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [ -z "${CONFIG_FILE-}" ] && [ -f "${CONFIG_FILE-}" ]; then + . "${CONFIG_FILE}" +fi + +PK_FILE=${PKI}/PK.cer +KEK_FILES=${PKI}/KEK.cer,${PKI}/MicCorKEKCA2011_2011-06-24.crt +DB_FILES=${PKI}/db.cer,${PKI}/MicWinProPCA2011_2011-10-19.crt,${PKI}/MicCorUEFCA2011_2011-06-27.crt + +gsutil mb -l "${GCP_REGION}" "gs://${GCP_BUCKET}" || true +gsutil pap set enforced "gs://${GCP_BUCKET}" || true +gsutil cp "${GCP_IMAGE_PATH}" "gs://${GCP_BUCKET}/${GCP_IMAGE_FILENAME}" +gcloud compute images create "${GCP_IMAGE_NAME}" \ + "--family=${GCP_IMAGE_FAMILY}" \ + "--source-uri=gs://${GCP_BUCKET}/${GCP_IMAGE_FILENAME}" \ + "--guest-os-features=GVNIC,SEV_CAPABLE,VIRTIO_SCSI_MULTIQUEUE,UEFI_COMPATIBLE" \ + "--platform-key-file=${PK_FILE}" \ + "--key-exchange-key-file=${KEK_FILES}" \ + "--signature-database-file=${DB_FILES}" \ + "--project=${GCP_PROJECT}" +gcloud compute images add-iam-policy-binding "${GCP_IMAGE_NAME}" \ + "--project=${GCP_PROJECT}" \ + --member='allAuthenticatedUsers' \ + --role='roles/compute.imageUser' +gsutil rm "gs://${GCP_BUCKET}/${GCP_IMAGE_FILENAME}" diff --git a/internal/config/config.go b/internal/config/config.go index 844dd5b5f..e1719c55c 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -142,6 +142,9 @@ type AzureConfig struct { // description: | // Use Confidential VMs. If set to false, Trusted Launch VMs are used instead. See: https://docs.microsoft.com/en-us/azure/confidential-computing/confidential-vm-overview ConfidentialVM *bool `yaml:"confidentialVM" validate:"required"` + // description: | + // Enable secure boot for VMs. If enabled, the OS image has to include a virtual machine guest state (VMGS) blob. + SecureBoot *bool `yaml:"secureBoot" validate:"required"` } // GCPConfig are GCP specific configuration values used by the CLI. @@ -203,6 +206,12 @@ type QEMUConfig struct { // description: | // List of values that should be enforced to be equal to the ones from the measurement list. Any non-equal values not in this list will only result in a warning. EnforcedMeasurements []uint32 `yaml:"enforcedMeasurements"` + // description: | + // NVRAM template to be used for secure boot. Can be sentinel value "production", "testing" or a path to a custom NVRAM template + NVRAM string `yaml:"nvram" validate:"required"` + // description: | + // Path to the OVMF firmware. Leave empty for auto selection. + Firmware string `yaml:"firmware"` } // Default returns a struct with the default config. @@ -226,6 +235,7 @@ func Default() *Config { IDKeyDigest: "57486a447ec0f1958002a22a06b7673b9fd27d11e1c6527498056054c5fa92d23c50f9de44072760fe2b6fb89740b696", EnforceIDKeyDigest: func() *bool { b := true; return &b }(), ConfidentialVM: func() *bool { b := true; return &b }(), + SecureBoot: func() *bool { b := false; return &b }(), }, GCP: &GCPConfig{ Project: "", @@ -246,7 +256,8 @@ func Default() *Config { LibvirtURI: "", LibvirtContainerImage: versions.LibvirtImage, Measurements: copyPCRMap(qemuPCRs), - EnforcedMeasurements: []uint32{11, 12}, + EnforcedMeasurements: []uint32{4, 8, 9, 11, 12, 13, 15}, + NVRAM: "testing", }, }, KubernetesVersion: string(versions.Default), diff --git a/internal/config/config_doc.go b/internal/config/config_doc.go index c180bd7fe..4dfeebca0 100644 --- a/internal/config/config_doc.go +++ b/internal/config/config_doc.go @@ -146,7 +146,7 @@ func init() { FieldName: "azure", }, } - AzureConfigDoc.Fields = make([]encoder.Doc, 15) + AzureConfigDoc.Fields = make([]encoder.Doc, 16) AzureConfigDoc.Fields[0].Name = "subscription" AzureConfigDoc.Fields[0].Type = "string" AzureConfigDoc.Fields[0].Note = "" @@ -222,6 +222,11 @@ func init() { AzureConfigDoc.Fields[14].Note = "" AzureConfigDoc.Fields[14].Description = "Use Confidential VMs. If set to false, Trusted Launch VMs are used instead. See: https://docs.microsoft.com/en-us/azure/confidential-computing/confidential-vm-overview" AzureConfigDoc.Fields[14].Comments[encoder.LineComment] = "Use Confidential VMs. If set to false, Trusted Launch VMs are used instead. See: https://docs.microsoft.com/en-us/azure/confidential-computing/confidential-vm-overview" + AzureConfigDoc.Fields[15].Name = "secureBoot" + AzureConfigDoc.Fields[15].Type = "bool" + AzureConfigDoc.Fields[15].Note = "" + AzureConfigDoc.Fields[15].Description = "Enable secure boot for VMs. If enabled, the OS image has to include a virtual machine guest state (VMGS) blob." + AzureConfigDoc.Fields[15].Comments[encoder.LineComment] = "Enable secure boot for VMs. If enabled, the OS image has to include a virtual machine guest state (VMGS) blob." GCPConfigDoc.Type = "GCPConfig" GCPConfigDoc.Comments[encoder.LineComment] = "GCPConfig are GCP specific configuration values used by the CLI." @@ -288,7 +293,7 @@ func init() { FieldName: "qemu", }, } - QEMUConfigDoc.Fields = make([]encoder.Doc, 9) + QEMUConfigDoc.Fields = make([]encoder.Doc, 11) QEMUConfigDoc.Fields[0].Name = "image" QEMUConfigDoc.Fields[0].Type = "string" QEMUConfigDoc.Fields[0].Note = "" @@ -334,6 +339,16 @@ func init() { QEMUConfigDoc.Fields[8].Note = "" QEMUConfigDoc.Fields[8].Description = "List of values that should be enforced to be equal to the ones from the measurement list. Any non-equal values not in this list will only result in a warning." QEMUConfigDoc.Fields[8].Comments[encoder.LineComment] = "List of values that should be enforced to be equal to the ones from the measurement list. Any non-equal values not in this list will only result in a warning." + QEMUConfigDoc.Fields[9].Name = "nvram" + QEMUConfigDoc.Fields[9].Type = "string" + QEMUConfigDoc.Fields[9].Note = "" + QEMUConfigDoc.Fields[9].Description = "NVRAM template to be used for secure boot. Can be sentinel value \"production\", \"testing\" or a path to a custom NVRAM template" + QEMUConfigDoc.Fields[9].Comments[encoder.LineComment] = "NVRAM template to be used for secure boot. Can be sentinel value \"production\", \"testing\" or a path to a custom NVRAM template" + QEMUConfigDoc.Fields[10].Name = "firmware" + QEMUConfigDoc.Fields[10].Type = "string" + QEMUConfigDoc.Fields[10].Note = "" + QEMUConfigDoc.Fields[10].Description = "Path to the OVMF firmware. Leave empty for auto selection." + QEMUConfigDoc.Fields[10].Comments[encoder.LineComment] = "Path to the OVMF firmware. Leave empty for auto selection." } func (_ Config) Doc() *encoder.Doc {