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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,7 @@ notebooks/ai_audit/internal/data/readme.md

.agents/
AGENTS.md

# Local JupyterLab state (jupyter MCP server runs from repo root)
.jupyter/
.jupyter_ystore.db
146 changes: 125 additions & 21 deletions packages/syft-enclave/Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ machine_boot_size_default := "200"
vm_default := "syft-enclave-vm"
secret_name_default := "syft-enclave-token"
sa_name_default := "syft-enclave-service-account"
tf_dir := "terraform"

# Shared shell snippet: loads settings from ~/.syft-enclaves/settings.json.
# `project_id` and `zone` are written by `just init`.
Expand Down Expand Up @@ -35,6 +36,12 @@ ensure_dockerhub_login := '''
fi
'''

# Preflight for terraform recipes: terraform installed + tfvars present.
tf_preflight := '''
command -v terraform >/dev/null 2>&1 || { echo "Error: terraform not found. Install: https://developer.hashicorp.com/terraform/install" >&2; exit 1; }
[ -f terraform/terraform.tfvars ] || { echo "Error: terraform/terraform.tfvars not found. Copy terraform/terraform.tfvars.example and fill it in (see docs/terraform.md)." >&2; exit 1; }
'''

# List all available commands
[private]
default:
Expand Down Expand Up @@ -143,17 +150,6 @@ _provision: _whoami
--member="serviceAccount:${project_number}-compute@developer.gserviceaccount.com" \
--role="roles/confidentialcomputing.workloadUser"

# open tcp/8080 (idempotent)
# gcloud compute firewall-rules create allow-enclave-http \
# --project="$project_id" \
# --direction=INGRESS \
# --priority=1000 \
# --network=default \
# --action=ALLOW \
# --rules=tcp:8080 \
# --target-tags=http-server \
# --source-ranges=0.0.0.0/0 || true


# Provision Secret Manager + a dedicated service account for the
# enclave runtime. The SA gets `secretmanager.secretAccessor` on the
Expand Down Expand Up @@ -241,7 +237,6 @@ start email name=vm_default machine_type=machine_type_default machine_boot_size=
--image-project=confidential-space-images \
--scopes=cloud-platform \
--service-account="$sa_email" \
--tags=http-server \
--metadata="^~^tee-image-reference={{image}}~tee-restart-policy=Never~tee-env-SYFT_ENCLAVE_EMAIL={{email}}~tee-env-SYFT_ENCLAVE_DATA_OWNERS=${data_owners}~tee-env-SYFT_ENCLAVE_REQUIRE_TEE=true~tee-env-SYFT_BOOTSTRAP=sa~tee-env-SYFT_BOOTSTRAP_SA_SECRET=${secret_resource}~tee-env-SYFT_ENCLAVE_USE_ENCRYPTION=true${job_timeout_env}"


Expand Down Expand Up @@ -274,11 +269,10 @@ start-debug email name=vm_default machine_type=machine_type_default machine_boot
--image-project=confidential-space-images \
--scopes=cloud-platform \
--service-account="$sa_email" \
--tags=http-server \
--metadata="^~^tee-image-reference={{image}}~tee-restart-policy=Always~tee-container-log-redirect=true~tee-env-SYFT_ENCLAVE_EMAIL={{email}}~tee-env-SYFT_ENCLAVE_DATA_OWNERS=${data_owners}~tee-env-SYFT_ENCLAVE_REQUIRE_TEE=true~tee-env-SYFT_BOOTSTRAP=sa~tee-env-SYFT_BOOTSTRAP_SA_SECRET=${secret_resource}~tee-env-SYFT_ENCLAVE_USE_ENCRYPTION={{use_encryption}}${job_timeout_env}"


# Delete the enclave VM and remove the firewall rule
# Delete the enclave VM
[group('teardown')]
stop name=vm_default: _whoami
#!/bin/bash
Expand All @@ -288,9 +282,6 @@ stop name=vm_default: _whoami
--project="$project_id" \
--zone="$zone" \
--quiet
# gcloud compute firewall-rules delete allow-enclave-http \
# --project="$project_id" \
# --quiet

