Deploy on GCP Confidential VMs¶
This page is for operators who want to run cMCP on Google Cloud with hardware protection switched on. Google Cloud Confidential VMs run on Intel TDX or AMD SEV-SNP processors, which keep the VM's memory sealed off from the cloud host and can produce a signed hardware report (an attestation) of the software that started. Following these steps, each signed session record cMCP produces (a TRACE claim) carries that hardware report instead of a software-only placeholder.
What you'll learn¶
- Which GCP machine types give you Intel TDX
- How to provision a Confidential VM with the gcloud CLI
- How to install and configure cMCP for TDX
- What to verify in the TRACE claim to confirm hardware attestation is live
Prerequisites¶
- Google Cloud SDK installed and authenticated (
gcloud auth login) - A GCP project with Confidential Computing API enabled
- A GCP project with billing enabled and Confidential VM quota
Enable the required APIs:
Choose your hardware¶
GCP Confidential VMs offer two kinds of protected hardware (TEE, trusted execution environment), plus an older option:
| TEE type | GCP machine type | provider value | Notes |
|---|---|---|---|
| Intel TDX | C3 (c3-standard-*, c3-highmem-*) | tdx | Supported in select zones |
| AMD SEV-SNP | N2D (n2d-standard-*) | sev-snp | Wider zone availability |
| AMD SEV (legacy) | N2D with --confidential-compute-type=SEV | tpm (vTPM) | Use SEV-SNP or TDX for new deployments |
C3 with TDX gives the strongest guarantee on GCP. N2D with SEV-SNP is available in more zones.
Check which zones offer C3 with TDX in your project:
Provision the VM¶
Intel TDX (C3)¶
PROJECT_ID=$(gcloud config get-value project)
ZONE=us-central1-a
gcloud compute instances create cmcp-gateway \
--project=$PROJECT_ID \
--zone=$ZONE \
--machine-type=c3-standard-4 \
--confidential-compute-type=TDX \
--on-host-maintenance=TERMINATE \
--image-family=ubuntu-2404-lts-amd64 \
--image-project=ubuntu-os-cloud \
--boot-disk-size=20GB \
--shielded-secure-boot \
--shielded-vtpm \
--shielded-integrity-monitoring \
--tags=cmcp-gateway
AMD SEV-SNP (N2D)¶
gcloud compute instances create cmcp-gateway \
--project=$PROJECT_ID \
--zone=$ZONE \
--machine-type=n2d-standard-4 \
--confidential-compute-type=SEV_SNP \
--on-host-maintenance=TERMINATE \
--image-family=ubuntu-2404-lts-amd64 \
--image-project=ubuntu-os-cloud \
--boot-disk-size=20GB \
--shielded-secure-boot \
--shielded-vtpm \
--tags=cmcp-gateway
Open the gateway port¶
gcloud compute firewall-rules create allow-cmcp \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp:8443 \
--target-tags=cmcp-gateway \
--source-ranges=0.0.0.0/0
Get the external IP:
gcloud compute instances describe cmcp-gateway \
--zone=$ZONE \
--format="get(networkInterfaces[0].accessConfigs[0].natIP)"
Install cMCP on the VM¶
VM_IP=$(gcloud compute instances describe cmcp-gateway \
--zone=$ZONE \
--format="get(networkInterfaces[0].accessConfigs[0].natIP)")
gcloud compute ssh azureuser@cmcp-gateway --zone=$ZONE
# On the VM:
sudo apt-get update -qq && sudo apt-get install -y python3-pip
pip install cmcp-runtime
cmcp --version
Configure for TDX¶
Confirm the gateway can reach the hardware. On a GCP TDX VM the TDX guest device, which also exposes the RTMR (Runtime Measurement Register) values, is present:
If tdx_guest is absent, verify the instance was created with --confidential-compute-type=TDX and the zone supports TDX.
Create the working directory:
cmcp-config.yaml:
attestation:
provider: tdx
enforcement_mode: enforcing
validity_seconds: 86400
staleness_policy: fail_closed
policy_bundle_path: ./policies/
catalog_path: ./catalog.json
listen_addr: "0.0.0.0:8443"
For SEV-SNP, change provider: tdx to provider: sev-snp.
Add a minimal set of policy rules:
cat > policies/manifest.json <<'EOF'
{
"version": "0.1.0",
"authored_at": "2026-01-01T00:00:00Z",
"author_identity": "[email protected]",
"commit_sha": "initial"
}
EOF
cat > policies/allow-all.cedar <<'EOF'
permit (principal, action, resource);
EOF
cat > policies/schema.cedarschema <<'EOF'
{"cMCP":{"entityTypes":{"Principal":{"memberOfTypes":[],"shape":{"type":"Record","attributes":{"session_id":{"type":"String","required":true},"workflow_id":{"type":"String","required":true}}}},"Resource":{"memberOfTypes":[],"shape":{"type":"Record","attributes":{"tool_name":{"type":"String","required":true}}}}},"actions":{"call_tool":{"appliesTo":{"principalTypes":["cMCP::Principal"],"resourceTypes":["cMCP::Resource"],"context":{"type":"Record","attributes":{"session_max_sensitivity":{"type":"String","required":true},"workflow_id":{"type":"String","required":true}}}}}}}}
EOF
cat > catalog.json <<'EOF'
[]
EOF
Start the gateway¶
export CMCP_BEARER_TOKEN="$(openssl rand -hex 32)"
echo "Bearer token: $CMCP_BEARER_TOKEN" # save this
cmcp start --config cmcp-config.yaml
Expected startup log on a real TDX VM:
The TEE field should read tdx. If it reads software-only, the gateway could not find the TDX hardware: check the machine type and that /dev/tdx_guest exists.
Verify hardware attestation¶
From your own computer, fetch a TRACE claim from the gateway and check it:
VM_IP=<external IP from above>
# Retrieve a TRACE claim
curl -s -H "Authorization: Bearer $CMCP_BEARER_TOKEN" \
http://$VM_IP:8443/session/test-session/claim \
| python3 -m json.tool > claim.json
# Verify
python3 - <<'EOF'
import json
from cmcp_verify import verify_trace_claim, ApprovedHashes
with open("claim.json") as f:
claim = json.load(f)
approved = ApprovedHashes(
policy_bundle_hash="sha256:<bundle_hash from startup log>",
tool_catalog_hash="sha256:<catalog_hash from startup log>",
)
result = verify_trace_claim(claim, approved)
print(f"Status: {result.status.value}")
print(f"Platform: {claim['trace']['runtime']['platform']}")
print(f"Measurement: {claim['trace']['runtime']['measurement']}")
print(f"Verified fields: {result.verified_fields}")
EOF
Expected output on a real TDX VM:
Status: verified
Platform: intel-tdx
Measurement: sha384:<non-zero hardware measurement>
Verified fields: ['schema', 'signature', 'policy_bundle.hash', 'tool_catalog.hash', 'attestation_freshness', 'audit_chain', 'hardware_attestation']
If hardware_attestation appears in verified_fields, the measurement (the fingerprint of the software that started) came from the hardware.
Pin the expected measurement¶
Once you have seen the measurement on a deployment you trust, write it into the config:
attestation:
provider: tdx
enforcement_mode: enforcing
expected_measurement: "sha384:<measurement from claim>"
Any change to the cMCP software or its startup config produces a different measurement. If the measurement does not match, the gateway stops at startup instead of signing claims with a value you did not expect.
Tear down¶
gcloud compute instances delete cmcp-gateway --zone=$ZONE --quiet
gcloud compute firewall-rules delete allow-cmcp --quiet
Next steps¶
- Azure deployment: AMD SEV-SNP and TDX on Azure DCasv5 / DCedsv5
- TEE attestation: detailed explanation of what each provider proves
- Verify a TRACE claim: full verification protocol
- Multi-tenant deployment: one gateway instance per tenant