Skip to content

Commit 846637c

Browse files
committed
Add dstack-verifier
1 parent d349941 commit 846637c

File tree

20 files changed

+2407
-2
lines changed

20 files changed

+2407
-2
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# SPDX-FileCopyrightText: © 2025 Phala Network <[email protected]>
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
name: Verifier Release
6+
7+
on:
8+
workflow_dispatch:
9+
push:
10+
tags:
11+
- 'verifier-v*'
12+
permissions:
13+
attestations: write
14+
id-token: write
15+
contents: write
16+
packages: write
17+
18+
jobs:
19+
build-and-release:
20+
runs-on: ubuntu-latest
21+
steps:
22+
- name: Checkout repository
23+
uses: actions/checkout@v4
24+
25+
- name: Parse version from tag
26+
run: |
27+
VERSION=${GITHUB_REF#refs/tags/verifier-v}
28+
echo "VERSION=$VERSION" >> $GITHUB_ENV
29+
echo "Parsed version: $VERSION"
30+
31+
- name: Log in to Docker Hub
32+
uses: docker/login-action@v3
33+
with:
34+
username: ${{ vars.DOCKERHUB_USERNAME }}
35+
password: ${{ secrets.DOCKERHUB_TOKEN }}
36+
37+
- name: Set up Docker Buildx
38+
uses: docker/setup-buildx-action@v3
39+
40+
- name: Get Git commit timestamps
41+
run: |
42+
echo "TIMESTAMP=$(git log -1 --pretty=%ct)" >> $GITHUB_ENV
43+
echo "GIT_REV=$(git rev-parse HEAD)" >> $GITHUB_ENV
44+
45+
- name: Build and push Docker image
46+
id: build-and-push
47+
uses: docker/build-push-action@v5
48+
env:
49+
SOURCE_DATE_EPOCH: ${{ env.TIMESTAMP }}
50+
with:
51+
context: verifier
52+
file: verifier/builder/Dockerfile
53+
push: true
54+
tags: ${{ vars.DOCKERHUB_USERNAME }}/dstack-verifier:${{ env.VERSION }}
55+
platforms: linux/amd64
56+
provenance: false
57+
build-args: |
58+
DSTACK_REV=${{ env.GIT_REV }}
59+
DSTACK_SRC_URL=${{ github.server_url }}/${{ github.repository }}.git
60+
SOURCE_DATE_EPOCH=${{ env.TIMESTAMP }}
61+
62+
- name: Generate artifact attestation
63+
uses: actions/attest-build-provenance@v1
64+
with:
65+
subject-name: "docker.io/${{ vars.DOCKERHUB_USERNAME }}/dstack-verifier"
66+
subject-digest: ${{ steps.build-and-push.outputs.digest }}
67+
push-to-registry: true
68+
69+
- name: GitHub Release
70+
uses: softprops/action-gh-release@v1
71+
with:
72+
name: "Verifier Release v${{ env.VERSION }}"
73+
body: |
74+
## Docker Image Information
75+
76+
**Image**: `docker.io/${{ vars.DOCKERHUB_USERNAME }}/dstack-verifier:${{ env.VERSION }}`
77+
78+
**Digest (SHA256)**: `${{ steps.build-and-push.outputs.digest }}`
79+
80+
**Verification**: [Verify on Sigstore](https://search.sigstore.dev/?hash=${{ steps.build-and-push.outputs.digest }})

Cargo.lock

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ members = [
4949
"serde-duration",
5050
"dstack-mr",
5151
"dstack-mr/cli",
52+
"verifier",
5253
"no_std_check",
5354
]
5455
resolver = "2"

REUSE.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,13 @@ SPDX-License-Identifier = "CC0-1.0"
162162
path = "dstack-util/tests/fixtures/*"
163163
SPDX-FileCopyrightText = "NONE"
164164
SPDX-License-Identifier = "CC0-1.0"
165+
166+
[[annotations]]
167+
path = "verifier/fixtures/*"
168+
SPDX-FileCopyrightText = "NONE"
169+
SPDX-License-Identifier = "CC0-1.0"
170+
171+
[[annotations]]
172+
path = "verifier/builder/shared/*.txt"
173+
SPDX-FileCopyrightText = "NONE"
174+
SPDX-License-Identifier = "CC0-1.0"

kms/dstack-app/builder/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ RUN cd dstack && cargo build --release -p dstack-kms --target x86_64-unknown-lin
2727
FROM debian:bookworm@sha256:0d8498a0e9e6a60011df39aab78534cfe940785e7c59d19dfae1eb53ea59babe
2828
COPY ./shared /build
2929
WORKDIR /build
30-
ARG QEMU_REV=d98440811192c08eafc07c7af110593c6b3758ff
30+
ARG QEMU_REV=dbcec07c0854bf873d346a09e87e4c993ccf2633
3131
RUN ./pin-packages.sh ./qemu-pinned-packages.txt && \
3232
apt-get update && \
3333
apt-get install -y --no-install-recommends \
@@ -43,7 +43,7 @@ RUN ./pin-packages.sh ./qemu-pinned-packages.txt && \
4343
flex \
4444
bison && \
4545
rm -rf /var/lib/apt/lists/* /var/log/* /var/cache/ldconfig/aux-cache
46-
RUN git clone https://github.com/kvinwang/qemu-tdx.git --depth 1 --branch passthrough-dump-acpi --single-branch && \
46+
RUN git clone https://github.com/kvinwang/qemu-tdx.git --depth 1 --branch dstack-qemu-9.2.1 --single-branch && \
4747
cd qemu-tdx && git fetch --depth 1 origin ${QEMU_REV} && \
4848
git checkout ${QEMU_REV} && \
4949
../config-qemu.sh ./build /usr/local && \

verifier/Cargo.toml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# SPDX-FileCopyrightText: © 2024-2025 Phala Network <[email protected]>
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
[package]
6+
name = "dstack-verifier"
7+
version.workspace = true
8+
authors.workspace = true
9+
edition.workspace = true
10+
license.workspace = true
11+
homepage.workspace = true
12+
repository.workspace = true
13+
14+
[dependencies]
15+
anyhow.workspace = true
16+
clap = { workspace = true, features = ["derive"] }
17+
figment.workspace = true
18+
fs-err.workspace = true
19+
hex.workspace = true
20+
rocket = { workspace = true, features = ["json"] }
21+
serde = { workspace = true, features = ["derive"] }
22+
serde_json.workspace = true
23+
tokio = { workspace = true, features = ["full"] }
24+
tracing.workspace = true
25+
tracing-subscriber.workspace = true
26+
reqwest.workspace = true
27+
tempfile.workspace = true
28+
29+
# Internal dependencies
30+
ra-tls.workspace = true
31+
dstack-types.workspace = true
32+
dstack-mr.workspace = true
33+
34+
# Crypto/verification dependencies
35+
dcap-qvl.workspace = true
36+
cc-eventlog.workspace = true
37+
sha2.workspace = true

verifier/README.md

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# dstack-verifier
2+
3+
A HTTP server that provides CVM (Confidential Virtual Machine) verification services using the same verification process as the dstack KMS.
4+
5+
## Features
6+
7+
- **TDX Quote Verification**: Uses dcap-qvl to verify TDX quotes
8+
- **Event Log Verification**: Validates event logs and extracts app information
9+
- **OS Image Hash Verification**: Uses dstack-mr to ensure OS image hash matches expected measurements
10+
- **Automatic Image Download**: Downloads and caches OS images automatically when not found locally
11+
- **RESTful API**: Simple HTTP endpoints for verification requests
12+
13+
## API Endpoints
14+
15+
### POST /verify
16+
17+
Verifies a CVM attestation with the provided quote, event log, and VM configuration.
18+
19+
**Request Body:**
20+
```json
21+
{
22+
"quote": "hex-encoded-quote",
23+
"event_log": "hex-encoded-event-log",
24+
"vm_config": "json-vm-config-string",
25+
"pccs_url": "optional-pccs-url"
26+
}
27+
```
28+
29+
**Response:**
30+
```json
31+
{
32+
"is_valid": true,
33+
"details": {
34+
"quote_verified": true,
35+
"event_log_verified": true,
36+
"os_image_hash_verified": true,
37+
"report_data": "hex-encoded-64-byte-report-data",
38+
"tcb_status": "OK",
39+
"advisory_ids": [],
40+
"app_info": {
41+
"app_id": "hex-string",
42+
"compose_hash": "hex-string",
43+
"instance_id": "hex-string",
44+
"device_id": "hex-string",
45+
"mrtd": "hex-string",
46+
"rtmr0": "hex-string",
47+
"rtmr1": "hex-string",
48+
"rtmr2": "hex-string",
49+
"rtmr3": "hex-string",
50+
"mr_system": "hex-string",
51+
"mr_aggregated": "hex-string",
52+
"os_image_hash": "hex-string",
53+
"key_provider_info": "hex-string"
54+
}
55+
},
56+
"reason": null
57+
}
58+
```
59+
60+
### GET /health
61+
62+
Health check endpoint that returns service status.
63+
64+
**Response:**
65+
```json
66+
{
67+
"status": "ok",
68+
"service": "dstack-verifier"
69+
}
70+
```
71+
72+
## Configuration
73+
74+
Configuration can be provided via:
75+
1. TOML file (default: `dstack-verifier.toml`)
76+
2. Environment variables with prefix `DSTACK_VERIFIER_`
77+
3. Command line arguments
78+
79+
### Configuration Options
80+
81+
- `host`: Server bind address (default: "0.0.0.0")
82+
- `port`: Server port (default: 8080)
83+
- `image_cache_dir`: Directory for cached OS images (default: "/tmp/dstack-verifier/cache")
84+
- `image_download_url`: URL template for downloading OS images (default: GitHub releases URL)
85+
- `image_download_timeout_secs`: Download timeout in seconds (default: 300)
86+
- `pccs_url`: Optional PCCS URL for quote verification
87+
88+
### Example Configuration File
89+
90+
```toml
91+
host = "0.0.0.0"
92+
port = 8080
93+
image_cache_dir = "/var/cache/dstack-verifier"
94+
image_download_url = "http://0.0.0.0:8000/mr_{OS_IMAGE_HASH}.tar.gz"
95+
image_download_timeout_secs = 300
96+
pccs_url = "https://pccs.example.com"
97+
```
98+
99+
## Usage
100+
101+
```bash
102+
# Run with default config
103+
cargo run --bin dstack-verifier
104+
105+
# Run with custom config file
106+
cargo run --bin dstack-verifier -- --config /path/to/config.toml
107+
108+
# Set via environment variables
109+
DSTACK_VERIFIER_PORT=9000 cargo run --bin dstack-verifier
110+
```
111+
112+
## Testing
113+
114+
Two test scripts are provided for easy testing:
115+
116+
### Full Test (with server management)
117+
```bash
118+
./test.sh
119+
```
120+
This script will:
121+
- Build the project
122+
- Start the server
123+
- Run the verification test
124+
- Display detailed results
125+
- Clean up automatically
126+
127+
### Quick Test (assumes server is running)
128+
```bash
129+
./quick-test.sh
130+
```
131+
This script assumes the server is already running and just sends a test request.
132+
133+
## Verification Process
134+
135+
The verifier performs three main verification steps:
136+
137+
1. **Quote Verification**: Validates the TDX quote using dcap-qvl, checking the quote signature and TCB status
138+
2. **Event Log Verification**: Replays event logs to ensure RTMR values match and extracts app information
139+
3. **OS Image Hash Verification**:
140+
- Automatically downloads OS images if not cached locally
141+
- Uses dstack-mr to compute expected measurements
142+
- Compares against the verified measurements from the quote
143+
144+
All three steps must pass for the verification to be considered valid.
145+
146+
### Automatic Image Download
147+
148+
When an OS image is not found in the local cache, the verifier will:
149+
150+
1. **Download**: Fetch the image tarball from the configured URL
151+
2. **Extract**: Extract the tarball contents to a temporary directory
152+
3. **Verify**: Check SHA256 checksums to ensure file integrity
153+
4. **Validate**: Confirm the OS image hash matches the computed hash
154+
5. **Cache**: Move the validated files to the cache directory for future use
155+
156+
The download URL template uses `{OS_IMAGE_HASH}` as a placeholder that gets replaced with the actual OS image hash from the verification request.
157+
158+
## Dependencies
159+
160+
- dcap-qvl: TDX quote verification
161+
- dstack-mr: OS image measurement computation
162+
- ra-tls: Attestation handling and verification
163+
- rocket: HTTP server framework

0 commit comments

Comments
 (0)