# Delete the enclave's syftbox (Drive files + local state)
# Usage: just delete-syftbox enclave@example.com
Expand Down Expand Up @@ -370,17 +361,18 @@ status name=vm_default: _whoami
--zone="$zone" \
--format='get(status)'

# Fetch the TEE attestation report from the running enclave
# Fetch the TEE attestation report from the running enclave via SSH
# (debug image only — no inbound port is open on the enclave; production
# publishes its attestation through the peer flow in SYFT_version.json)
[group('inspect')]
attest name=vm_default: _whoami
#!/bin/bash
set -e
{{load_settings}}
ip=$(gcloud compute instances describe {{name}} \
gcloud compute ssh {{name}} \
--project="$project_id" \
--zone="$zone" \
--format='get(networkInterfaces[0].accessConfigs[0].natIP)')
curl -sS "http://${ip}:8080/attestation" | python3 -m json.tool
--command='curl -sS http://localhost:8080/attestation' | python3 -m json.tool

# Tail the last 50 lines of the VM's serial port output
[group('inspect')]
Expand Down Expand Up @@ -486,3 +478,115 @@ credentials-to-token credentials_path output_path:
out = credentials_to_token('{{credentials_path}}', '{{output_path}}')
print(f'token written: {out}')
"

# ---------------------------------------------------------------------------------------------------------------------
# Terraform
#
# Declarative alternative to the gcloud recipes above — see docs/terraform.md.
# Config lives in terraform/terraform.tfvars (gitignored, copy the .example);
# these recipes never read ~/.syft-enclaves/settings.json. dev_mode is always
# forced on the CLI by tf-apply / tf-apply-dev so tfvars can't override it.
# ---------------------------------------------------------------------------------------------------------------------

# Initialize terraform (providers + local state)
[group('terraform')]
tf-init:
terraform -chdir={{tf_dir}} init

# Preview the production deployment
[group('terraform')]
tf-plan *args:
#!/bin/bash
set -e
{{tf_preflight}}
terraform -chdir={{tf_dir}} plan -var=dev_mode=false {{args}}

# Deploy a production enclave (hardened image, no SSH, encryption on)
[group('terraform')]
tf-apply *args:
#!/bin/bash
set -e
{{tf_preflight}}
terraform -chdir={{tf_dir}} apply -var=dev_mode=false {{args}}

# Deploy a debug enclave (SSH, container logs on serial output, encryption off)
[group('terraform')]
tf-apply-dev *args:
#!/bin/bash
set -e
{{tf_preflight}}
terraform -chdir={{tf_dir}} apply -var=dev_mode=true {{args}}

# Destroy everything terraform created (VM, secret, SA, IAM; APIs stay enabled)
[group('terraform')]
tf-destroy *args:
#!/bin/bash
set -e
{{tf_preflight}}
terraform -chdir={{tf_dir}} destroy {{args}}

# Replace the VM without config changes (e.g. after pushing a new :latest image)
[group('terraform')]
tf-redeploy dev="false" *args="":
#!/bin/bash
set -e
{{tf_preflight}}
terraform -chdir={{tf_dir}} apply -var=dev_mode={{dev}} -replace=google_compute_instance.enclave {{args}}

# Show terraform outputs (IP, SA email, secret resource, ...)
[group('terraform')]
tf-output *args:
terraform -chdir={{tf_dir}} output {{args}}

# Fetch the attestation report from the terraform-managed VM via SSH
# (dev deployments only — no inbound port is open on the enclave)
[group('terraform')]
tf-attest:
#!/bin/bash
set -e
gcloud compute ssh \
"$(terraform -chdir={{tf_dir}} output -raw vm_name)" \
--project="$(terraform -chdir={{tf_dir}} output -raw project_id)" \
--zone="$(terraform -chdir={{tf_dir}} output -raw zone)" \
--command='curl -sS http://localhost:8080/attestation' | python3 -m json.tool

