Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions cc-eventlog/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,15 @@ impl TryFrom<TcgEventLog> for TdxEventLog {
.try_into()
.ok()
.context("invalid digest size")?;
// TCG event logs use 1-based IMR indices (1-4), while TDX RTMRs are 0-based (0-3).
// Standard conversion: TCG IMR 1 → RTMR 0, TCG IMR 2 → RTMR 1, etc.
//
// However, some cloud platforms (notably GCP) may include events with IMR index 0
// in their CCEL tables. Rather than failing on these, we pass them through as RTMR 0.
// This maintains compatibility with both standard TCG format and GCP's implementation.
let imr = value.imr_index.saturating_sub(1);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merging imr 0 and 1 would cause RMTR replay mismatches. We've dropped imr 0 events in an internal dev branch.

Ok(TdxEventLog {
imr: value
.imr_index
.checked_sub(1)
.context("invalid imr index")?,
imr,
event_type: value.event_type,
digest,
event: Default::default(),
Expand Down
87 changes: 87 additions & 0 deletions deploy/gcp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<!--
SPDX-FileCopyrightText: © 2025 Phala Network <dstack@phala.network>
SPDX-License-Identifier: Apache-2.0
-->

# Dstack on Google Cloud Platform

Deploy Dstack with Intel TDX Confidential Computing on GCP.

## Prerequisites

- Google Cloud account with billing enabled
- `gcloud` CLI authenticated
- Terraform >= 1.5.0

## Supported Machines

| Type | TEE | Zones |
|------|-----|-------|
| `c3-standard-*` | Intel TDX | us-central1-a/b/c, us-east1-c/d, europe-west4-a/b/c |
| `a3-highgpu-1g` | Intel TDX + H100 | us-central1-a, us-east5-a, europe-west4-c |

## Quick Start

```bash
# Authenticate
gcloud auth login
gcloud auth application-default login
gcloud config set project YOUR_PROJECT_ID
gcloud services enable compute.googleapis.com

# Deploy
cd deploy/gcp/terraform
cp terraform.tfvars.example terraform.tfvars
# Edit terraform.tfvars
terraform init && terraform apply

# Verify
./test.sh <VM_IP> [SSH_KEY]
```

## Verify TDX

```bash
ssh ubuntu@<VM_IP>

# TDX device
ls -la /dev/tdx_guest

# Kernel detection
sudo dmesg | grep tdx

# Memory encryption
sudo dmesg | grep "Memory Encryption"

# TSM quote
dd if=/dev/zero bs=1 count=64 | sudo tee /sys/kernel/config/tsm/report/com.intel.dcap/inblob >/dev/null
sudo cat /sys/kernel/config/tsm/report/com.intel.dcap/outblob | xxd | head -5
```

## Real vs Simulated

| Check | Simulated | Real TDX |
|-------|-----------|----------|
| `/dev/tdx_guest` | Missing | Present |
| `dmesg "tdx: Guest"` | Missing | Present |
| TSM provider | N/A | `tdx_guest` |
| Quote TEE type | N/A | `0x81000000` |

## Limitations

- No Local SSD (use pd-balanced)
- No live migration
- H100 requires quota request

## Cost

| Resource | $/hr |
|----------|------|
| c3-standard-8 | ~$0.40 |
| a3-highgpu-1g | ~$3.50 |

## Cleanup

```bash
terraform destroy
```
48 changes: 48 additions & 0 deletions deploy/gcp/deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/bash
# SPDX-FileCopyrightText: © 2025 Phala Network <dstack@phala.network>
# SPDX-License-Identifier: Apache-2.0
# Dstack GCP Deployment Script
set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TERRAFORM_DIR="$SCRIPT_DIR/terraform"

RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'

check_prereqs() {
command -v gcloud &>/dev/null || { echo -e "${RED}gcloud CLI not found${NC}"; exit 1; }
command -v terraform &>/dev/null || { echo -e "${RED}Terraform not found${NC}"; exit 1; }

ACCOUNT=$(gcloud auth list --filter=status:ACTIVE --format="value(account)" 2>/dev/null)
[ -z "$ACCOUNT" ] && { echo -e "${RED}Not authenticated. Run: gcloud auth login${NC}"; exit 1; }
echo -e "${GREEN}Authenticated as: $ACCOUNT${NC}"
}

deploy() {
cd "$TERRAFORM_DIR"

[ ! -f terraform.tfvars ] && {
cp terraform.tfvars.example terraform.tfvars
echo "Edit terraform.tfvars with your project ID, then re-run."
exit 1
}

terraform init
terraform plan -out=tfplan

read -p "Apply? (y/N) " -n 1 -r; echo
[[ $REPLY =~ ^[Yy]$ ]] && terraform apply tfplan && terraform output
}

destroy() {
cd "$TERRAFORM_DIR"
terraform destroy
}

case "${1:-deploy}" in
deploy) check_prereqs; deploy ;;
destroy) destroy ;;
*) echo "Usage: $0 [deploy|destroy]"; exit 1 ;;
esac
195 changes: 195 additions & 0 deletions deploy/gcp/terraform/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
# SPDX-FileCopyrightText: © 2025 Phala Network <dstack@phala.network>
# SPDX-License-Identifier: Apache-2.0
# Dstack on GCP with Intel TDX
# Supported zones: us-central1-a/b/c, us-east1-c/d, europe-west4-a/b/c, asia-southeast1-a/b/c

