Skip to main content
WARNINGThis tutorial assumes your have access to a compatible Intel TDX Server ready to be configured with dstack. Check the Hardware Requirements for more information or skip setting everything up from scratch and Sign-up for Phala Cloud Account.
For the latest information, please refer to the dstack README.

dstack

dstack is a developer friendly and security first SDK to simplify the deployment of arbitrary Docker-based apps into TEE. Main features:
  • 🔒 Deploy containerized apps securely in TEE in minutes
  • 🛠️ Use familiar tools - just write a docker-compose.yaml
  • 🔑 Safely manage secrets and sensitive data
  • 📡 Expose services via built-in TLS termination
dstack is community driven. Open sourced and built by Kevin Wang and many others from Phala Network, inspired by Andrew Miller (Flashbots & Teleport), and contributed by Nethermind and many others.

Overview

Components in dstack:
  • dstack-vmm: A service running in bare TDX host to manage CVMs
  • dstack-gateway: A reverse proxy to forward TLS connections to CVMs
  • dstack-kms: A KMS server to generate keys for CVMs
  • dstack-guest-agent: A service running in CVM to serve containers’ key derivation and attestation requests
  • meta-dstack: A Yocto meta layer to build CVM guest images
The overall architecture is shown below:

Directory structure

Build and play locally

Prerequisites

  • A bare metal TDX server setup following canonical/tdx
  • Public IPv4 address assigned to the machine
  • At least 16GB RAM, 100GB free disk space.
  • A domain with DNS access if you want to set up dstack-gateway for Zero Trust HTTPS

Install dependencies

Build and run

Review and customize the build-config.sh configuration file according to your environment requirements. The file contains network ports, domain settings, and other important parameters. Once configured, run the build script again to generate the necessary artifacts:

Download guest image or build guest image from source

Or build guest image from source:
Now you can open 3 terminals to start the components:
  1. Run ./dstack-kms -c kms.toml
  2. Run sudo ./dstack-gateway -c gateway.toml
  3. Run ./dstack-vmm -c vmm.toml

Deploy an App

Open the dstack-vmm webpage http://localhost:9080(change the port according to your configuration) on your local machine to deploy a docker-compose.yaml file:
dstack-vmm web interface

dstack-vmm web interface

After the container deployed, it should need some time to start the CVM and the containers. Time would be vary depending on your workload.
  • Click the [Logs] button to see the logs of the CVM, you can see if the container is finished starting there.
  • Once the container is running, you can click the [Dashboard] button to see some information of the container. And the logs of the containers can be seen in the [Dashboard] page.
    dstack guest agent status

    dstack guest agent status

  • You can open dstack-gateway’s dashboard at https://localhost:9070 to see the CVM’s wireguard ip address, as shown below:
    dstack gateway dashboard

    dstack gateway dashboard

Pass Secrets to Apps

When deploying a new App, you can pass private data via Encrypted Environment Variables. These variables can be referenced in the docker-compose.yaml file as shown below:
dstack secret management

dstack secret management

The environment variables will be encrypted in the client-side and decrypted in the CVM before being passed to the containers.

Access the App

Once the app is deployed and listening on an HTTP port, you can access the HTTP service via tproxy’s public domain. The ingress mapping rules are:
  • <id>[s].<base_domain> maps to port 80 or 443 if with s in the CVM.
  • <id>-<port>[s].<base_domain> maps to port <port> in the CVM.
For example, 3327603e03f5bd1f830812ca4a789277fc31f577-8080.app.kvin.wang maps to port 8080 in the CVM. Where the <id> can be either the app id or the instance id. If the app id is used, one of the instances will be selected by the load balancer.
If the id-port part ends with s, it means the TLS connection will be passthrough to the app rather than terminating at dstack-gateway.
You can also ssh into the CVM to inspect more information, if your deployment uses the image dstack-x.x.x-dev:

Getting TDX quote in docker container

To get a TDX quote within app containers:
  1. Mount /var/run/dstack.sock to the target container in docker-compose.yaml
  2. Execute the quote request command in the container.
For automated verification of your application’s attestation, see the Trust Center Technical Documentation which explains how to use these quotes with the Trust Center verification platform.

Container logs

Container logs can be obtained from the CVM’s dashboard page or by curl:
Replace <appid> and <container name> with actual values. Available parameters:
  • since=0: Starting Unix timestamp for log retrieval
  • until=0: Ending Unix timestamp for log retrieval
  • follow: Enables continuous log streaming
  • text: Returns human-readable text instead of base64 encoding
  • timestamps: Adds timestamps to each log line
  • bare: Returns the raw log lines without json format
