From 1b0ec8f0588c82b0bb70a7e0a8eeeec86fec53b4 Mon Sep 17 00:00:00 2001 From: Simon Ott Date: Fri, 28 Jun 2024 11:02:59 +0000 Subject: [PATCH 1/6] treewide: minor log output changes Signed-off-by: Simon Ott --- cmc/sgx.go | 1 - cmc/snp.go | 1 - cmc/sw.go | 1 - cmc/tpm.go | 1 - testtool/tls.go | 3 ++- 5 files changed, 2 insertions(+), 5 deletions(-) diff --git a/cmc/sgx.go b/cmc/sgx.go index adebbef2..acce2a9a 100644 --- a/cmc/sgx.go +++ b/cmc/sgx.go @@ -20,6 +20,5 @@ package cmc import "github.com/Fraunhofer-AISEC/cmc/sgxdriver" func init() { - log.Info("Adding SGX driver to supported drivers") drivers["sgx"] = &sgxdriver.Sgx{} } diff --git a/cmc/snp.go b/cmc/snp.go index 86c0dd02..5d91c032 100644 --- a/cmc/snp.go +++ b/cmc/snp.go @@ -20,6 +20,5 @@ package cmc import "github.com/Fraunhofer-AISEC/cmc/snpdriver" func init() { - log.Info("Adding SNP driver to supported drivers") drivers["snp"] = &snpdriver.Snp{} } diff --git a/cmc/sw.go b/cmc/sw.go index 09abf310..023ed9c2 100644 --- a/cmc/sw.go +++ b/cmc/sw.go @@ -20,6 +20,5 @@ package cmc import "github.com/Fraunhofer-AISEC/cmc/swdriver" func init() { - log.Info("Adding SW driver to supported drivers") drivers["sw"] = &swdriver.Sw{} } diff --git a/cmc/tpm.go b/cmc/tpm.go index 41bf13aa..31659a8e 100644 --- a/cmc/tpm.go +++ b/cmc/tpm.go @@ -20,6 +20,5 @@ package cmc import "github.com/Fraunhofer-AISEC/cmc/tpmdriver" func init() { - log.Info("Adding TPM driver to supported drivers") drivers["tpm"] = &tpmdriver.Tpm{} } diff --git a/testtool/tls.go b/testtool/tls.go index 0dfdca9e..d76b037c 100644 --- a/testtool/tls.go +++ b/testtool/tls.go @@ -235,7 +235,8 @@ func handleConnection(conn net.Conn) { msg, err := r.ReadString('\n') if err != nil { - log.Errorf("Failed to read: %v", err) + log.Warnf("Failed to read: %v", err) + return } log.Infof("Received from peer: %v", msg) From aeb5aefe8cd9ea65fce8d19c4345363b6d9481ad Mon Sep 17 00:00:00 2001 From: Simon Ott Date: Wed, 26 Jun 2024 18:41:39 +0000 Subject: [PATCH 2/6] measure: sort OCI runtime config environment variables alphabetically Signed-off-by: Simon Ott --- measure/rtconfig.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/measure/rtconfig.go b/measure/rtconfig.go index 01f9e68d..98a305de 100644 --- a/measure/rtconfig.go +++ b/measure/rtconfig.go @@ -21,6 +21,7 @@ import ( "encoding/json" "fmt" "path/filepath" + "slices" "strings" "github.com/opencontainers/runtime-spec/specs-go" @@ -78,7 +79,7 @@ func normalize(id string, configData []byte) ([]byte, string, error) { return nil, "", fmt.Errorf("failed to evaluate dockerd symlink: %w", err) } - // TODO FIXME The docker network controller ID is generated randomly (// github.com/moby/moby/libnetwork/controller.go:New()) + // TODO FIXME The docker network controller ID is generated randomly (github.com/moby/moby/libnetwork/controller.go:New()) // and then the truncated daemon.netController.ID() is added as an argument in the prestart // hooks (github.com/moby/moby/daemon/oci_linux.go:withLibnetwork()). This is a very hacky // way to make it reproducible, ideally, the actual network ID controller ID should be @@ -107,6 +108,9 @@ func normalize(id string, configData []byte) ([]byte, string, error) { rootfs := config.Root.Path config.Root = nil + // List environment variables alphabetically to guarantee reproducibility + slices.Sort(config.Process.Env) + data, err := json.Marshal(config) if err != nil { return nil, "", fmt.Errorf("failed to marshal config: %w", err) From 47cb84475dfe1757817ea0244b05944ff9d7859b Mon Sep 17 00:00:00 2001 From: Simon Ott Date: Wed, 26 Jun 2024 18:42:27 +0000 Subject: [PATCH 3/6] example-setup: support docker compose Signed-off-by: Simon Ott --- example-setup/setup-cmc | 1 + example-setup/update-container-manifest-live | 185 +++++++++++-------- 2 files changed, 110 insertions(+), 76 deletions(-) diff --git a/example-setup/setup-cmc b/example-setup/setup-cmc index cc05dad1..b137e8dc 100755 --- a/example-setup/setup-cmc +++ b/example-setup/setup-cmc @@ -35,6 +35,7 @@ mkdir -p "${data}" # Install dependencies sudo apt install -y moreutils golang-cfssl build-essential zlib1g-dev libssl-dev jq +sudo snap install yq # Intall tpm-pcr-tools git clone https://github.com/Fraunhofer-AISEC/tpm-pcr-tools.git "${data}/tpm-pcr-tools" diff --git a/example-setup/update-container-manifest-live b/example-setup/update-container-manifest-live index 1267fd15..a9294082 100755 --- a/example-setup/update-container-manifest-live +++ b/example-setup/update-container-manifest-live @@ -8,8 +8,12 @@ source "${dir}/utils.sh" export PATH=${PATH}:${HOME}/go/bin if [[ "$#" -lt 5 ]]; then - echo "Usage: ./update-container-manifest-live []" - exit 1 + # The target depends on the client, examples: + # docker/ctr: docker.io/library/ubuntu:22.04 + # docker compose: docker-compose.yaml + # runc: /path/to/runtime-bundle + echo "Usage: ./update-container-manifest-live []" + exit 1 fi # Extract the -env parameters @@ -28,7 +32,7 @@ for arg in "$@"; do done # Set all parameters -container="$1" +target="$1" shift data=$(set -e; abs_path "$1") shift @@ -44,105 +48,134 @@ input="${data}/metadata-raw" tmp="${data}/metadata-tmp" output="${data}/metadata-signed" runtime="${cmc}/tools/containerd-shim-cmc-v1/containerd-shim-cmc-v1" -container="${container%/}" -container_name=$(echo "${container}-oci" | sed 's:.*/::' | tr : -) +target="${target%/}" + -echo "Creating reference values for container: ${container} with args ${args}" +echo "Creating reference values for container: ${target} with args ${args}" echo "Using ${data} as directory for local data" # Delete temporary manifests -rm -rf "${tmp}"/${container_name}.manifest.* +rm -rf "${tmp}"/* # Calculate the container reference values sudo rm -f /tmp/container-refs echo "Generating reference values for ${client} client" if [[ "${client}" == "ctr" ]]; then - sudo ctr image pull ${container} + containers=("${target}") + sudo ctr image pull ${target} set +e - sudo ctr run --detach ${args} ${container} REF_CONTAINER + sudo ctr run --detach ${args} ${target} REF_CONTAINER sudo ctr task kill -s SIGKILL REF_CONTAINER sudo ctr container delete REF_CONTAINER set -e elif [[ "${client}" == "shim" ]]; then - sudo ctr image pull ${container} + containers=("${target}") + sudo ctr image pull ${target} set +e - sudo ctr run --runtime ${runtime} -t --rm ${args} ${container} CMC_GENERATE_APP_MANIFEST + sudo ctr run --runtime ${runtime} -t --rm ${args} ${target} CMC_GENERATE_APP_MANIFEST set -e elif [[ "${client}" == "docker" ]]; then - sudo docker run ${args} ${container} + containers=("${target}") + sudo docker run ${args} ${target} +elif [[ "${client}" == "docker-compose" ]]; then + containers=($(yq eval '.services | keys | .[]' "${target}")) + set +e + docker compose -f "${target}" up & + echo "Sleeping for 10s to enable container start" + sleep 10 + echo "Stopping containers" + docker compose -f "${target}" stop + sleep 3 + set -e elif [[ "${client}" == "runc" ]]; then - cd ${container} + containers=("${target}") + cd ${target} sudo runc create references sudo runc delete references cd - else - echo "Client ${client} not supported. Only 'docker', 'ctr' and 'runc' supported for now." + echo "Client ${client} not supported. Only 'docker', 'docker-compose', 'ctr' and 'runc' supported for now." exit fi refvals=$(cat /tmp/container-refs) -# App Manifest: Replace existing reference values with new reference values in the App Manifest -json=$(cat "${input}/app.manifest.json") -json=$(echo "${json}" | jq 'del(.referenceValues[])') -json=$(echo "${json}" | jq --argjson ver "${refvals}" '.referenceValues += $ver') - -# App Manifest: Extract the reference value and add it to the file name to not overwrite the same -# container with different arguments such as environment variables -refval=$(echo "${json}" | jq -r '.referenceValues[0].sha256') - -# App Manifest: Set name and reference value name -json=$(echo "${json}" | jq ".name = \"${container}-${refval}\"") -json=$(echo "${json}" | jq ".referenceValues[0].name += \": ${container}\"") - -# App Manifest: Store -echo "Writing ${input}/${container_name}-${refval}.manifest.json" -printf "%s\n" "${json}" > "${input}/${container_name}-${refval}.manifest.json" - -# App Description: Create corresponding app description -appdesc=$(cat "${input}/app.description.json") -appdesc=$(echo "${appdesc}" | jq ".name = \"${container}-${refval}.description\"") -appdesc=$(echo "${appdesc}" | jq ".appManifest = \"${container}-${refval}\"") -echo "Adding environment variables" -for i in "${!keys[@]}"; do - envs="{\"key\": \"${keys[$i]}\", \"value\": \"${values[$i]}\"}" - echo "Adding $envs" - appdesc=$(echo "${appdesc}" | jq --argjson envs "${envs}" '.environment += [$envs]') -done - -# Device Description: Add/replace app description to/in device description -devdesc=$(cat "${input}/device.description.json") -exists=$(echo "${devdesc}" | jq "any(.appDescriptions[]; .name == \"${container}-${refval}.description\")") -if [[ "${exists}" = false ]]; then - echo "Adding app description to device description" -else - echo "Replacing existing app description" - devdesc=$(echo "$devdesc" | jq ".appDescriptions |= map(select(.name != \"${container}-${refval}.description\"))") -fi -devdesc=$(echo "${devdesc}" | jq --argjson desc "[${appdesc}]" '.appDescriptions += $desc') - -# Device Description: Store -echo "Writing ${input}/device.description.json" -printf "%s\n" "${devdesc}" > "${input}/device.description.json" - -# Sign the metadata* -key="${data}/pki/signing-cert-key.pem" -chain="${data}/pki/signing-cert.pem,${data}/pki/ca.pem" - -# Convert to CBOR if specified -if [[ "${ser,,}" = "json" ]]; then - echo "using json serialization" - cp "${input}/${container_name}-${refval}.manifest.json" "${tmp}/${container_name}-${refval}.manifest.json" - cp "${input}/device.description.json" "${tmp}/device.description.json" -elif [[ "${ser,,}" = "cbor" ]]; then - echo "using cbor serialiation" - cmc-converter -in "${input}/${container_name}-${refval}.manifest.json" -out "${tmp}/${container_name}-${refval}.manifest.cbor" -outform cbor - cmc-converter -in "${input}/device.description.json" -out "${tmp}/device.description.cbor" -outform cbor -else - echo "serialization format ${ser} is not supported" - exit 1 -fi +# if containers not set, set it to the single container + +# In some scenarios, e.g. docker-compose, we have more than one container and have to iterate over all +num_containers=$(echo "${refvals}" | jq length) +for ((i = 0; i < num_containers; i++)); do + echo "Creating manifest for container $i" + + container=${containers[$i]} + container_name=$(echo "${container}-oci" | sed 's:.*/::' | tr : -) + + refval=$(echo "${refvals}" | jq -r ".[$i]") + + # App Manifest: Replace existing reference values with new reference values in the App Manifest + json=$(cat "${input}/app.manifest.json") + json=$(echo "${json}" | jq 'del(.referenceValues[])') + json=$(echo "${json}" | jq --argjson ver "[${refval}]" '.referenceValues += $ver') + + # App Manifest: Extract the reference value sha256 and add it to the file name to not overwrite the same + # container with different arguments such as environment variables + sha256=$(echo "${json}" | jq -r '.referenceValues[0].sha256') + + echo "Refval sha256: ${sha256}" + + # App Manifest: Set name and reference value name + json=$(echo "${json}" | jq ".name = \"${container}-${sha256}\"") + json=$(echo "${json}" | jq ".referenceValues[0].name += \": ${container}\"") + + # App Manifest: Store + echo "Writing ${input}/${container_name}-${sha256}.manifest.json" + printf "%s\n" "${json}" > "${input}/${container_name}-${sha256}.manifest.json" + + # App Description: Create corresponding app description + appdesc=$(cat "${input}/app.description.json") + appdesc=$(echo "${appdesc}" | jq ".name = \"${container}-${sha256}.description\"") + appdesc=$(echo "${appdesc}" | jq ".appManifest = \"${container}-${sha256}\"") + echo "Adding environment variables" + for i in "${!keys[@]}"; do + envs="{\"key\": \"${keys[$i]}\", \"value\": \"${values[$i]}\"}" + echo "Adding $envs" + appdesc=$(echo "${appdesc}" | jq --argjson envs "${envs}" '.environment += [$envs]') + done + + # Device Description: Add/replace app description to/in device description + devdesc=$(cat "${input}/device.description.json") + exists=$(echo "${devdesc}" | jq "any(.appDescriptions[]; .name == \"${container}-${sha256}.description\")") + if [[ "${exists}" = false ]]; then + echo "Adding app description to device description" + else + echo "Replacing existing app description" + devdesc=$(echo "$devdesc" | jq ".appDescriptions |= map(select(.name != \"${container}-${sha256}.description\"))") + fi + devdesc=$(echo "${devdesc}" | jq --argjson desc "[${appdesc}]" '.appDescriptions += $desc') + + # Device Description: Store + echo "Writing ${input}/device.description.json" + printf "%s\n" "${devdesc}" > "${input}/device.description.json" + + # Sign the metadata* + key="${data}/pki/signing-cert-key.pem" + chain="${data}/pki/signing-cert.pem,${data}/pki/ca.pem" + + # Convert to CBOR if specified + if [[ "${ser,,}" = "json" ]]; then + echo "using json serialization" + cp "${input}/${container_name}-${sha256}.manifest.json" "${tmp}/${container_name}-${sha256}.manifest.json" + cp "${input}/device.description.json" "${tmp}/device.description.json" + elif [[ "${ser,,}" = "cbor" ]]; then + echo "using cbor serialiation" + cmc-converter -in "${input}/${container_name}-${sha256}.manifest.json" -out "${tmp}/${container_name}-${sha256}.manifest.cbor" -outform cbor + cmc-converter -in "${input}/device.description.json" -out "${tmp}/device.description.cbor" -outform cbor + else + echo "serialization format ${ser} is not supported" + exit 1 + fi -cmc-signing-tool -in "${tmp}/${container_name}-${refval}.manifest.${ser}" -out "${output}/${container_name}-${refval}.manifest.${ser}" -keys "${key}" -x5cs "${chain}" -cmc-signing-tool -in "${tmp}/device.description.${ser}" -out "${output}/device.description.${ser}" -keys "${key}" -x5cs "${chain}" \ No newline at end of file + cmc-signing-tool -in "${tmp}/${container_name}-${sha256}.manifest.${ser}" -out "${output}/${container_name}-${sha256}.manifest.${ser}" -keys "${key}" -x5cs "${chain}" + cmc-signing-tool -in "${tmp}/device.description.${ser}" -out "${output}/device.description.${ser}" -keys "${key}" -x5cs "${chain}" +done \ No newline at end of file From 7978e30678b0b8ffa39400b38f71042c4c47470b Mon Sep 17 00:00:00 2001 From: Simon Ott Date: Tue, 23 Jul 2024 11:39:23 +0000 Subject: [PATCH 4/6] example-setup/update-platform: retrieve platform details Signed-off-by: Simon Ott --- example-setup/update-platform | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/example-setup/update-platform b/example-setup/update-platform index 8b9ad8ff..1740e391 100755 --- a/example-setup/update-platform +++ b/example-setup/update-platform @@ -25,6 +25,14 @@ fi echo "Using ${data} as directory for local data" +# Retrieve high level details +set +e +firmware="Lenovo" +bootloader=$(grub-install --version) +kernel=$(uname -r) +os=$(lsb_release -sd 2>/dev/null) +set -e + # Replace existing app description in the device description (will be added through # update-app-manifest scripts) json=$(cat "${input}/device.description.json") @@ -34,17 +42,31 @@ printf "%s\n" "${json}" > "${input}/device.description.json" # Parse the values of the RTM PCRs from the kernel's binary bios measurements as reference values referenceValues=$(sudo parse-srtm-pcrs -p 0,1,2,3,4,5,6,7 -f json -e) -# Replace existing reference values with new reference values in the RTM Manifest +# Load RTM manifest json=$(cat "${input}/rtm.manifest.json") + +# Insert high-level details +json=$(echo "${json}" | jq ".details.firmware = \"${firmware}\"") +json=$(echo "${json}" | jq ".details.bootloader = \"${bootloader}\"") + +# Replace existing reference values with new reference values in the RTM Manifest json=$(echo "${json}" | jq 'del(.referenceValues[])') json=$(echo "${json}" | jq --argjson ver "${referenceValues}" '.referenceValues += $ver') + +# Save the RTM manifest printf "%s\n" "${json}" > "${input}/rtm.manifest.json" # Parse the values of the OS PCRs from the kernel's binary bios measurements as reference values referenceValues=$(sudo parse-srtm-pcrs -p 8,9,12,13,14,15 -f json -e) -# Replace existing reference values with new reference values in the RTM Manifest +# Load OS manifest json=$(cat "${input}/os.manifest.json") + +# Insert high-level details +json=$(echo "${json}" | jq ".details.kernel = \"${kernel}\"") +json=$(echo "${json}" | jq ".details.os = \"${os}\"") + +# Replace existing reference values with new reference values in the OS Manifest json=$(echo "${json}" | jq 'del(.referenceValues[])') json=$(echo "${json}" | jq --argjson ver "${referenceValues}" '.referenceValues += $ver') printf "%s\n" "${json}" > "${input}/os.manifest.json" From cff22365f4f31e8c7da90a1c724d98ec474814f0 Mon Sep 17 00:00:00 2001 From: Simon Ott Date: Thu, 25 Jul 2024 11:58:19 +0000 Subject: [PATCH 5/6] measure: fixed unit test Signed-off-by: Simon Ott --- measure/rtconfig_test.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/measure/rtconfig_test.go b/measure/rtconfig_test.go index ffe5df6d..9b796e5d 100644 --- a/measure/rtconfig_test.go +++ b/measure/rtconfig_test.go @@ -38,7 +38,12 @@ func TestGetConfigMeasurement(t *testing.T) { id: "mycontainer", configData: configData, }, - want: []byte{0x17, 0x76, 0xdf, 0xed, 0x31, 0x7c, 0xa1, 0x03, 0xd1, 0x49, 0x13, 0xd6, 0x5e, 0x86, 0x2e, 0x8a, 0xa8, 0x0a, 0x3c, 0x73, 0x87, 0xeb, 0x3f, 0x36, 0x20, 0xd3, 0xe3, 0x2d, 0x46, 0x4c, 0x54, 0x62}, + want: []byte{ + 0xaf, 0xd6, 0xa3, 0x51, 0xca, 0x87, 0xb4, 0x1c, + 0x84, 0x82, 0x5d, 0x76, 0x7a, 0x71, 0x91, 0x80, + 0x3d, 0x08, 0x77, 0xc3, 0x33, 0xf1, 0xf1, 0xee, + 0xaa, 0xd0, 0xa5, 0x9a, 0xf5, 0x01, 0x11, 0x0e, + }, wantErr: false, }, } @@ -92,7 +97,7 @@ func Test_normalize(t *testing.T) { } var ( - normalizedDockerConfig = []byte(`{"hooks":{"prestart":[{"args":["libnetwork-setkey","-exec-root=/var/run/docker","",""],"path":"/usr/bin/dockerd"}]},"hostname":"","linux":{"cgroupsPath":"system.slice:docker:","maskedPaths":["/proc/asound","/sys/devices/virtual/powercap"],"namespaces":[{"type":"mount"}],"readonlyPaths":["/proc/bus","/proc/sysrq-trigger"],"resources":{"blockIO":{},"devices":[{"access":"rwm","allow":false}]},"seccomp":{"architectures":["SCMP_ARCH_X86_64","SCMP_ARCH_X32"],"defaultAction":"SCMP_ACT_ERRNO","defaultErrnoRet":1,"syscalls":[{"action":"SCMP_ACT_ALLOW","names":["chroot"]}]},"sysctl":{"net.ipv4.ip_unprivileged_port_start":"0","net.ipv4.ping_group_range":"0 2147483647"}},"mounts":[{"destination":"/etc/resolv.conf","options":["rbind","rprivate"],"source":"/var/lib/docker/containers//resolv.conf","type":"bind"}],"ociVersion":"1.2.0","process":{"args":["/bin/sh"],"capabilities":{"permitted":["CAP_CHOWN","CAP_DAC_OVERRIDE"]},"cwd":"/","env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","HOSTNAME=","TERM=xterm"],"user":{"gid":0,"uid":0}}}`) + normalizedDockerConfig = []byte(`{"hooks":{"prestart":[{"args":["libnetwork-setkey","-exec-root=/var/run/docker","",""],"path":"/usr/bin/dockerd"}]},"hostname":"","linux":{"cgroupsPath":"system.slice:docker:","maskedPaths":["/proc/asound","/sys/devices/virtual/powercap"],"namespaces":[{"type":"mount"}],"readonlyPaths":["/proc/bus","/proc/sysrq-trigger"],"resources":{"blockIO":{},"devices":[{"access":"rwm","allow":false}]},"seccomp":{"architectures":["SCMP_ARCH_X86_64","SCMP_ARCH_X32"],"defaultAction":"SCMP_ACT_ERRNO","defaultErrnoRet":1,"syscalls":[{"action":"SCMP_ACT_ALLOW","names":["chroot"]}]},"sysctl":{"net.ipv4.ip_unprivileged_port_start":"0","net.ipv4.ping_group_range":"0 2147483647"}},"mounts":[{"destination":"/etc/resolv.conf","options":["rbind","rprivate"],"source":"/var/lib/docker/containers//resolv.conf","type":"bind"}],"ociVersion":"1.2.0","process":{"args":["/bin/sh"],"capabilities":{"permitted":["CAP_CHOWN","CAP_DAC_OVERRIDE"]},"cwd":"/","env":["HOSTNAME=","PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","TERM=xterm"],"user":{"gid":0,"uid":0}}}`) dockerConfig = []byte(` { From 80c3846a5cdc39dd36f1cc323f4555b27671f3fd Mon Sep 17 00:00:00 2001 From: Simon Ott Date: Thu, 25 Jul 2024 12:01:57 +0000 Subject: [PATCH 6/6] ci: updated go version Signed-off-by: Simon Ott --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 95729149..9ffcf005 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v2 with: - go-version: 1.20.5 + go-version: 1.22.5 - name: Build run: |