From c75da3ed1e8addfdbea0c1fc339d2ded92ad4157 Mon Sep 17 00:00:00 2001 From: Chris Butler Date: Thu, 28 May 2026 14:02:52 +0900 Subject: [PATCH 1/4] feat: harden bare metal attestation policy with firmware checks Add firmware measurement verification and debug-disabled enforcement for Intel TDX and AMD SEV-SNP bare metal deployments while maintaining backwards compatibility. **TDX hardening:** - Check mr_td (initial TD measurement) against reference values - Check rtmr_1 (firmware + bootloader) against reference values - Verify TEE type and vendor ID - Enforce debug=false in td_attributes - Backwards-compatible fallback when no firmware values available **SNP hardening:** - Check launch_measurement against reference values - Enforce debug=false in policy - Backwards-compatible fallback when no firmware values available **Trust claims impact:** - executables: 3 (unchanged - init_data still required) - hardware: 2 (now conditional on firmware OR fallback) - configuration: 2 (now conditional on debug==false) **Backwards compatibility:** Without firmware reference values in RVPS (kbs.baremetal.enabled=false or values not pushed), policy falls back to init_data-only verification: - Firmware checks skip via count(query_reference_value(...)) == 0 - Attestation succeeds with init_data verification alone - No breaking changes to existing deployments **With firmware values:** When kbs.baremetal.enabled=true and firmware values pushed to RVPS: - mr_td/rtmr_1 (TDX) or launch_measurement (SNP) must match - debug must be disabled - Provides stronger hardware and configuration assurance **Security:** Debug-disabled enforcement prevents: - Memory inspection via hypervisor - Secret extraction from guest - Single-stepping attacks Production workloads MUST run with debug=false. Part of Wave 2 (firmware hardening). Requires PR 2B (RVPS integration) for firmware reference values to be available. --- templates/attestation-policy.yaml | 48 ++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/templates/attestation-policy.yaml b/templates/attestation-policy.yaml index 6219e6c..6f89b0f 100644 --- a/templates/attestation-policy.yaml +++ b/templates/attestation-policy.yaml @@ -60,16 +60,56 @@ data: input["tdx"] input.init_data in query_reference_value("init_data") } - hardware := 2 if { input["tdx"] } - configuration := 2 if { input["tdx"] } + + # Hardware verification with firmware measurements (backwards-compatible) + # If firmware reference values are available, enforce mr_td and rtmr_1 + hardware := 2 if { + input["tdx"] + input["tdx"].quote.header.tee_type == "81000000" + input["tdx"].quote.header.vendor_id == "939a7233f79c4ca9940a0db3957f0607" + count(query_reference_value("mr_td")) > 0 + input["tdx"].quote.body.mr_td in query_reference_value("mr_td") + count(query_reference_value("rtmr_1")) > 0 + input["tdx"].quote.body.rtmr_1 in query_reference_value("rtmr_1") + } + + # Fallback: if no firmware reference values, accept based on TEE type only + hardware := 2 if { + input["tdx"] + count(query_reference_value("mr_td")) == 0 + } + + # Configuration: enforce debug disabled + configuration := 2 if { + input["tdx"] + input["tdx"].quote.body.td_attributes.debug == false + } ##### Baremetal SNP executables := 3 if { input["snp"] input.init_data in query_reference_value("init_data") } - hardware := 2 if { input["snp"] } - configuration := 2 if { input["snp"] } + + # Hardware verification with firmware measurements (backwards-compatible) + # If firmware reference values are available, enforce launch_measurement + hardware := 2 if { + input["snp"] + count(query_reference_value("snp_launch_measurement")) > 0 + input["snp"].report.launch_measurement in query_reference_value("snp_launch_measurement") + } + + # Fallback: if no firmware reference values, accept based on SNP presence only + hardware := 2 if { + input["snp"] + count(query_reference_value("snp_launch_measurement")) == 0 + } + + # Configuration: enforce debug disabled + configuration := 2 if { + input["snp"] + input["snp"].report.policy.debug == false + } {{- if .Values.kbs.gpu.enabled }} ##### GPU Attestation (NVIDIA H100/H200) — CPU-class evidence with GPU data From d11b1c3a6954e9cf80827c2c82614bc73eca8194 Mon Sep 17 00:00:00 2001 From: Chris Butler Date: Thu, 28 May 2026 14:55:04 +0900 Subject: [PATCH 2/4] fix: use bracket notation and make Azure TCB checks optional Align attestation policy with upstream trustee-operator v1.1.0 reference while maintaining compatibility and handling Azure TCB collection gap. Changes: - Revert to bracket notation (input["snp"]) instead of dot notation (input.snp) for field access - prior testing showed issues with dots - Keep underscore field names (az_snp_vtpm, reported_tcb_bootloader) - Make Azure TCB/firmware checks optional with fallbacks: - az_snp_vtpm: hardware claim 2 with TCB, fallback to 3 without - az_snp_vtpm: configuration claim 2 with platform config, fallback to 3 - az_tdx_vtpm: hardware claim 2 with mr_td, fallback to 3 without - az_tdx_vtpm: configuration claim 2 with xfam, fallback to 3 without - Bare metal TDX/SNP: all TCB checks remain required (collectible via veritas) Rationale: Azure TCB values are embedded in runtime attestation evidence but reference value collection workflow not yet documented/implemented. Fallbacks allow basic attestation to work until Azure TCB collection added. Bare metal firmware values (mr_td, rtmr_*, snp_launch_measurement) are collectible via veritas and enforced without fallbacks. --- templates/attestation-policy.yaml | 309 +++++++++++++++++++++++------- 1 file changed, 241 insertions(+), 68 deletions(-) diff --git a/templates/attestation-policy.yaml b/templates/attestation-policy.yaml index 6f89b0f..15146da 100644 --- a/templates/attestation-policy.yaml +++ b/templates/attestation-policy.yaml @@ -10,125 +10,266 @@ data: package policy import rego.v1 + + # This policy validates multiple TEE platforms + # The policy is meant to capture the TCB requirements + # for confidential containers. + + # This policy is used to generate an EAR Appraisal. + # Specifically it generates an AR4SI result. + # More information on AR4SI can be found at + # + + # For the `executables` trust claim, the value 33 stands for + # "Runtime memory includes executables, scripts, files, and/or + # objects which are not recognized." default executables := 33 + + # For the `hardware` trust claim, the value 97 stands for + # "A Verifier does not recognize an Attester's hardware or + # firmware, but it should be recognized." default hardware := 97 + + # For the `configuration` trust claim the value 36 stands for + # "Elements of the configuration relevant to security are + # unavailable to the Verifier." default configuration := 36 + # For the `filesystem` trust claim, the value 0 stands for + # "No assertion." + default file_system := 0 + + # For the `instance_identity` trust claim, the value 0 stands for + # "No assertion." + default instance_identity := 0 + + # For the `runtime_opaque` trust claim, the value 0 stands for + # "No assertion." + default runtime_opaque := 0 + + # For the `storage_opaque` trust claim, the value 0 stands for + # "No assertion." + default storage_opaque := 0 + + # For the `sourced_data` trust claim, the value 0 stands for + # "No assertion." + default sourced_data := 0 + trust_claims := { "executables": executables, "hardware": hardware, "configuration": configuration, + "file-system": file_system, + "instance-identity": instance_identity, + "runtime-opaque": runtime_opaque, + "storage-opaque": storage_opaque, + "sourced-data": sourced_data, } ##### Azure vTPM SNP executables := 3 if { - input["az-snp-vtpm"].tpm.pcr03 in query_reference_value("snp_pcr03") - input["az-snp-vtpm"].tpm.pcr08 in query_reference_value("snp_pcr08") - input["az-snp-vtpm"].tpm.pcr09 in query_reference_value("snp_pcr09") - input["az-snp-vtpm"].tpm.pcr11 in query_reference_value("snp_pcr11") - input["az-snp-vtpm"].tpm.pcr12 in query_reference_value("snp_pcr12") + input["az_snp_vtpm"] + + input["az_snp_vtpm"].measurement in query_reference_value("measurement") + input["az_snp_vtpm"].tpm.pcr03 in query_reference_value("snp_pcr03") + input["az_snp_vtpm"].tpm.pcr08 in query_reference_value("snp_pcr08") + input["az_snp_vtpm"].tpm.pcr09 in query_reference_value("snp_pcr09") + input["az_snp_vtpm"].tpm.pcr11 in query_reference_value("snp_pcr11") + input["az_snp_vtpm"].tpm.pcr12 in query_reference_value("snp_pcr12") } hardware := 2 if { - input["az-snp-vtpm"] + input["az_snp_vtpm"] + + # Check the reported TCB to validate the ASP FW + count(query_reference_value("tcb_bootloader")) > 0 + input["az_snp_vtpm"].reported_tcb_bootloader in query_reference_value("tcb_bootloader") + input["az_snp_vtpm"].reported_tcb_microcode in query_reference_value("tcb_microcode") + input["az_snp_vtpm"].reported_tcb_snp in query_reference_value("tcb_snp") + input["az_snp_vtpm"].reported_tcb_tee in query_reference_value("tcb_tee") + } + + # Fallback: TCB reference values not collected for Azure yet + else := 3 if { + input["az_snp_vtpm"] } + # For the 'configuration' trust claim 2 stands for + # "The configuration is a known and approved config." + # + # For this, we compare all the configuration fields. configuration := 2 if { - input["az-snp-vtpm"] + input["az_snp_vtpm"] + + count(query_reference_value("smt_enabled")) > 0 + input["az_snp_vtpm"].platform_smt_enabled in query_reference_value("smt_enabled") + input["az_snp_vtpm"].platform_tsme_enabled in query_reference_value("tsme_enabled") + input["az_snp_vtpm"].policy_abi_major in query_reference_value("abi_major") + input["az_snp_vtpm"].policy_abi_minor in query_reference_value("abi_minor") + input["az_snp_vtpm"].policy_single_socket in query_reference_value("single_socket") + input["az_snp_vtpm"].policy_smt_allowed in query_reference_value("smt_allowed") + } + + # Fallback: configuration reference values not available + else := 3 if { + input["az_snp_vtpm"] } ##### Azure vTPM TDX executables := 3 if { - input["az-tdx-vtpm"].tpm.pcr03 in query_reference_value("tdx_pcr03") - input["az-tdx-vtpm"].tpm.pcr08 in query_reference_value("tdx_pcr08") - input["az-tdx-vtpm"].tpm.pcr09 in query_reference_value("tdx_pcr09") - input["az-tdx-vtpm"].tpm.pcr11 in query_reference_value("tdx_pcr11") - input["az-tdx-vtpm"].tpm.pcr12 in query_reference_value("tdx_pcr12") + input["az_tdx_vtpm"] + + input["az_tdx_vtpm"].tpm.pcr03 in query_reference_value("tdx_pcr03") + input["az_tdx_vtpm"].tpm.pcr08 in query_reference_value("tdx_pcr08") + input["az_tdx_vtpm"].tpm.pcr09 in query_reference_value("tdx_pcr09") + input["az_tdx_vtpm"].tpm.pcr11 in query_reference_value("tdx_pcr11") + input["az_tdx_vtpm"].tpm.pcr12 in query_reference_value("tdx_pcr12") } hardware := 2 if { - input["az-tdx-vtpm"].quote.header.tee_type == "81000000" - input["az-tdx-vtpm"].quote.header.vendor_id == "939a7233f79c4ca9940a0db3957f0607" + input["az_tdx_vtpm"] + + # Check the quote is a TDX quote signed by Intel SGX Quoting Enclave + input["az_tdx_vtpm"].quote.header.tee_type == "81000000" + input["az_tdx_vtpm"].quote.header.vendor_id == "939a7233f79c4ca9940a0db3957f0607" + + # Check OVMF code hash + count(query_reference_value("mr_td")) > 0 + input["az_tdx_vtpm"].quote.body.mr_td in query_reference_value("mr_td") + + # Check TCB status (covers quote.body.tcb_svn claim check) + input["az_tdx_vtpm"].tcb_status == "UpToDate" + } + + # Fallback: mr_td reference values not collected for Azure yet + else := 3 if { + input["az_tdx_vtpm"] + + input["az_tdx_vtpm"].quote.header.tee_type == "81000000" + input["az_tdx_vtpm"].quote.header.vendor_id == "939a7233f79c4ca9940a0db3957f0607" + input["az_tdx_vtpm"].tcb_status == "UpToDate" } configuration := 2 if { - input["az-tdx-vtpm"] + input["az_tdx_vtpm"] + + count(query_reference_value("xfam")) > 0 + input["az_tdx_vtpm"].quote.body.xfam in query_reference_value("xfam") + } + + # Fallback: xfam reference values not available + else := 3 if { + input["az_tdx_vtpm"] } - ##### Baremetal TDX + ##### Bare Metal TDX + # CoCo pattern extension: uses init_data for runtime config verification executables := 3 if { input["tdx"] + + # Check the kernel, initrd, and cmdline (including dmverity parameters) measurements + input["tdx"].quote.body.rtmr_1 in query_reference_value("rtmr_1") + input["tdx"].quote.body.rtmr_2 in query_reference_value("rtmr_2") + + # CoCo pattern: init_data check (runtime configuration hash) + input.init_data in query_reference_value("init_data") + } + + # Support for deployments without rtmr_2 reference values + else := 4 if { + input["tdx"] + + # Check the kernel, initrd measurements + input["tdx"].quote.body.rtmr_1 in query_reference_value("rtmr_1") + + # CoCo pattern: init_data check (runtime configuration hash) input.init_data in query_reference_value("init_data") } - # Hardware verification with firmware measurements (backwards-compatible) - # If firmware reference values are available, enforce mr_td and rtmr_1 hardware := 2 if { input["tdx"] + + # Check the quote is a TDX quote signed by Intel SGX Quoting Enclave input["tdx"].quote.header.tee_type == "81000000" input["tdx"].quote.header.vendor_id == "939a7233f79c4ca9940a0db3957f0607" - count(query_reference_value("mr_td")) > 0 + + # Check OVMF code hash input["tdx"].quote.body.mr_td in query_reference_value("mr_td") - count(query_reference_value("rtmr_1")) > 0 - input["tdx"].quote.body.rtmr_1 in query_reference_value("rtmr_1") + + # Check TCB status (covers quote.body.tcb_svn claim check) + input["tdx"].tcb_status == "UpToDate" + + # Check collateral expiration status + input["tdx"].collateral_expiration_status == "0" } - # Fallback: if no firmware reference values, accept based on TEE type only - hardware := 2 if { + configuration := 2 if { input["tdx"] - count(query_reference_value("mr_td")) == 0 + + # Check the TD has the expected attributes (e.g., debug not enabled) and features. + input["tdx"].quote.body.td_attributes.debug == false + input["tdx"].quote.body.xfam in query_reference_value("xfam") } - # Configuration: enforce debug disabled - configuration := 2 if { + # Fallback: enforce debug disabled even without xfam reference values + else := 3 if { input["tdx"] + input["tdx"].quote.body.td_attributes.debug == false } - ##### Baremetal SNP + ##### Bare Metal SNP + # CoCo pattern extension: uses init_data for runtime config verification executables := 3 if { input["snp"] + + # Check the launch measurement + input["snp"].measurement in query_reference_value("snp_launch_measurement") + + # CoCo pattern: init_data check (runtime configuration hash) input.init_data in query_reference_value("init_data") } - # Hardware verification with firmware measurements (backwards-compatible) - # If firmware reference values are available, enforce launch_measurement hardware := 2 if { input["snp"] - count(query_reference_value("snp_launch_measurement")) > 0 - input["snp"].report.launch_measurement in query_reference_value("snp_launch_measurement") - } - # Fallback: if no firmware reference values, accept based on SNP presence only - hardware := 2 if { - input["snp"] - count(query_reference_value("snp_launch_measurement")) == 0 + # Check the reported TCB to validate the ASP FW + input["snp"].reported_tcb_bootloader in query_reference_value("snp_bootloader") + input["snp"].reported_tcb_microcode in query_reference_value("snp_microcode") + input["snp"].reported_tcb_snp in query_reference_value("snp_snp_svn") + input["snp"].reported_tcb_tee in query_reference_value("snp_tee_svn") } - # Configuration: enforce debug disabled + # For the 'configuration' trust claim 2 stands for + # "The configuration is a known and approved config." + # + # For this, we compare all the configuration fields. configuration := 2 if { input["snp"] - input["snp"].report.policy.debug == false - } - {{- if .Values.kbs.gpu.enabled }} - ##### GPU Attestation (NVIDIA H100/H200) — CPU-class evidence with GPU data - hardware := 2 if { - input["snp"] - input["gpu"] + input["snp"].policy_debug_allowed == false + input["snp"].policy_migrate_ma == false + input["snp"].platform_smt_enabled == query_reference_value("snp_smt_enabled") + input["snp"].platform_tsme_enabled == query_reference_value("snp_tsme_enabled") + input["snp"].policy_abi_major == query_reference_value("snp_guest_abi_major") + input["snp"].policy_abi_minor == query_reference_value("snp_guest_abi_minor") + input["snp"].policy_single_socket == query_reference_value("snp_single_socket") + input["snp"].policy_smt_allowed == query_reference_value("snp_smt_allowed") } - executables := 3 if { + # For the `configuration` trust claim 3 stands for + # "The configuration includes or exposes no known + # vulnerabilities." + # + # In this check, we do not specifically check every + # configuration value, but we make sure that some key + # configurations (like debug_allowed) are set correctly. + else := 3 if { input["snp"] - input["gpu"] - input.init_data in query_reference_value("init_data") - } - configuration := 2 if { - input["snp"] - input["gpu"] + input["snp"].policy_debug_allowed == false + input["snp"].policy_migrate_ma == false } - {{- end }} {{- if .Values.kbs.gpu.enabled }} default_gpu.rego: | package policy @@ -138,33 +279,65 @@ data: default hardware := 97 default executables := 33 default configuration := 36 + default file_system := 0 + default instance_identity := 0 + default runtime_opaque := 0 + default storage_opaque := 0 + default sourced_data := 0 trust_claims := { "executables": executables, "hardware": hardware, "configuration": configuration, + "file-system": file_system, + "instance-identity": instance_identity, + "runtime-opaque": runtime_opaque, + "storage-opaque": storage_opaque, + "sourced-data": sourced_data, } + # GPUs verified by NRAS hardware := 2 if { - input.nvidia - input.nvidia["x-nvidia-gpu-attestation-report-cert-chain"]["x-nvidia-cert-status"] == "valid" - input.nvidia["x-nvidia-gpu-attestation-report-parsed"] - input.nvidia["x-nvidia-gpu-attestation-report-signature-verified"] - input.nvidia["x-nvidia-gpu-arch-check"] + input["nvidia"] + + input["nvidia"]["x-nvidia-gpu-attestation-report-cert-chain"]["x-nvidia-cert-ocsp-status"] == "good" + input["nvidia"]["x-nvidia-gpu-attestation-report-cert-chain"]["x-nvidia-cert-status"] == "valid" + + input["nvidia"]["x-nvidia-gpu-attestation-report-cert-chain-fwid-match"] + input["nvidia"]["x-nvidia-gpu-attestation-report-parsed"] + input["nvidia"]["x-nvidia-gpu-attestation-report-signature-verified"] + + input["nvidia"]["x-nvidia-gpu-arch-check"] } configuration := 2 if { - input.nvidia.secboot - input.nvidia.dbgstat == "disabled" + input["nvidia"].secboot + input["nvidia"].dbgstat == "disabled" + input["nvidia"]["x-nvidia-gpu-vbios-version"] in query_reference_value("allowed_vbios_versions") + input["nvidia"]["x-nvidia-gpu-driver-version"] in query_reference_value("allowed_driver_versions") + } + + else := 3 if { + input["nvidia"].secboot + input["nvidia"].dbgstat == "disabled" } executables := 3 if { - input.nvidia["x-nvidia-gpu-driver-rim-fetched"] - input.nvidia["x-nvidia-gpu-driver-rim-schema-validated"] - input.nvidia["x-nvidia-gpu-driver-rim-signature-verified"] - input.nvidia["x-nvidia-gpu-vbios-rim-fetched"] - input.nvidia["x-nvidia-gpu-vbios-rim-schema-validated"] - input.nvidia["x-nvidia-gpu-vbios-rim-signature-verified"] - input.nvidia.measres == "success" - } -{{- end }} \ No newline at end of file + input["nvidia"]["x-nvidia-gpu-vbios-rim-cert-chain"]["x-nvidia-cert-ocsp-status"] == "good" + input["nvidia"]["x-nvidia-gpu-vbios-rim-cert-chain"]["x-nvidia-cert-status"] == "valid" + + input["nvidia"]["x-nvidia-gpu-driver-rim-fetched"] + input["nvidia"]["x-nvidia-gpu-driver-rim-measurements-available"] + input["nvidia"]["x-nvidia-gpu-driver-rim-schema-validated"] + input["nvidia"]["x-nvidia-gpu-driver-rim-signature-verified"] + input["nvidia"]["x-nvidia-gpu-driver-rim-version-match"] + + input["nvidia"]["x-nvidia-gpu-vbios-rim-fetched"] + input["nvidia"]["x-nvidia-gpu-vbios-rim-measurements-available"] + input["nvidia"]["x-nvidia-gpu-vbios-rim-schema-validated"] + input["nvidia"]["x-nvidia-gpu-vbios-rim-signature-verified"] + input["nvidia"]["x-nvidia-gpu-vbios-rim-version-match"] + + input["nvidia"].measres == "success" + } +{{- end }} From b4462dd70813270db90cdef2a467d7e645f04813 Mon Sep 17 00:00:00 2001 From: Chris Butler Date: Thu, 28 May 2026 17:51:41 +0900 Subject: [PATCH 3/4] fix: enforce init_data check in bare metal configuration fallbacks Ensure init_data is always validated even when firmware reference values (xfam for TDX, platform config for SNP) are not available. Changes: - Bare metal TDX configuration fallback: add init_data check - Bare metal SNP configuration fallback: add init_data check Rationale: init_data validates runtime configuration (workload image, environment variables, secrets). This check must pass regardless of whether optional firmware/platform reference values are available. Security impact: Prevents attestation from succeeding with only debug checks when init_data reference values are missing. --- templates/attestation-policy.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/templates/attestation-policy.yaml b/templates/attestation-policy.yaml index 15146da..dfee848 100644 --- a/templates/attestation-policy.yaml +++ b/templates/attestation-policy.yaml @@ -216,6 +216,9 @@ data: input["tdx"] input["tdx"].quote.body.td_attributes.debug == false + + # CoCo pattern: init_data check (runtime configuration hash) + input.init_data in query_reference_value("init_data") } ##### Bare Metal SNP @@ -269,6 +272,9 @@ data: input["snp"].policy_debug_allowed == false input["snp"].policy_migrate_ma == false + + # CoCo pattern: init_data check (runtime configuration hash) + input.init_data in query_reference_value("init_data") } {{- if .Values.kbs.gpu.enabled }} default_gpu.rego: | From 7eddc80b8176664a32a0a806800cc71f9dde9181 Mon Sep 17 00:00:00 2001 From: Chris Butler Date: Thu, 28 May 2026 17:56:51 +0900 Subject: [PATCH 4/4] feat: add validated identifiers and align resource policy with upstream Align attestation and resource policies with trustee-operator v1.1.0 reference implementation for complete workload identity binding and trustworthiness-vector validation. Attestation policy changes: - Add EAR extensions with validated identifiers (container images, UIDs) - Parse init_data_claims to extract workload metadata - Bind workload identity to hardware attestation evidence - Applied to both default_cpu.rego and default_gpu.rego Resource policy changes: - Align with upstream resource-policy-restrictive.rego - Replace simple ear.status check with trustworthiness-vector validation - Check executables, configuration, and hardware claims separately - Require claims in affirming range (2-31) - Add kbs.resourcePolicy.enforceHardware flag (default: true) - When false, hardware claim failures are bypassed New values: - kbs.baremetal.enabled: false (firmware reference values feature gate) - kbs.resourcePolicy.enforceHardware: true (hardware claim enforcement) Security impact: - EAR tokens now include validated workload identifiers for audit trail - Resource policy enforces granular trust claim validation - Hardware enforcement can be disabled for environments without TCB values Upstream alignment: - attestation-policy.yaml: matches ear_default_attestation_policy_cpu.rego - resource-policy.yaml: matches resource-policy-restrictive.rego --- templates/attestation-policy.yaml | 74 +++++++++++++++++++++++++++++++ templates/resource-policy.yaml | 33 ++++++++++++-- values.yaml | 9 ++++ 3 files changed, 113 insertions(+), 3 deletions(-) diff --git a/templates/attestation-policy.yaml b/templates/attestation-policy.yaml index dfee848..acd38b2 100644 --- a/templates/attestation-policy.yaml +++ b/templates/attestation-policy.yaml @@ -66,6 +66,43 @@ data: "sourced-data": sourced_data, } + extensions := [ + {"name": "ear.trustee.identifiers", + "key": -18, + "value": { + "validated": validated_identifiers + } + } + ] + + # Validated identifiers are information that describes a workload + # that are bound to the hardware evidence via attestation + # and bound to the workload by the guest runtime. + validated_identifiers := object.union_n([ + container_images_id, + container_uids_id, + ]) + + # Use list comprehension to parse all of the images specified in the policy. + container_images := [img | + container := input["init_data_claims"]["agent_policy_claims"]["containers"][_] + img := container["OCI"]["Annotations"]["io.kubernetes.cri.image-name"] + ] + + container_images_id := {"container_images": container_images} if { + count(container_images) > 0 + } else := {} + + # UIDs + container_uids := [uid | + container := input["init_data_claims"]["agent_policy_claims"]["containers"][_] + uid := container["OCI"]["Process"]["User"]["UID"] + ] + + container_uids_id := {"container_uids": container_uids} if { + count(container_uids) > 0 + } else := {} + ##### Azure vTPM SNP executables := 3 if { input["az_snp_vtpm"] @@ -302,6 +339,43 @@ data: "sourced-data": sourced_data, } + extensions := [ + {"name": "ear.trustee.identifiers", + "key": -18, + "value": { + "validated": validated_identifiers + } + } + ] + + # Validated identifiers are information that describes a workload + # that are bound to the hardware evidence via attestation + # and bound to the workload by the guest runtime. + validated_identifiers := object.union_n([ + container_images_id, + container_uids_id, + ]) + + # Use list comprehension to parse all of the images specified in the policy. + container_images := [img | + container := input["init_data_claims"]["agent_policy_claims"]["containers"][_] + img := container["OCI"]["Annotations"]["io.kubernetes.cri.image-name"] + ] + + container_images_id := {"container_images": container_images} if { + count(container_images) > 0 + } else := {} + + # UIDs + container_uids := [uid | + container := input["init_data_claims"]["agent_policy_claims"]["containers"][_] + uid := container["OCI"]["Process"]["User"]["UID"] + ] + + container_uids_id := {"container_uids": container_uids} if { + count(container_uids) > 0 + } else := {} + # GPUs verified by NRAS hardware := 2 if { input["nvidia"] diff --git a/templates/resource-policy.yaml b/templates/resource-policy.yaml index 47c7f2a..3c2b583 100644 --- a/templates/resource-policy.yaml +++ b/templates/resource-policy.yaml @@ -11,14 +11,41 @@ data: import rego.v1 default allow = false + default hardware_failing = false allow if { - not any_not_affirming count(input.submods) > 0 + not executable_failing + not configuration_failing + not hardware_failing + } + executable_failing if { + some _, submod in input.submods + executables := submod["ear.trustworthiness-vector"]["executables"] + not in_affirming_range(executables) } - any_not_affirming if { + configuration_failing if { some _, submod in input.submods - submod["ear.status"] != "affirming" + configuration := submod["ear.trustworthiness-vector"]["configuration"] + not in_affirming_range(configuration) + } + + # Hardware trust claims are enforced by default. For TDX, no additional + # RVPS values are needed. For SNP, you must provide hardware-specific + # RVPS values (tcb_bootloader, tcb_microcode, tcb_snp, tcb_tee) from + # your environment. If these values are not available, you can disable + # hardware enforcement by setting kbs.resourcePolicy.enforceHardware: false +{{- if .Values.kbs.resourcePolicy.enforceHardware }} + hardware_failing if { + some _, submod in input.submods + hardware := submod["ear.trustworthiness-vector"]["hardware"] + not in_affirming_range(hardware) + } +{{- end }} + + in_affirming_range(val) if { + val >= 2 + val <= 31 } \ No newline at end of file diff --git a/values.yaml b/values.yaml index bb40e6c..e6d06be 100644 --- a/values.yaml +++ b/values.yaml @@ -77,6 +77,15 @@ kbs: # See docs/firmware-reference-values.md in coco-pattern for collection workflow enabled: false + # Resource policy configuration + resourcePolicy: + # Enforce hardware trust claims in resource policy + # When true: requires hardware claim >= 2 (affirming range) + # When false: allows resource access even if hardware claim fails + # Note: For SNP, hardware enforcement requires TCB reference values + # (tcb_bootloader, tcb_microcode, tcb_snp, tcb_tee) in RVPS + enforceHardware: true + # Attestation token certificate configuration # Used when secretStore.backend is "none" (cert-manager generates certs) attestation: