Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .changeset/dstack-tee-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tinycloud": minor
---

Add dstack TEE support for confidential deployment. Keys can now be derived deterministically from TEE KMS, sensitive database columns are encrypted with AES-256-GCM, and a new `/attestation` endpoint provides TDX hardware attestation quotes. The `/version` endpoint now includes an `inTEE` flag. Enabled via `--features dstack`.
13 changes: 8 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_with = { version = "3.0", features = ["hex"] }
thiserror = "2.0"
time.workspace = true
tempfile = "3"
tokio = { version = "1", features = ["rt", "macros", "rt-multi-thread"] }
tokio-stream = { version = "0.1", features = ["fs"] }
Expand All @@ -46,6 +47,10 @@ features = ["sqlite", "postgres", "mysql", "tokio"]
[dependencies.tinycloud-lib]
path = "tinycloud-lib/"

[features]
default = []
dstack = []

[workspace]

members = [
Expand Down
7 changes: 5 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Build argument to select runtime base (default scratch)
ARG RUNTIME_BASE=scratch
# Optional: pass "dstack" to enable TEE support
ARG CARGO_FEATURES=""

FROM rust:alpine AS chef
RUN apk add --no-cache musl-dev pkgconfig openssl-dev openssl-libs-static g++
Expand All @@ -21,15 +23,16 @@ COPY ./scripts/ ./scripts/
RUN cargo chef prepare --recipe-path recipe.json

FROM chef AS builder
ARG CARGO_FEATURES=""
COPY --from=planner /app/recipe.json recipe.json
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/app/target \
cargo chef cook --release --recipe-path recipe.json
cargo chef cook --release --recipe-path recipe.json ${CARGO_FEATURES:+--features $CARGO_FEATURES}
COPY --from=planner /app/ ./
RUN chmod +x ./scripts/init-tinycloud-data.sh && ./scripts/init-tinycloud-data.sh
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/app/target \
cargo build --release --bin tinycloud && \
cargo build --release --bin tinycloud ${CARGO_FEATURES:+--features $CARGO_FEATURES} && \
cp /app/target/release/tinycloud /app/tinycloud
RUN addgroup -g 1000 tinycloud && adduser -u 1000 -G tinycloud -s /bin/sh -D tinycloud

Expand Down
40 changes: 40 additions & 0 deletions docker-compose.dstack-full.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# dstack deployment - Topology 3: Full Confidential (Postgres in CVM)
# Both tinycloud-node and Postgres run inside the same CVM.
# Maximum confidentiality - no external database exposure.

services:
tinycloud:
image: ghcr.io/tinycloudlabs/tinycloud-node:latest
ports:
- "8000:8000"
- "8001:8001"
volumes:
- /var/run/dstack.sock:/var/run/dstack.sock
environment:
TINYCLOUD_KEYS_TYPE: Dstack
TINYCLOUD_STORAGE_DATABASE: "postgres://tinycloud:tinycloud@postgres:5432/tinycloud"
TINYCLOUD_STORAGE_BLOCKS_TYPE: Local
TINYCLOUD_STORAGE_BLOCKS_PATH: /data/blocks
TINYCLOUD_LOG_LEVEL: info
TINYCLOUD_CORS: "true"
ROCKET_ADDRESS: "0.0.0.0"
depends_on:
postgres:
condition: service_healthy

postgres:
image: postgres:16
environment:
POSTGRES_USER: tinycloud
POSTGRES_PASSWORD: tinycloud
POSTGRES_DB: tinycloud
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U tinycloud"]
interval: 5s
timeout: 5s
retries: 5

volumes:
pgdata:
27 changes: 27 additions & 0 deletions docker-compose.dstack-postgres.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# dstack deployment - Topology 2: Postgres + S3
# tinycloud-node in the CVM, Postgres external.
# Database credentials encrypted by dstack KMS.
# Column encryption enabled for sensitive data.
#
# All ${...} variables should be encrypted using dstack's KMS public key
# before deployment. The operator never sees plaintext values.

services:
tinycloud:
image: ghcr.io/tinycloudlabs/tinycloud-node:latest
ports:
- "8000:8000"
- "8001:8001"
volumes:
- /var/run/dstack.sock:/var/run/dstack.sock
environment:
TINYCLOUD_KEYS_TYPE: Dstack
TINYCLOUD_STORAGE_DATABASE: "${DATABASE_URL}"
TINYCLOUD_STORAGE_BLOCKS_TYPE: S3
TINYCLOUD_STORAGE_BLOCKS_BUCKET: "${S3_BUCKET}"
TINYCLOUD_STORAGE_BLOCKS_ENDPOINT: "${S3_ENDPOINT}"
AWS_ACCESS_KEY_ID: "${AWS_KEY}"
AWS_SECRET_ACCESS_KEY: "${AWS_SECRET}"
TINYCLOUD_LOG_LEVEL: info
TINYCLOUD_CORS: "true"
ROCKET_ADDRESS: "0.0.0.0"
31 changes: 31 additions & 0 deletions docker-compose.dstack.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# dstack deployment - Topology 1: SQLite + Local Storage
# Single container, everything in the CVM. Good for small/personal instances.
#
# Deploy on dstack:
# docker build --build-arg CARGO_FEATURES=dstack -t tinycloud-dstack .
# # Or use the pre-built image from ghcr.io
#
# The same image works on dstack (TEE) and classic (non-TEE) deployments.
# In TEE mode, keys are derived from dstack KMS - never stored, never exposed.
# In classic mode, set TINYCLOUD_KEYS_SECRET manually.

services:
tinycloud:
image: ghcr.io/tinycloudlabs/tinycloud-node:latest
ports:
- "8000:8000"
- "8001:8001"
volumes:
- /var/run/dstack.sock:/var/run/dstack.sock
- tinycloud-data:/app/data
environment:
TINYCLOUD_KEYS_TYPE: Dstack
TINYCLOUD_STORAGE_DATABASE: "sqlite:./data/caps.db?mode=rwc"
TINYCLOUD_STORAGE_BLOCKS_TYPE: Local
TINYCLOUD_STORAGE_BLOCKS_PATH: ./data/blocks
TINYCLOUD_LOG_LEVEL: info
TINYCLOUD_CORS: "true"
ROCKET_ADDRESS: "0.0.0.0"

volumes:
tinycloud-data:
35 changes: 32 additions & 3 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ pub struct Config {
pub cors: bool,
pub keys: Keys,
#[serde(default)]
pub tee: TeeConfig,
#[serde(default)]
pub public_spaces: PublicSpacesConfig,
}

Expand Down Expand Up @@ -57,15 +59,42 @@ impl Default for PublicSpacesConfig {
}
}

#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq, Default)]
#[serde(tag = "type")]
pub enum Keys {
Static(Static),
#[cfg(feature = "dstack")]
Dstack,
#[default]
Auto,
}

#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
pub struct TeeConfig {
#[serde(default = "default_tee_mode")]
pub mode: TeeMode,
#[serde(default)]
pub attestation: bool,
}

impl Default for Keys {
#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq, Default)]
pub enum TeeMode {
#[default]
Auto,
Dstack,
Off,
}

fn default_tee_mode() -> TeeMode {
TeeMode::Auto
}

impl Default for TeeConfig {
fn default() -> Self {
Self::Static(Static::default())
Self {
mode: TeeMode::Auto,
attestation: false,
}
}
}

Expand Down
Loading