# Tail logs of the terraform-managed VM. Prefers SSH + journalctl (full
# container logs; dev deployments only) — the serial console caps redirected
# container output, so chatty containers go quiet there. Falls back to
# serial output when SSH is unavailable (production image).
[group('terraform')]
tf-logs n="100":
#!/bin/bash
set -e
vm=$(terraform -chdir={{tf_dir}} output -raw vm_name)
project=$(terraform -chdir={{tf_dir}} output -raw project_id)
zone=$(terraform -chdir={{tf_dir}} output -raw zone)
if logs=$(timeout 60 gcloud compute ssh "$vm" --project="$project" --zone="$zone" \
--command="sudo journalctl --no-pager -n 20000 2>/dev/null | grep cs_container_launcher | tail -n {{n}}" 2>/dev/null); then
echo "$logs"
else
echo "(SSH unavailable — falling back to serial output; container logs there are capped)" >&2
gcloud compute instances get-serial-port-output "$vm" \
--project="$project" --zone="$zone" 2>&1 | tail -n {{n}}
fi

# Status of the terraform-managed VM (RUNNING / TERMINATED / ...)
[group('terraform')]
tf-status:
#!/bin/bash
set -e
gcloud compute instances describe \
"$(terraform -chdir={{tf_dir}} output -raw vm_name)" \
--project="$(terraform -chdir={{tf_dir}} output -raw project_id)" \
--zone="$(terraform -chdir={{tf_dir}} output -raw zone)" \
--format='get(status)'

# SSH into the terraform-managed VM (dev deployments only)
[group('terraform')]
tf-ssh:
#!/bin/bash
set -e
gcloud compute ssh \
"$(terraform -chdir={{tf_dir}} output -raw vm_name)" \
--project="$(terraform -chdir={{tf_dir}} output -raw project_id)" \
--zone="$(terraform -chdir={{tf_dir}} output -raw zone)"
12 changes: 8 additions & 4 deletions packages/syft-enclave/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Enclave support for syft-client, enabling secure computation in Trusted Executio
- [Security Overview](./docs/security.md)
- [Enclave Architecture](./docs/enclave_architecture.md)
- [API](./docs/api.md)
- [Terraform Deployment](./docs/terraform.md)

## Prerequisites

Expand All @@ -18,6 +19,8 @@ Enclave support for syft-client, enabling secure computation in Trusted Executio

All commands are defined in the [`Justfile`](./Justfile). Run them from this directory.

Prefer declarative deploys? The same stack can be managed with Terraform — see [Terraform Deployment](./docs/terraform.md) (`just tf-apply` / `just tf-apply-dev`).

## One-time setup

```bash
Expand All @@ -40,10 +43,10 @@ Hardened image — no SSH access, TEE enforcement enabled.
```bash
just start EMAIL # defaults: syft-enclave-vm, n2d-standard-2
just start EMAIL my-vm n2d-standard-4 # override name / machine type
just stop [name] # Teardown: Deletes VM and removes firewall rule (default: syft-enclave-vm)
just stop [name] # Teardown: Deletes the VM (default: syft-enclave-vm)
```

The first run also provisions APIs, IAM roles, and firewall rules (idempotent).
The first run also provisions APIs and IAM roles (idempotent). No inbound port is opened on the enclave — attestation is published through the peer flow, and all other traffic is outbound.

## Debug deployment

Expand All @@ -52,7 +55,7 @@ Debug image — SSH enabled, container logs redirected to serial output.
```bash
just start-debug EMAIL # defaults: syft-enclave-vm, n2d-standard-2
just start-debug EMAIL my-vm n2d-standard-4 # override name / machine type
just stop [name] # Teardown: Deletes VM and removes firewall rule.
just stop [name] # Teardown: Deletes the VM.
```

## Inspect a running VM
Expand All @@ -63,9 +66,10 @@ All inspect commands take an optional `name` (default: `syft-enclave-vm`). Zone
# Works on both production and debug
just status [name] # RUNNING / TERMINATED / etc.
just get-ip [name] # external IP
just attest [name] # fetch TEE attestation report

# Debug only
just attest [name] # fetch TEE attestation report via SSH (no inbound port is open;
# production publishes attestation through the peer flow instead)
just ssh [name] # SSH into the VM (production image disables SSH)
just logs [name] # last 50 lines of serial output (production only shows boot logs;
# debug redirects container logs to serial output)
Expand Down
Loading
Loading