diff --git a/Makefile b/Makefile
index 057ceaa1..358444c4 100644
--- a/Makefile
+++ b/Makefile
@@ -5,6 +5,10 @@
include Makefile-common
##@ Key Management
+.PHONY: gen-secrets
+gen-secrets: ## Generate KBS keys, sealed-secrets signing key, and values-secret template
+ @scripts/gen-secrets.sh
+
.PHONY: cache-keys
cache-keys: ## Download Red Hat signing keys from official sources to ~/.coco-pattern/
@mkdir -p ~/.coco-pattern
@@ -99,6 +103,14 @@ dcap-offline-provision: ## Full DCAP offline provisioning workflow (collect coll
$(MAKE) collect-dcap-collateral
$(MAKE) load-secrets
+.PHONY: check-pck-expiry
+check-pck-expiry: ## Check expiry of PCK cache secrets and platform data (requires oc login)
+ @scripts/check-pck-expiry.sh
+
+.PHONY: check-collateral-expiry
+check-collateral-expiry: ## Check expiry of TDX DCAP collateral in trustee-operator-system (requires oc login)
+ @scripts/check-collateral-expiry.sh
+
##@ AMD SEV-SNP VCEK Provisioning
.PHONY: snp-collect-vcek-urls
@@ -191,6 +203,16 @@ argocd-login: ## Extract ArgoCD credentials from cluster and log in with argocd
fi
##@ Hardware Detection
+.PHONY: get-pccs-node
+get-pccs-node: ## Detect a node with Intel TDX support for PCCS deployment (requires KUBECONFIG or oc login)
+ @NODE=$$(oc get nodes -l intel.feature.node.kubernetes.io/tdx=true \
+ -o jsonpath='{.items[0].metadata.name}' 2>/dev/null); \
+ if [ -z "$$NODE" ]; then \
+ echo "ERROR: No TDX-capable nodes found" >&2; \
+ exit 1; \
+ fi; \
+ echo "$$NODE"
+
.PHONY: detect-hardware
detect-hardware: ## Detect hardware profile from cluster nodes (requires KUBECONFIG or oc login)
@echo "Detecting hardware profile from cluster nodes..."
diff --git a/README.md b/README.md
index 57cca15a..65e2447c 100644
--- a/README.md
+++ b/README.md
@@ -96,8 +96,8 @@ For air-gapped bare metal environments, see [`airgap/DEPLOY-RUNBOOK.md`](airgap/
These scripts generate the cryptographic material and attestation reference values needed by Trustee. Run them once before your first deployment.
-1. `bash scripts/gen-secrets.sh` — generates KBS key pairs, sealed-secrets signing keys, and copies `values-secret.yaml.template` to `~/values-secret-coco-pattern.yaml`
-2. Collect attestation reference values (requires `podman`, `yq`, `jq`, and `~/pull-secret.json`):
+1. `make gen-secrets` — generates KBS key pairs, sealed-secrets signing keys, and copies `values-secret.yaml.template` to `~/values-secret-coco-pattern.yaml`
+2. Collect attestation reference values (requires `veritas` — `pip install "osc-veritas[snp]==0.1.3rc1"` —, `cosign` >= 2.0 for Azure, `yq`, `jq`, and `~/pull-secret.json`). By default this collects and merges reference values for **both TDX and SNP**:
- **Azure:** `make collect-azure-refvals` — pulls PCR measurements from the dm-verity image via veritas. Saves to `~/.coco-pattern/measurements.json`.
- **Bare metal:** `make collect-firmware-refvals` — computes firmware measurements from OCP release artifacts via veritas. Saves to `~/.coco-pattern/firmware-reference-values.json`. For bare metal, also uncomment the `firmwareReferenceValues` section in `~/values-secret-coco-pattern.yaml`.
- See [docs/firmware-reference-values.md](docs/firmware-reference-values.md) for detailed workflow and options.
diff --git a/docs/firmware-reference-values.md b/docs/firmware-reference-values.md
index efbbc936..0f225f02 100644
--- a/docs/firmware-reference-values.md
+++ b/docs/firmware-reference-values.md
@@ -13,14 +13,20 @@ Reference values are cryptographic measurements of the Trusted Computing Base (T
| Bare metal | TDX | mr_td, rtmr_1, rtmr_2, xfam | SHA-384 |
| Bare metal | SNP | snp_launch_measurement | SHA-384 |
-Both platforms use the [veritas](https://github.com/confidential-devhub/veritas) tool, packaged in the `quay.io/openshift_sandboxed_containers/coco-tools` container. No cluster access is required — veritas computes expected measurements from OCP release artifacts or the dm-verity image.
+Both platforms use the [veritas](https://github.com/confidential-devhub/veritas) tool. No cluster access is required — veritas computes expected measurements from OCP release artifacts or the dm-verity image.
+
+By default, `collect-firmware-refvals.sh` collects reference values for **both TDX and SNP and merges them** into a single output, so one RVPS ConfigMap supports heterogeneous (mixed-TEE) deployments out of the box — see [Multi-Architecture Collection](#multi-architecture-collection) below.
## Prerequisites
-- `podman` installed and running
+- `veritas` installed on the host: `pip install "osc-veritas[snp]==0.1.3rc1"`
+- `cosign` >= 2.0 — Azure only, used by veritas to verify the Red Hat dm-verity image signature:
- `yq` and `jq` installed
- OpenShift pull secret at `~/pull-secret.json`
- For bare metal: OCP version of your cluster (auto-detected if `oc` is logged in)
+- For bare metal TDX: `tdx-measure` (`cargo install --git https://github.com/virtee/tdx-measure tdx-measure-cli`) — collection continues with a warning if absent, but TDX RTMR values will be incomplete
+
+**Why host-installed instead of the `coco-tools` container**: the container image (`quay.io/openshift_sandboxed_containers/coco-tools:0.5.1`) is pinned to an older veritas release that lacks `--skip-tlog`, which is needed to avoid the Azure verification failures described below. This is a deliberate, temporary deviation — see the tracking issue referenced in [Known Limitations](#known-limitations) for moving back to the container once a `coco-tools` release ships with a newer veritas.
## Collecting Reference Values
@@ -36,7 +42,9 @@ make collect-azure-refvals
Output: `~/.coco-pattern/measurements.json`
-Veritas pulls the `osc-dm-verity-image` from the Red Hat registry, verifies its signature via cosign, and extracts pre-computed PCR values. These are the same values previously collected by `scripts/get-pcr.sh`.
+Veritas pulls the `osc-dm-verity-image` from the Red Hat registry, verifies its signature via cosign, and extracts pre-computed PCR values.
+
+**Signature verification and Rekor**: by default this script passes `--skip-tlog` to veritas for the Azure branch. Red Hat signs and logs these images against its own private Rekor instance, which has been unreliable (repeated `curl` failures fetching the Rekor public key). `--skip-tlog` still verifies the cosign signature against Red Hat's public key — it only skips the transparency-log lookup, which cannot succeed against a different Rekor server anyway (the log entry only exists on Red Hat's instance, so pointing at a different one, e.g. public Sigstore, does not work as a substitute). Pass `--verify-tlog` to opt back into full transparency-log verification if needed.
### Bare Metal
@@ -47,7 +55,7 @@ make collect-firmware-refvals
# Or with explicit OCP version:
./scripts/collect-firmware-refvals.sh --ocp-version 4.20.18
-# Specify TEE type (default: tdx):
+# Collect a single TEE only (default is both, see below):
./scripts/collect-firmware-refvals.sh --tee snp --ocp-version 4.20.18
```
@@ -66,9 +74,18 @@ Options:
-p, --pull-secret Pull secret file (default: ~/pull-secret.json)
-v, --ocp-version OCP version (baremetal; default: auto-detect)
--osc-version OSC operator version (azure; default: auto-detect)
- -t, --tee TEE type (default: tdx)
+ -t, --tee TEE type (default: both -- collects and merges both)
+ --verify-tlog Azure only: verify against Rekor instead of --skip-tlog
```
+## Multi-Architecture Collection
+
+By default (`--tee both`, or by omitting `--tee` entirely), this script runs veritas **twice** — once per TEE — and merges the resulting reference values into a single output file, for both the Azure and bare-metal branches. This supports heterogeneous/mixed-TEE deployments (for example, a bare-metal hub that verifies evidence from both TDX and SNP spokes, per `values-baremetal-hub.yaml`'s `kbs.tdx.enabled` + `kbs.snp.enabled`) without any manual merge step.
+
+The merge is a plain JSON key union: TDX and SNP reference values use disjoint, TEE-prefixed key names (`tdx_*`/`mr_td`/`rtmr_*` vs `snp_*`/`snp_launch_measurement`), so there's no collision risk, and this matches how `trustee-chart`'s RVPS template already consumes the `firmwareReferenceValues`/`pcrStash` secrets (it passes through whichever TEE-specific keys are present).
+
+Pass `--tee tdx` or `--tee snp` explicitly to collect a single architecture only (faster, useful for single-cluster deployments pinned to one hardware profile).
+
## Loading Values to Vault
### Step 1: Configure values-secret.yaml
@@ -149,13 +166,22 @@ The following table maps what veritas provides vs what the attestation policy ch
| TEE type | Policy hardcoded | - | Policy hardcoded | - |
| Init data | Computed by imperative job | Computed by imperative job | Computed by imperative job | Computed by imperative job |
-## Known Limitations
+## Azure "External" Reference Values (kbs.azure.*)
+
+Azure SEV-SNP also has a second, separate set of reference values that veritas does **not** collect: `trustee-chart`'s `kbs.azure.*` block (`snpLaunchMeasurement`, `smtEnabled`, `tsmeEnabled`, `abiMajor`, `abiMinor`, `singleSocket`, `smtAllowed`). These are static Azure-platform/VM-series constants (describing the SEV-SNP policy Azure enforces for a given confidential VM series), not measurements derived from any artifact veritas can pull and hash.
+
+coco-pattern pins these explicitly in `overrides/values-trustee-azure.yaml` (wired into `values-azure.yaml`) rather than silently relying on `trustee-chart`'s own defaults, so the values are visible/versioned in this repository. See that file's comments for the current VM-series mapping and for how to update them if you change `global.azure.defaultVMFlavour` to a series with different platform behavior.
-As of the coco-tools 1.12 container:
+**Note**: as of the current `trustee-chart` attestation policy, the Rego checks that would compare evidence against these values are commented out upstream ("Azure manages TCB validation"), so they are not currently enforced — they're pinned here so they're ready to take effect if/when upstream re-enables those checks, and so the values are documented and auditable rather than hidden inside a dependency chart's defaults.
+
+There is currently no automated way to collect/verify these values against a real deployment. A `snpguest`-based collection script (SSH into the podvm with `enableSSHDebug`, run `snpguest report --openhcl`, parse the SNP attestation report) is tracked as a follow-up.
+
+## Known Limitations
1. **TCB version numbers** — Not collected for SNP (reported_tcb_bootloader, tcb_microcode, etc.). Hardware trust claim fallback rules handle this.
-2. **SNP policy configuration** — SMT, TSME, guest ABI not output. Configuration fallback rules check debug disabled + init_data.
+2. **Azure SNP platform configuration** — SMT, TSME, guest ABI are not collected by veritas at all (see [Azure "External" Reference Values](#azure-external-reference-values-kbsazure) above); bare-metal SNP configuration fallback rules check debug disabled + init_data instead.
3. **rtmr_2 variants** — Veritas generates multiple cmdline variants (nr_cpus=1..N). If the actual cmdline differs, the policy falls back to the rtmr_1-only rule (executables: 4 instead of 3).
+4. **Host-installed veritas instead of the `coco-tools` container** — temporary, until `coco-tools` publishes a release pinning a newer veritas with `--skip-tlog`/`--cosign-pub-key`/`--mirror-registry` support. See the tracking issue for details and for moving back to the container-based approach.
## Security Considerations
diff --git a/overrides/values-trustee-azure.yaml b/overrides/values-trustee-azure.yaml
new file mode 100644
index 00000000..702cb688
--- /dev/null
+++ b/overrides/values-trustee-azure.yaml
@@ -0,0 +1,45 @@
+# Azure SEV-SNP platform configuration reference values, pinned explicitly in
+# coco-pattern rather than silently inherited from trustee-chart's own
+# values.yaml defaults.
+#
+# These describe the SEV-SNP policy Azure enforces for confidential VMs of a
+# given series. They are NOT derived from the workload image -- they are
+# Azure platform constants for the VM type -- and are NOT collected by
+# 'make collect-azure-refvals' (veritas does not compute these; see
+# docs/firmware-reference-values.md "Known Limitations").
+#
+# Current values below match Azure DCasv5-series VMs (this pattern's default
+# VM flavour, see global.azure.defaultVMFlavour in values-global.yaml):
+#
+# VM Series | SMT | TSME | ABI Minor | Notes
+# ----------------|-----|------|-----------|------
+# DCasv5 (Genoa) | true| true | 31 | Standard CoCo peer-pod VMs (default)
+# DCadsv5 (Genoa) | true| true | 31 | With local NVMe
+# ECasv5 (Genoa) | true| true | 31 | Memory-optimized
+# DCesv5 (Milan) | true| true | 31 | Earlier generation, may differ
+#
+# If you change global.azure.defaultVMFlavour to a series with different
+# platform behaviour, or if Azure updates its confidential VM firmware,
+# update the values below to match. There is currently no automated way to
+# collect them (see the tracking issue for a snpguest-based collection
+# script) -- the only documented method today is: check the trustee logs
+# (RUST_LOG=debug is enabled by default on the KBS pod) for the actual
+# values reported by the VM on attestation failure, and update these to
+# match.
+#
+# NOTE: as of trustee-chart's current attestation-policy.yaml, the Rego
+# checks that would compare evidence against these values (smt_enabled,
+# tsme_enabled, abi_major/minor, single_socket, smt_allowed) are commented
+# out upstream ("Azure manages TCB validation" / "Azure platform
+# constants"), so these are not currently enforced. They are pinned here
+# so the values are visible/versioned in this repo, and ready to take
+# effect if/when upstream re-enables those policy checks.
+kbs:
+ azure:
+ snpLaunchMeasurement: "qnydpVwThuWxZTsSWXi+2ns/laha6w+d2723g84FaijJ0CHaI5w0pYw6ZXZUJw7v"
+ smtEnabled: "true"
+ tsmeEnabled: "true"
+ abiMajor: "0"
+ abiMinor: "31"
+ singleSocket: "false"
+ smtAllowed: "true"
diff --git a/rhdp/README.md b/rhdp/README.md
index b8f9d711..01ec5b2e 100644
--- a/rhdp/README.md
+++ b/rhdp/README.md
@@ -5,7 +5,9 @@ The scripts in this directory help users of that platform automate deployments.
## Prerequisites
-- `podman` installed and running (used for reference value collection)
+- `podman` installed and running (used by `pattern.sh` itself)
+- `veritas` installed on the host (used for reference value collection): `pip install "osc-veritas[snp]==0.1.3rc1"`
+- `cosign` >= 2.0 (used by veritas for Azure image signature verification)
- `yq`, `jq` installed
- OpenShift pull secret (default: `~/pull-secret.json`, override with `PULL_SECRET` — see below)
- An SSH key pair (default: auto-detected, preferring Ed25519 — override with `SSH_PUBLIC_KEY` — see below)
diff --git a/scripts/collect-firmware-refvals.sh b/scripts/collect-firmware-refvals.sh
index 3ea1c1e2..2a948995 100755
--- a/scripts/collect-firmware-refvals.sh
+++ b/scripts/collect-firmware-refvals.sh
@@ -1,11 +1,26 @@
#!/usr/bin/env bash
-# Collect firmware reference values using veritas container (runs locally, no cluster pods)
+# Collect firmware reference values using the veritas CLI (runs locally, no cluster pods)
#
# This script:
-# 1. Runs veritas via podman container to compute firmware measurements
+# 1. Runs veritas (installed on the host) to compute firmware measurements
# 2. Extracts reference values from OCP release artifacts (baremetal) or
# dm-verity image (azure)
-# 3. Saves to ~/.coco-pattern/ for loading into Vault via 'make load-secrets'
+# 3. By default collects for BOTH TDX and SNP and merges the results, so a
+# single output supports heterogeneous (mixed-TEE) deployments
+# 4. Saves to ~/.coco-pattern/ for loading into Vault via 'make load-secrets'
+#
+# veritas is installed on the host via pip (see Prerequisites below) rather
+# than run in a container. The container image this script used to run
+# (quay.io/openshift_sandboxed_containers/coco-tools) is pinned to an older
+# veritas release that lacks --skip-tlog, which is needed to avoid repeated
+# failures against Red Hat's private Rekor instance for Azure image signature
+# verification. See the tracking issue for moving back to the container once
+# a coco-tools release ships with a newer veritas.
+#
+# Prerequisites:
+# pip install "osc-veritas[snp]==0.1.3rc1"
+# cosign >= 2.0 (Azure only; https://docs.sigstore.dev/cosign/system_config/installation/)
+# tdx-measure (baremetal TDX only; cargo install --git https://github.com/virtee/tdx-measure tdx-measure-cli)
#
# Usage:
# ./scripts/collect-firmware-refvals.sh [OPTIONS]
@@ -16,7 +31,11 @@
# -p, --pull-secret Pull secret file (default: ~/pull-secret.json)
# -v, --ocp-version OCP version (baremetal; default: auto-detect)
# --osc-version OSC operator version (azure; default: auto-detect)
-# -t, --tee TEE type (default: tdx)
+# -t, --tee TEE type (default: both -- collects and merges both)
+# --verify-tlog Azure only: verify against the Rekor transparency
+# log instead of the default --skip-tlog. Only the
+# signature check is skipped by default, not
+# overall image verification.
# -h, --help Show this help message
set -euo pipefail
@@ -27,8 +46,9 @@ OUTPUT_FILE=""
PULL_SECRET="${HOME}/pull-secret.json"
OCP_VERSION=""
OSC_VERSION=""
-TEE="tdx"
-CONTAINER_IMAGE="quay.io/openshift_sandboxed_containers/coco-tools:0.5.1"
+TEE="both"
+SKIP_TLOG=true
+VERITAS_PIP_SPEC='osc-veritas[snp]==0.1.3rc1'
# Parse arguments
while [[ $# -gt 0 ]]; do
@@ -57,8 +77,12 @@ while [[ $# -gt 0 ]]; do
TEE="$2"
shift 2
;;
+ --verify-tlog)
+ SKIP_TLOG=false
+ shift
+ ;;
-h|--help)
- sed -n '2,18p' "$0" | sed 's/^# //'
+ sed -n '2,39p' "$0" | sed 's/^# \?//'
exit 0
;;
*)
@@ -75,6 +99,15 @@ if [[ "$PLATFORM" != "baremetal" && "$PLATFORM" != "azure" ]]; then
exit 1
fi
+# Validate TEE
+case "$TEE" in
+ tdx|snp|both) ;;
+ *)
+ echo "Error: --tee must be 'tdx', 'snp', or 'both'" >&2
+ exit 1
+ ;;
+esac
+
# Set default output file based on platform
if [ -z "$OUTPUT_FILE" ]; then
if [ "$PLATFORM" = "azure" ]; then
@@ -85,9 +118,33 @@ if [ -z "$OUTPUT_FILE" ]; then
fi
# Prerequisites check
-command -v podman >/dev/null 2>&1 || { echo "Error: podman is required but not installed." >&2; exit 1; }
+if ! command -v veritas >/dev/null 2>&1; then
+ echo "Error: veritas is required but not installed." >&2
+ echo " Install with: pip install \"${VERITAS_PIP_SPEC}\"" >&2
+ exit 1
+fi
python3 -c "import yaml" 2>/dev/null || { echo "Error: python3 with PyYAML module is required. Install with: pip3 install pyyaml" >&2; exit 1; }
+# cosign is only used by veritas for Azure image signature verification.
+# Bare metal verifies via 'oc adm release info --verify' instead.
+if [ "$PLATFORM" = "azure" ]; then
+ if ! command -v cosign >/dev/null 2>&1; then
+ echo "Error: cosign is required for Azure signature verification but was not found." >&2
+ echo " Install cosign >= 2.0: https://docs.sigstore.dev/cosign/system_config/installation/" >&2
+ exit 1
+ fi
+ COSIGN_RAW_VERSION=$(cosign version 2>/dev/null | grep -oE 'GitVersion:[[:space:]]*v?[0-9]+\.[0-9]+' | grep -oE '[0-9]+\.[0-9]+' | head -1)
+ if [ -z "$COSIGN_RAW_VERSION" ]; then
+ echo "WARNING: could not determine cosign version; veritas requires cosign >= 2.0" >&2
+ else
+ COSIGN_MAJOR="${COSIGN_RAW_VERSION%%.*}"
+ if [ "$COSIGN_MAJOR" -lt 2 ]; then
+ echo "Error: cosign >= 2.0 is required (found: $COSIGN_RAW_VERSION)" >&2
+ exit 1
+ fi
+ fi
+fi
+
# Check pull secret exists
if [ ! -f "$PULL_SECRET" ]; then
echo "Error: Pull secret not found at $PULL_SECRET" >&2
@@ -96,7 +153,8 @@ if [ ! -f "$PULL_SECRET" ]; then
fi
# Build version args and resolve version for display
-VERSION_ARGS=""
+VERSION_ARG_NAME=""
+VERSION_ARG_VALUE=""
VERSION_DISPLAY=""
if [ "$PLATFORM" = "azure" ]; then
if [ -z "$OSC_VERSION" ]; then
@@ -116,7 +174,8 @@ if [ "$PLATFORM" = "azure" ]; then
OSC_VERSION="latest"
fi
fi
- VERSION_ARGS="--image-tag $OSC_VERSION"
+ VERSION_ARG_NAME="--image-tag"
+ VERSION_ARG_VALUE="$OSC_VERSION"
VERSION_DISPLAY="OSC $OSC_VERSION"
else
if [ -z "$OCP_VERSION" ]; then
@@ -130,49 +189,35 @@ else
fi
echo "Detected OCP version: $OCP_VERSION"
fi
- VERSION_ARGS="--ocp-version $OCP_VERSION"
+ VERSION_ARG_NAME="--ocp-version"
+ VERSION_ARG_VALUE="$OCP_VERSION"
VERSION_DISPLAY="OCP $OCP_VERSION"
fi
+if [ "$TEE" = "both" ]; then
+ TEES_TO_RUN=(tdx snp)
+else
+ TEES_TO_RUN=("$TEE")
+fi
+
echo "=========================================="
echo "Firmware Reference Value Collection"
echo "=========================================="
echo "Platform: $PLATFORM"
echo "Version: $VERSION_DISPLAY"
-echo "TEE Type: $TEE"
+echo "TEE Type(s): ${TEES_TO_RUN[*]}"
echo "Output file: $OUTPUT_FILE"
echo ""
-# Create temp directory for output
+# Create temp directory for per-TEE veritas output and extracted JSON
TEMP_DIR=$(mktemp -d)
-trap "rm -rf $TEMP_DIR" EXIT
-
-# Build veritas command
-VERITAS_CMD="veritas --platform $PLATFORM --tee $TEE $VERSION_ARGS --authfile /pull-secret.json"
-
-# Add baremetal-specific flags
-if [ "$PLATFORM" = "baremetal" ]; then
- VERITAS_CMD="$VERITAS_CMD --hw-xfam-allow x87 --hw-xfam-allow sse --hw-xfam-allow avx"
-fi
-
-VERITAS_CMD="$VERITAS_CMD -o /output"
-
-echo "Running veritas to compute firmware measurements..."
-echo "(This may take 2-3 minutes to download and process artifacts)"
-echo ""
-
-podman run --rm \
- -v "${PULL_SECRET}:/pull-secret.json:ro,z" \
- -v "${TEMP_DIR}:/output:z" \
- "$CONTAINER_IMAGE" \
- $VERITAS_CMD
+trap 'rm -rf "$TEMP_DIR"' EXIT
-# Extract reference values from ConfigMap YAML (supports both old and new veritas formats)
-echo ""
-echo "Extracting reference values..."
-mkdir -p "$(dirname "$OUTPUT_FILE")"
-
-python3 -c "
+extract_reference_values() {
+ # Extract reference values from a veritas-produced ConfigMap YAML into a
+ # plain JSON dict (supports both old and new veritas RVPS formats).
+ local yaml_path="$1"
+ python3 -c "
import yaml, json, base64, sys
with open(sys.argv[1]) as f:
@@ -182,7 +227,7 @@ data = doc.get('data', {})
result = {}
if 'reference_value' in data:
- # New format (veritas 0.5.1+ / coco-tools 0.5.1): JSON object with base64-encoded RVPS entries
+ # New format (veritas 0.1.x / Trustee 1.2): JSON object with base64-encoded RVPS entries
raw = data['reference_value']
entries = json.loads(raw) if isinstance(raw, str) else raw
for claim_name, b64_value in entries.items():
@@ -202,7 +247,64 @@ else:
sys.exit(1)
print(json.dumps(result, indent=2))
-" "$TEMP_DIR/rvps-reference-values.yaml" > "$OUTPUT_FILE"
+" "$yaml_path"
+}
+
+PER_TEE_JSON_FILES=()
+
+for tee in "${TEES_TO_RUN[@]}"; do
+ OUT_DIR="${TEMP_DIR}/${tee}"
+ mkdir -p "$OUT_DIR"
+
+ VERITAS_ARGS=(--platform "$PLATFORM" --tee "$tee" "$VERSION_ARG_NAME" "$VERSION_ARG_VALUE" --authfile "$PULL_SECRET")
+
+ # XFAM CPU features only matter for TDX; only add for the tdx run to
+ # avoid veritas's harmless-but-noisy "only relevant for TDX" warning.
+ if [ "$PLATFORM" = "baremetal" ] && [ "$tee" = "tdx" ]; then
+ VERITAS_ARGS+=(--hw-xfam-allow x87 --hw-xfam-allow sse --hw-xfam-allow avx)
+ fi
+
+ # cosign/Rekor verification only applies to the Azure branch. Default to
+ # --skip-tlog: Red Hat signs and logs these images against its own
+ # private Rekor instance, which has been unreliable. --skip-tlog still
+ # verifies the cosign signature against Red Hat's public key -- it only
+ # skips the transparency-log lookup, which cannot succeed against a
+ # different Rekor server anyway (the log entry only exists on Red Hat's
+ # instance). Pass --verify-tlog to opt back into full verification.
+ if [ "$PLATFORM" = "azure" ] && [ "$SKIP_TLOG" = true ]; then
+ VERITAS_ARGS+=(--skip-tlog)
+ fi
+
+ VERITAS_ARGS+=(-o "$OUT_DIR")
+
+ echo "Running veritas (tee=$tee)..."
+ echo "(This may take 2-3 minutes to download and process artifacts)"
+ veritas "${VERITAS_ARGS[@]}"
+ echo ""
+
+ TEE_JSON="${TEMP_DIR}/${tee}.json"
+ extract_reference_values "${OUT_DIR}/rvps-reference-values.yaml" > "$TEE_JSON"
+ PER_TEE_JSON_FILES+=("$TEE_JSON")
+done
+
+echo "Merging reference values from: ${TEES_TO_RUN[*]}..."
+mkdir -p "$(dirname "$OUTPUT_FILE")"
+
+python3 -c "
+import json, sys
+
+result = {}
+for path in sys.argv[1:]:
+ with open(path) as f:
+ data = json.load(f)
+ for key, value in data.items():
+ if key in result and result[key] != value:
+ print(f\"WARNING: key '{key}' differs between TEE runs; keeping the first value seen\", file=sys.stderr)
+ continue
+ result[key] = value
+
+print(json.dumps(result, indent=2))
+" "${PER_TEE_JSON_FILES[@]}" > "$OUTPUT_FILE"
echo ""
echo "Collected firmware reference values:"
diff --git a/scripts/get-pccs-node.sh b/scripts/get-pccs-node.sh
deleted file mode 100755
index 32b4313b..00000000
--- a/scripts/get-pccs-node.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/usr/bin/env bash
-# Detects a node with Intel TDX support for PCCS deployment.
-# Usage: bash scripts/get-pccs-node.sh
-NODE=$(oc get nodes -l intel.feature.node.kubernetes.io/tdx=true \
- -o jsonpath='{.items[0].metadata.name}' 2>/dev/null)
-if [ -z "$NODE" ]; then
- echo "ERROR: No TDX-capable nodes found" >&2
- exit 1
-fi
-echo "$NODE"
diff --git a/scripts/get-pcr.sh b/scripts/get-pcr.sh
deleted file mode 100755
index b509edbd..00000000
--- a/scripts/get-pcr.sh
+++ /dev/null
@@ -1,122 +0,0 @@
-#!/usr/bin/env bash
-set -e
-
-# Script to retrieve the sandboxed container operator CSV for the current clusterGroup
-# using the pull secret for authentication if needed.
-
-# 1. Locate pull secret
-PULL_SECRET_PATH="${HOME}/pull-secret.json"
-if [ ! -f "$PULL_SECRET_PATH" ]; then
- if [ -n "${PULL_SECRET}" ]; then
- PULL_SECRET_PATH="${PULL_SECRET}"
- if [ ! -f "$PULL_SECRET_PATH" ]; then
- echo "ERROR: Pull secret file not found at path specified in PULL_SECRET: $PULL_SECRET_PATH"
- exit 1
- fi
- else
- echo "ERROR: Pull secret not found at ~/pull-secret.json"
- echo "Please either place your pull secret at ~/pull-secret.json or set the PULL_SECRET environment variable"
- exit 1
- fi
-fi
-
-echo "Using pull secret: $PULL_SECRET_PATH"
-
-# 2. Check for required tools
-if ! command -v yq &> /dev/null; then
- echo "ERROR: yq is required but not installed"
- echo "Please install yq: https://github.com/mikefarah/yq#install"
- exit 1
-fi
-
-if ! command -v skopeo &> /dev/null; then
- echo "ERROR: skopeo is required but not installed"
- echo "Please install skopeo: https://github.com/containers/skopeo/blob/main/install.md"
- exit 1
-fi
-
-if ! command -v podman &> /dev/null; then
- echo "ERROR: podman is required but not installed"
- echo "Please install podman: https://podman.io/docs/installation"
- exit 1
-fi
-
-# 3. Check values-global.yaml exists
-if [ ! -f "values-global.yaml" ]; then
- echo "ERROR: values-global.yaml not found in current directory"
- echo "Please run this script from the root directory of the project"
- exit 1
-fi
-
-# 4. Get the active clusterGroupName from values-global.yaml
-CLUSTER_GROUP_NAME=$(yq eval '.main.clusterGroupName' values-global.yaml)
-
-if [ -z "$CLUSTER_GROUP_NAME" ] || [ "$CLUSTER_GROUP_NAME" == "null" ]; then
- echo "ERROR: Could not determine clusterGroupName from values-global.yaml"
- echo "Expected: main.clusterGroupName to be set"
- exit 1
-fi
-
-echo "Active clusterGroup: $CLUSTER_GROUP_NAME"
-
-# 5. Locate the values file for the active clusterGroup
-VALUES_FILE="values-${CLUSTER_GROUP_NAME}.yaml"
-
-if [ ! -f "$VALUES_FILE" ]; then
- echo "ERROR: Values file for clusterGroup not found: $VALUES_FILE"
- exit 1
-fi
-
-# 6. Get the sandboxed container operator CSV from the clusterGroup values
-SANDBOX_CSV=$(yq eval '.clusterGroup.subscriptions.sandbox.csv' "$VALUES_FILE")
-
-if [ -z "$SANDBOX_CSV" ] || [ "$SANDBOX_CSV" == "null" ]; then
- echo "WARNING: No sandboxed container operator CSV found in $VALUES_FILE"
- echo "The subscription clusterGroup.subscriptions.sandbox.csv is not defined"
- exit 0
-fi
-
-# Extract version from CSV (e.g., "sandboxed-containers-operator.v1.12.0" -> "1.12.0")
-# Remove everything up to and including ".v"
-SANDBOX_VERSION="${SANDBOX_CSV##*.v}"
-
-echo "Sandboxed container operator CSV: $SANDBOX_CSV"
-echo "Version: $SANDBOX_VERSION"
-# alternatively, use the operator-version tag.
-# OSC_VERSION=1.12.0
-VERITY_IMAGE=registry.redhat.io/openshift-sandboxed-containers/osc-dm-verity-image
-
-TAG=$(skopeo inspect --authfile $PULL_SECRET_PATH docker://${VERITY_IMAGE}:${SANDBOX_VERSION} | jq -r .Digest)
-
-IMAGE=${VERITY_IMAGE}@${TAG}
-
-echo "IMAGE: $IMAGE"
-
-curl -L https://tuf-default.apps.rosa.rekor-prod.2jng.p3.openshiftapps.com/targets/rekor.pub -o rekor.pub
-curl -L https://security.access.redhat.com/data/63405576.txt -o cosign-pub-key.pem
-# export REGISTRY_AUTH_FILE=${PULL_SECRET_PATH}
-# echo "REGISTRY_AUTH_FILE: $REGISTRY_AUTH_FILE"
-# export SIGSTORE_REKOR_PUBLIC_KEY=${PWD}/rekor.pub
-# echo "SIGSTORE_REKOR_PUBLIC_KEY: $SIGSTORE_REKOR_PUBLIC_KEY"
-# cosign verify --key cosign-pub-key.pem --output json --rekor-url=https://rekor-server-default.apps.rosa.rekor-prod.2jng.p3.openshiftapps.com $IMAGE > cosign_verify.log
-
-
-# Ensure output directory exists
-mkdir -p ~/.coco-pattern
-
-# Clean up any existing measurement files
-rm -f ~/.coco-pattern/measurements-raw.json ~/.coco-pattern/measurements.json
-
-# Download the measurements using podman cp (works on macOS with remote podman)
-podman pull --authfile $PULL_SECRET_PATH $IMAGE
-
-cid=$(podman create --entrypoint /bin/true $IMAGE)
-echo "CID: ${cid}"
-podman cp $cid:/image/measurements.json ~/.coco-pattern/measurements-raw.json
-podman rm $cid
-
-# Trim leading "0x" from all measurement values
-jq 'walk(if type == "string" and startswith("0x") then .[2:] else . end)' \
- ~/.coco-pattern/measurements-raw.json > ~/.coco-pattern/measurements.json
-
-echo "Measurements saved to ~/.coco-pattern/measurements.json (0x prefixes removed)"
\ No newline at end of file
diff --git a/values-azure.yaml b/values-azure.yaml
index 326eb181..39b6c865 100644
--- a/values-azure.yaml
+++ b/values-azure.yaml
@@ -90,6 +90,7 @@ clusterGroup:
chartVersion: 0.9.*
extraValueFiles:
- '/overrides/values-trustee.yaml'
+ - '/overrides/values-trustee-azure.yaml'
overrides:
- name: global.coco.secured
value: "true"