diff --git a/.ci/ci_job_flags.sh b/.ci/ci_job_flags.sh index ee8519994..8d5a52536 100755 --- a/.ci/ci_job_flags.sh +++ b/.ci/ci_job_flags.sh @@ -106,7 +106,7 @@ case "${CI_JOB}" in export CRI_RUNTIME="containerd" export KATA_HYPERVISOR="qemu" ;; -"CRI_CONTAINERD"|"CRI_CONTAINERD_K8S"|"CC_CRI_CONTAINERD"|"CC_CRI_CONTAINERD_K8S"|"CC_SEV_CRI_CONTAINERD_K8S") +"CRI_CONTAINERD"|"CRI_CONTAINERD_K8S"|"CC_CRI_CONTAINERD"|"CC_CRI_CONTAINERD_K8S") # This job only tests containerd + k8s init_ci_flags export CRI_CONTAINERD="yes" @@ -116,7 +116,7 @@ case "${CI_JOB}" in "CRI_CONTAINERD_K8S") export KUBERNETES="yes" ;; - "CC_CRI_CONTAINERD"|"CC_CRI_CONTAINERD_K8S"|"CC_SEV_CRI_CONTAINERD_K8S") + "CC_CRI_CONTAINERD"|"CC_CRI_CONTAINERD_K8S") # Export any CC specific environment variables export KATA_BUILD_CC="yes" export MEASURED_ROOTFS="yes" @@ -124,14 +124,31 @@ case "${CI_JOB}" in if [[ "${CI_JOB}" =~ K8S ]]; then export KUBERNETES=yes fi - if [[ "${CI_JOB}" =~ SEV ]]; then - export TEE_TYPE="sev" - export AA_KBC="online_sev_kbc" - export TEST_INITRD="yes" - fi ;; esac ;; +"CC_SEV_CRI_CONTAINERD_K8S"|"CC_SNP_CRI_CONTAINERD_K8S") + init_ci_flags + export CRI_CONTAINERD="yes" + export CRI_RUNTIME="containerd" + export KATA_HYPERVISOR="qemu" + export KATA_BUILD_CC="yes" + export AA_KBC="offline_fs_kbc" + export TEST_INITRD="yes" + if [[ "${CI_JOB}" =~ K8S ]]; then + export KUBERNETES=yes + fi + if [[ "${CI_JOB}" =~ SEV ]]; then + export TEE_TYPE="sev" + export AA_KBC="online_sev_kbc" + export KATA_BUILD_KERNEL_TYPE="sev" + fi + if [[ "${CI_JOB}" =~ SNP ]]; then + export TEE_TYPE="snp" + export KATA_BUILD_QEMU_TYPE="snp" + export KATA_BUILD_KERNEL_TYPE="sev" + fi + ;; "CC_CRI_CONTAINERD_TDX_QEMU"|"CC_CRI_CONTAINERD_TDX_CLOUD_HYPERVISOR") init_ci_flags export CRI_CONTAINERD="yes" diff --git a/.ci/install_kata.sh b/.ci/install_kata.sh index 38a56b1ba..2af726757 100755 --- a/.ci/install_kata.sh +++ b/.ci/install_kata.sh @@ -33,6 +33,10 @@ if [ "${TEE_TYPE:-}" == "sev" ]; then KATA_BUILD_KERNEL_TYPE=sev fi +if [ "${TEE_TYPE:-}" == "snp" ]; then + KATA_BUILD_KERNEL_TYPE=snp +fi + if [ "${KATA_HYPERVISOR:-}" == "dragonball" ]; then KATA_BUILD_KERNEL_TYPE=dragonball fi @@ -87,7 +91,7 @@ case "${KATA_HYPERVISOR}" in "${cidir}/install_virtiofsd.sh" if [ "${TEE_TYPE}" == "tdx" ]; then "${cidir}/install_tdvf.sh" - elif [ "${TEE_TYPE:-}" == "sev" ]; then + elif [ "${TEE_TYPE:-}" == "sev" ] || [ "${TEE_TYPE:-}" == "snp" ]; then "${cidir}/install_ovmf_sev.sh" fi ;; diff --git a/.ci/install_kata_image.sh b/.ci/install_kata_image.sh index 00866dfec..fd7ec521c 100755 --- a/.ci/install_kata_image.sh +++ b/.ci/install_kata_image.sh @@ -21,7 +21,9 @@ TEE_TYPE="${TEE_TYPE:-}" build_image_for_cc () { if [ "${TEST_INITRD}" == "yes" ]; then - [ "${TEE_TYPE}" == "sev" ] || die "SEV is the only TEE type that supports initrd" + if [ "${TEE_TYPE}" != "sev" ] && [ "${TEE_TYPE}" != "snp" ]; then + die "SEV and SNP are the only TEE types that supports initrd" + fi build_static_artifact_and_install "sev-rootfs-initrd" else [ "${osbuilder_distro:-ubuntu}" == "ubuntu" ] || \ diff --git a/.ci/install_qemu.sh b/.ci/install_qemu.sh index 09e9afde0..7dda7041a 100755 --- a/.ci/install_qemu.sh +++ b/.ci/install_qemu.sh @@ -29,7 +29,7 @@ build_and_install_qemu_for_cc() { local artifact="qemu" case "${qemu_type}" in - tdx) + tdx|snp) artifact="${qemu_type}-${artifact}" ;; vanilla) ;; @@ -109,6 +109,12 @@ main() { export qemu_type case "${qemu_type}" in + snp) + CURRENT_QEMU_VERSION=$(get_version "assets.hypervisor.qemu-snp-experimental.tag") + QEMU_REPO_URL=$(get_version "assets.hypervisor.qemu-snp-experimental.url") + qemu_latest_build_url="${jenkins_url}/job/kata-containers-2.0-qemu-snp-$(uname -m)/${cached_artifacts_path}" + qemu_type="snp-qemu" + ;; vanilla) qemu_type="qemu" ;; diff --git a/.ci/install_runtime.sh b/.ci/install_runtime.sh index 2d0cb7daf..5be2f3933 100755 --- a/.ci/install_runtime.sh +++ b/.ci/install_runtime.sh @@ -134,6 +134,8 @@ case "${KATA_HYPERVISOR}" in enable_hypervisor_config "${PKGDEFAULTSDIR}/configuration-qemu-tdx.toml" elif [ "$TEE_TYPE" == "sev" ]; then enable_hypervisor_config "${PKGDEFAULTSDIR}/configuration-qemu-sev.toml" + elif [ "$TEE_TYPE" == "snp" ]; then + enable_hypervisor_config "${PKGDEFAULTSDIR}/configuration-qemu-snp.toml" elif [ "$TEE_TYPE" == "se" ]; then enable_hypervisor_config "${PKGDEFAULTSDIR}/configuration-qemu-se.toml" else diff --git a/Makefile b/Makefile index 6e48a8283..c32c0977b 100644 --- a/Makefile +++ b/Makefile @@ -113,6 +113,12 @@ cc-sev-kubernetes: K8S_TEST_UNION="confidential/sev.bats" \ bash integration/kubernetes/run_kubernetes_tests.sh +# Run the Confidential Containers AMD SNP specific tests. +cc-snp-kubernetes: + bash -f .ci/install_bats.sh + K8S_TEST_UNION="confidential/snp.bats" \ + bash integration/kubernetes/run_kubernetes_tests.sh + log-parser: make -C cmd/log-parser diff --git a/integration/kubernetes/confidential/snp.bats b/integration/kubernetes/confidential/snp.bats new file mode 100644 index 000000000..1f5183ece --- /dev/null +++ b/integration/kubernetes/confidential/snp.bats @@ -0,0 +1,95 @@ +#!/usr/bin/env bats +# Copyright 2023 Advanced Micro Devices, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Environment variables +TEST_TAG="[cc][kubernetes][containerd][snp]" +TESTS_REPO_DIR=$(realpath "${BATS_TEST_DIRNAME}/../../..") +RUNTIMECLASS="${RUNTIMECLASS:-"kata"}" +IMAGE_REPO="ghcr.io/confidential-containers/test-container" +UNENCRYPTED_IMAGE_URL="${IMAGE_REPO}:unencrypted" + +# Text to grep for active feature in guest dmesg output +SNP_DMESG_GREP_TEXT="Memory Encryption Features active:.*SEV-SNP" + +export TEST_DIR +export ENCRYPTION_KEY +export SSH_KEY_FILE + +load "${BATS_TEST_DIRNAME}/../../confidential/lib.sh" +load "${TESTS_REPO_DIR}/lib/common.bash" +load "${TESTS_REPO_DIR}/integration/kubernetes/lib.sh" + +# Delete all test services +k8s_delete_all() { + k8s_delete_by_yaml "snp-unencrypted" "${TEST_DIR}/snp-unencrypted.yaml" +} + +setup_file() { + TEST_DIR="$(mktemp -d /tmp/test-kata-snp.XXXXXXXX)" + SSH_KEY_FILE="${TEST_DIR}/container-ssh-key" + + # Install package dependencies + echo "Installing required packages..." + esudo apt install -y jq + + # Configure CoCo settings in containerd config + local saved_containerd_conf_file="/etc/containerd/config.toml.$$" + configure_cc_containerd "${saved_containerd_conf_file}" + + # Pull unencrypted image and retrieve ssh keys + echo "Pulling unencrypted image and retrieve ssh key..." + docker_image_label_save_ssh_key "${UNENCRYPTED_IMAGE_URL}" "${SSH_KEY_FILE}" + + # SEV service yaml generation + k8s_generate_service_yaml "${TEST_DIR}/snp-unencrypted.yaml" "${IMAGE_REPO}:unencrypted" +} + +teardown_file() { + # Allow to not destroy the environment if you are developing/debugging tests + if [[ "${CI:-false}" == "false" && "${DEBUG:-}" == true ]]; then + echo "Leaving changes and created resources untouched" + return + fi + + # Remove all k8s test services + k8s_delete_all + + # Cleanup directories + esudo rm -rf "${TEST_DIR}" +} + +setup() { + # Remove any previous k8s test services + echo "Deleting previous test services..." + k8s_delete_all +} + + +@test "${TEST_TAG} Test SNP unencrypted container launch success" { + # Start the service/deployment/pod + esudo kubectl apply -f "${TEST_DIR}/snp-unencrypted.yaml" + + # Retrieve pod name, wait for it to come up, retrieve pod ip + local pod_name=$(esudo kubectl get pod -o wide | grep snp-unencrypted | awk '{print $1;}') + k8s_wait_for_pod_ready_state "$pod_name" 20 + local pod_ip=$(esudo kubectl get pod -o wide | grep snp-unencrypted | awk '{print $6;}') + + k8s_print_info "snp-unencrypted" + + # Look for SEV enabled in container dmesg output + local snp_enabled=$(ssh_dmesg_grep \ + "${SSH_KEY_FILE}" \ + "${pod_ip}" \ + "${SNP_DMESG_GREP_TEXT}") + + if [ -z "${snp_enabled}" ]; then + >&2 echo -e "KATA SNP TEST - FAIL: SNP is NOT Enabled" + return 1 + else + echo "DMESG REPORT: ${snp_enabled}" + echo -e "KATA SNP TEST - PASS: SNP is Enabled" + fi +}