The response of the RPC looks like:

TLS Passthrough with Custom Domain

dstack-gateway supports TLS passthrough for custom domains. See the example here for more details.

Upgrade an App

Got to the dstack-vmm webpage, click the [Upgrade] button, select or paste the compose file you want to upgrade to, and click the [Upgrade] button again.
The app id does not change after the upgrade. Stop and start the app to apply the upgrade.

HTTPS Certificate Transparency

In the tutorial above, we used a TLS certificate with a private key external to the TEE. To establish trust, we need to generate and maintain the certificate’s private key within the TEE and provide evidence that all TLS certificates for the domain were originate solely from dstack-gateway CVM. By combining Certificate Transparency Logs and CAA DNS records, we can make best effort to minimize security risks. Here’s our approach:
  • Set CAA records to allow only the account created in dstack-gateway CVM to request Certificates.
  • Launch a program to monitor Certificate Transparency Log and give alarm once any certificate issued to a pubkey that isn’t generated by dstack-gateway CVM.

Configurations

To launch Certbot, you need to own a domain hosted on Cloudflare. Obtain an API token with DNS operation permissions from the Cloudflare dashboard. Configure it in the build-config.sh:
Then re-run the ../build.sh:

Launch certbot

Then run the certbot in the build/ and you will see the following log:
Where the command did are:
  • Registered to letsencrypt and got a new account https://acme-staging-v02.api.letsencrypt.org/acme/acct/168601853
  • Auto set CAA records for the domain on cloudflare, you can open the CF dashboard to see the record:
    certbot CAA record configuration

    certbot CAA record configuration

  • Auto requested a new certificate from Let’s Encrypt. Automatically renews the certificate to maintain its validity

Launch dstack-gateway

Execute dstack-gateway with sudo ./dstack-gateway -c gateway.toml, then access the web portal to check the dstack-gateway CVM managed Let’s Encrypt account. The account’s private key remains securely sealed within the TEE.
dstack gateway account ID

dstack gateway account ID

Certificate transparency log monitor

To enhance security, we’ve limited TLS certificate issuance to dstack-gateway via CAA records. However, since these records can be modified through Cloudflare’s domain management, we need to implement global CA certificate monitoring to maintain security oversight. ct_monitor tracks Certificate Transparency logs via https://crt.sh, comparing their public key with the ones got from dstack-gateway RPC. It immediately alerts when detecting unauthorized certificates not issued through dstack-gateway:

Troubleshooting

Error from dstack-vmm: qemu-system-x86_64: -device vhost-vsock-pci,guest-cid=: vhost-vsock: unable to set guest cid: Address already in use

dstack-vmm may throw this error when creating a new VM if the Unix Socket CID is occupied. To solve the problem, first, you should list the occupied CID:
Then choose a new range of the CID not conflicting with the CID in use. You can change build/vmm.toml file and restart dstack-vmm. This error should disappear. For example, you may find 33000-34000 free to use:
When building the dstack from scratch, you should change the CID configs in build-config.sh instead, because vmm.toml file is generated by build.sh. Its content is derived from build-config.sh. You may encounter this problem when upgrading from an older version of dstack, because CID was introduced in build-config.sh in later versions. In such case, please follow the docs to add the missing entries in build-config.sh and rebuild dstack.

Error: Operation not permitted when building guest image

When running ../build.sh guest, you might encounter this error:
This error occurs because Ubuntu 23.10 and later versions restrict unprivileged user namespaces by default. To fix this, run:
Then try building again. For more information about this restriction, see the Ubuntu discourse post.

Contributors

dstack is proudly built by open source and Pi-rateship contributors: The inspiration for this work stems from Andrew Miller’s pioneering concept of a Docker-based P2P TEE SDK. This project cannot be built without standing on the shoulders of giants: Special acknowledgment to Flashbots for building a community around TEE. The TEE Hacker House initiative, organized by Flashbots and led by Tina, has brought together TEE builders to develop tools for TEE-Web3 integration. This collaborative journey has generated invaluable insights for advancing secure, confidential environments within Web3. Together, we’re shaping the future of TEE in Web3, paving the way for more secure and developer-accessible confidential computing! For a full list of the direct contributors to this repo, see Contributors on GitHub.