terraform {
required_version = ">= 1.5.0"
required_providers {
google-beta = {
source = "hashicorp/google-beta"
version = "~> 5.0"
}
}
}

variable "project_id" {
description = "GCP Project ID"
type = string
}

variable "region" {
type = string
default = "us-central1"
}

variable "zone" {
type = string
default = "us-central1-a"
}

variable "machine_type" {
type = string
default = "c3-standard-8"
}

variable "disk_size_gb" {
type = number
default = 200
}

variable "ssh_public_key" {
type = string
default = ""
}

variable "dstack_version" {
type = string
default = "0.5.2"
}

provider "google-beta" {
project = var.project_id
region = var.region
}

resource "google_compute_network" "dstack" {
provider = google-beta
name = "dstack-network"
auto_create_subnetworks = false
}

resource "google_compute_subnetwork" "dstack" {
provider = google-beta
name = "dstack-subnet"
ip_cidr_range = "10.0.0.0/24"
region = var.region
network = google_compute_network.dstack.id
}

resource "google_compute_firewall" "dstack" {
provider = google-beta
name = "dstack-allow"
network = google_compute_network.dstack.name

allow {
protocol = "tcp"
ports = ["22", "9080", "9201", "9204", "9300"]
}

source_ranges = ["0.0.0.0/0"]
target_tags = ["dstack"]
}

resource "google_compute_instance" "dstack_vmm" {
provider = google-beta
name = "dstack-vmm"
machine_type = var.machine_type
zone = var.zone
tags = ["dstack"]

boot_disk {
initialize_params {
image = "ubuntu-os-cloud/ubuntu-2204-lts"
size = var.disk_size_gb
type = "pd-balanced"
}
}

confidential_instance_config {
confidential_instance_type = "TDX"
enable_confidential_compute = true
}

scheduling {
on_host_maintenance = "TERMINATE"
automatic_restart = true
}

network_interface {
subnetwork = google_compute_subnetwork.dstack.id
access_config {}
}

metadata = {
ssh-keys = var.ssh_public_key != "" ? "ubuntu:${var.ssh_public_key}" : null
}

metadata_startup_script = <<-EOF
#!/bin/bash
set -e
exec > >(tee /var/log/dstack-startup.log) 2>&1

apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential curl wget git docker.io jq

systemctl enable docker && systemctl start docker
usermod -aG docker ubuntu

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sudo -u ubuntu sh -s -- -y

cd /home/ubuntu
sudo -u ubuntu git clone https://github.com/Dstack-TEE/dstack.git
mkdir -p vmm-data/{images,run}
chown -R ubuntu:ubuntu vmm-data

cd vmm-data
wget -q "https://github.com/Dstack-TEE/meta-dstack/releases/download/v${var.dstack_version}/dstack-${var.dstack_version}.tar.gz" || true
[ -f "dstack-${var.dstack_version}.tar.gz" ] && tar -xzf "dstack-${var.dstack_version}.tar.gz" -C images/ && rm "dstack-${var.dstack_version}.tar.gz"

cd /home/ubuntu/dstack
sudo -u ubuntu /home/ubuntu/.cargo/bin/cargo build --release -p dstack-vmm -p supervisor || true
[ -f target/release/dstack-vmm ] && cp target/release/{dstack-vmm,supervisor} /home/ubuntu/vmm-data/

cat > /home/ubuntu/vmm-data/vmm.toml << 'VMCFG'
address = "0.0.0.0:9080"
image_path = "./images"
run_path = "./run/vm"
[cvm]
kms_urls = ["http://127.0.0.1:9201"]
gateway_urls = ["http://127.0.0.1:9204"]
cid_start = 30000
cid_pool_size = 1000
[host_api]
port = 9300
[supervisor]
exe = "./supervisor"
sock = "./run/supervisor.sock"
VMCFG
chown ubuntu:ubuntu /home/ubuntu/vmm-data/vmm.toml

cat > /etc/systemd/system/dstack-vmm.service << 'SVC'
[Unit]
Description=Dstack VMM
After=network.target docker.service
[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/vmm-data
ExecStart=/home/ubuntu/vmm-data/dstack-vmm -c vmm.toml
Restart=always
[Install]
WantedBy=multi-user.target
SVC

[ -f /home/ubuntu/vmm-data/dstack-vmm ] && systemctl daemon-reload && systemctl enable --now dstack-vmm
EOF

service_account {
scopes = ["cloud-platform"]
}

allow_stopping_for_update = true
}

output "ip" {
value = google_compute_instance.dstack_vmm.network_interface[0].access_config[0].nat_ip
}

output "ssh" {
value = "ssh ubuntu@${google_compute_instance.dstack_vmm.network_interface[0].access_config[0].nat_ip}"
}

output "verify_tdx" {
value = "ssh ubuntu@${google_compute_instance.dstack_vmm.network_interface[0].access_config[0].nat_ip} 'ls -la /dev/tdx_guest'"
}
13 changes: 13 additions & 0 deletions deploy/gcp/terraform/terraform.tfvars.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# SPDX-FileCopyrightText: © 2025 Phala Network <dstack@phala.network>
# SPDX-License-Identifier: Apache-2.0
# Copy to terraform.tfvars and edit

project_id = "your-project-id"
region = "us-central1"
zone = "us-central1-a" # Must support TDX

machine_type = "c3-standard-8" # c3-* for TDX
disk_size_gb = 200
dstack_version = "0.5.2"

# ssh_public_key = "ssh-rsa AAAAB3... user@host"
Loading