From eb0e87b886864f7d95f41a0a3a259453c520a908 Mon Sep 17 00:00:00 2001 From: Magnus Kulke Date: Thu, 5 Dec 2024 12:54:26 +0100 Subject: [PATCH] podvm: truncate initdata digest to 32 bytes on az According to initdata spec the digest needs to be truncated/padded according to the requirements of the TEE. for az tpm we use the sha256 bank of TPM for initdata. This will fix a bug when a initdata body with alg=sha384+ was used and the PCR8 value in the TEE evidence will not be extended, since you cannot extend sha256 w/ a digest that's bigger than 32 bytes. An e2e test for azure was added to assert this behaviour. Signed-off-by: Magnus Kulke --- .github/workflows/azure-e2e-test.yml | 2 +- .../10-override.conf | 7 +-- .../10-override.conf | 5 ++- src/cloud-api-adaptor/test/e2e/azure_test.go | 43 +++++++++++++++++++ 4 files changed, 51 insertions(+), 6 deletions(-) diff --git a/.github/workflows/azure-e2e-test.yml b/.github/workflows/azure-e2e-test.yml index 1811df0a6..11f114ebb 100644 --- a/.github/workflows/azure-e2e-test.yml +++ b/.github/workflows/azure-e2e-test.yml @@ -241,7 +241,7 @@ jobs: az aks get-credentials \ --resource-group ${{ secrets.AZURE_RESOURCE_GROUP }} \ --name "${CLUSTER_NAME}" - make test-e2e RUN_TESTS="^Test\(CreateSimplePodAzure\|RemoteAttestation\)$" + make test-e2e RUN_TESTS="^Test\(CreateSimplePodAzure\|RemoteAttestation\|InitDataMeasurement\)$" cleanup: runs-on: ubuntu-24.04 diff --git a/src/cloud-api-adaptor/podvm-mkosi/mkosi.skeleton/usr/lib/systemd/system/afterburn-checkin.service.d/10-override.conf b/src/cloud-api-adaptor/podvm-mkosi/mkosi.skeleton/usr/lib/systemd/system/afterburn-checkin.service.d/10-override.conf index 3876b8529..082333d36 100644 --- a/src/cloud-api-adaptor/podvm-mkosi/mkosi.skeleton/usr/lib/systemd/system/afterburn-checkin.service.d/10-override.conf +++ b/src/cloud-api-adaptor/podvm-mkosi/mkosi.skeleton/usr/lib/systemd/system/afterburn-checkin.service.d/10-override.conf @@ -1,8 +1,9 @@ -# As our image is generic, we don't set the cloud provider on the kernel command line. -# Instead, we always run the unit, even if it is only needed on Azure right now. +# We don't set the cloud provider on the kernel command line. The unit will only +# run on azure [Unit] ConditionKernelCommandLine= +ConditionVirtualization=microsoft [Service] ExecStart= -ExecStart=-/usr/bin/afterburn --provider=azure --check-in +ExecStart=/usr/bin/afterburn --provider=azure --check-in diff --git a/src/cloud-api-adaptor/podvm-mkosi/mkosi.skeleton/usr/lib/systemd/system/process-user-data.service.d/10-override.conf b/src/cloud-api-adaptor/podvm-mkosi/mkosi.skeleton/usr/lib/systemd/system/process-user-data.service.d/10-override.conf index a2dd6822f..bc75230cc 100644 --- a/src/cloud-api-adaptor/podvm-mkosi/mkosi.skeleton/usr/lib/systemd/system/process-user-data.service.d/10-override.conf +++ b/src/cloud-api-adaptor/podvm-mkosi/mkosi.skeleton/usr/lib/systemd/system/process-user-data.service.d/10-override.conf @@ -1,5 +1,6 @@ [Service] +# mount config disk if available ExecStartPre=-/bin/mkdir -p /run/media/cidata ExecStartPre=-/bin/mount -t iso9660 -o ro /dev/disk/by-label/cidata /run/media/cidata -ExecStartPost=-/bin/bash -c 'tpm2_pcrextend 8:sha256=$(cat /run/peerpod/initdata.digest)' -ExecStartPost=-/bin/bash -c 'tpm2_pcrextend 8:sha384=$(cat /run/peerpod/initdata.digest)' +# The digest is a string in hex representation, we truncate it to a 32 bytes hex string +ExecStartPost=-/bin/bash -c 'tpm2_pcrextend 8:sha256=$(head -c64 /run/peerpod/initdata.digest)' diff --git a/src/cloud-api-adaptor/test/e2e/azure_test.go b/src/cloud-api-adaptor/test/e2e/azure_test.go index fdf0b1f26..f5fe51d0a 100644 --- a/src/cloud-api-adaptor/test/e2e/azure_test.go +++ b/src/cloud-api-adaptor/test/e2e/azure_test.go @@ -7,7 +7,12 @@ package e2e import ( "bytes" + "crypto/sha256" + "crypto/sha512" + b64 "encoding/base64" + "fmt" "os" + "strconv" "strings" "testing" @@ -178,3 +183,41 @@ func TestAzureImageDecryption(t *testing.T) { DoTestImageDecryption(t, testEnv, assert, keyBrokerService) } + +// This test is to verify that the initdata is measured correctly. The digest algorith in the initdata fixture +// is sha384. The initdata spec requires the digest to be truncated/padded to the TEE's requirement. In this case, +// the az tpm attester requires the digest to be sha256 and is hence truncated +func TestInitDataMeasurement(t *testing.T) { + kbsEndpoint := "http://some.endpoint" + initdata := fmt.Sprintf(testInitdata, kbsEndpoint, kbsEndpoint, kbsEndpoint) + + digest := sha512.Sum384([]byte(initdata)) + truncatedDigest := digest[:32] + zeroes := bytes.Repeat([]byte{0x00}, 32) + + hasher := sha256.New() + hasher.Write(zeroes) + hasher.Write(truncatedDigest) + msmt := hasher.Sum(nil) + + name := "initdata-msmt" + image := "quay.io/confidential-containers/test-images:curl-jq" + + // truncate the measurement to 32 bytes + strValues := make([]string, len(msmt)) + for i, v := range msmt { + strValues[i] = strconv.Itoa(int(v)) + } + // json array string + msStr := "[" + strings.Join(strValues, ",") + "]" + + shCmd := "curl -s \"http://127.0.0.1:8006/aa/evidence?runtime_data=test\" | jq -c '(.quote // .tpm_quote).pcrs[8]'" + cmd := []string{"sh", "-c", shCmd} + + b64Data := b64.StdEncoding.EncodeToString([]byte(initdata)) + annotations := map[string]string{ + "io.katacontainers.config.runtime.cc_init_data": b64Data, + } + job := NewJob(E2eNamespace, name, 0, image, WithJobCommand(cmd), WithJobAnnotations(annotations)) + NewTestCase(t, testEnv, "InitDataMeasurement", assert, "InitData measured correctly").WithJob(job).WithExpectedPodLogString(msStr).Run() +}