Skip to content

Commit 16648d5

Browse files
committed
refactor reproducible and auditing mindset
1 parent 92665b7 commit 16648d5

15 files changed

Lines changed: 2740 additions & 75 deletions

tutorial/01-attestation/README.md

Lines changed: 121 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,24 @@ phala deploy -n tee-oracle -c docker-compose.yaml
6666

6767
## Verification
6868

69-
The quote contains measured values. Compare them against reference values you trust:
70-
71-
| Measured (from quote) | Reference | Source |
72-
|-----------------------|-----------|--------|
73-
| Intel signature | Intel root CA | Built into dcap-qvl |
74-
| MRTD, RTMR0-2 | Calculated from OS image | Download from [meta-dstack releases](https://github.com/Dstack-TEE/meta-dstack/releases) |
75-
| compose-hash (RTMR3) | `sha256(app-compose.json)` | Build from your docker-compose.yaml |
76-
| report_data | `sha256(statement)` | Hash the statement yourself |
69+
The quote contains **measured values**. Verification means comparing them against **reference values** you trust.
70+
71+
### Reference Values: Where They Come From
72+
73+
| Measured Value | Reference Value | Who Provides It |
74+
|----------------|-----------------|-----------------|
75+
| Intel signature | Intel root CA | Intel (built into dcap-qvl) |
76+
| MRTD, RTMR0-2 | Hash of OS image | [meta-dstack releases](https://github.com/Dstack-TEE/meta-dstack/releases) |
77+
| compose-hash (RTMR3) | `sha256(app-compose.json)` | **The developer** |
78+
| report_data | `sha256(statement)` | Computed from output |
7779
| tlsFingerprint | Certificate fingerprint | Fetch from api.coingecko.com |
7880

81+
This is the core insight: **attestation is only as trustworthy as your reference values.**
82+
83+
- Intel provides reference values for hardware authenticity
84+
- Dstack maintainers provide reference values for the OS layer
85+
- **The app developer must provide reference values for the application layer**
86+
7987
### Step 1: Validate Quote and Compare Measurements
8088

8189
Use the included Python script:
@@ -159,8 +167,110 @@ cat response.json | jq -r '.statement.tlsFingerprint'
159167

160168
---
161169

170+
## Critical Thinking: The Auditor's Perspective
171+
172+
> *This section appears throughout the tutorial. Each chapter examines a different trust assumption.*
173+
174+
### The Fundamental Question
175+
176+
As an auditor, your job is to answer: **"Does the deployed system behave according to the source code I reviewed?"**
177+
178+
TEE attestation helps, but only partially. The quote proves *some code* is running in isolated hardware. It gives you hashes. But hashes of what?
179+
180+
```
181+
┌─────────────────────────────────────────────────────────────────┐
182+
│ The Reference Value Problem │
183+
│ │
184+
│ What you audit: Source code, Dockerfile, docker-compose │
185+
│ What quote gives: compose-hash = 0x392b8a1f... │
186+
│ │
187+
│ The gap: Can you compute 0x392b8a1f from what you audited? │
188+
│ │
189+
└─────────────────────────────────────────────────────────────────┘
190+
```
191+
192+
### Trust Layers
193+
194+
Every TEE app has a trust stack. At each layer, ask: *"Where does the reference value come from?"*
195+
196+
| Layer | What You're Trusting | Reference Value Source |
197+
|-------|---------------------|------------------------|
198+
| Hardware | Intel TDX is secure | Intel's attestation infrastructure |
199+
| Firmware | No backdoors in BIOS/firmware | Platform vendor |
200+
| OS | Dstack boots what it claims | meta-dstack releases (open source, reproducible) |
201+
| App | Code matches what was audited | **Developer-provided** |
202+
203+
The bottom three layers have established reference value sources. The app layer is the developer's responsibility.
204+
205+
### How Auditing Actually Works
206+
207+
An auditor doesn't just read code—they run it. The workflow:
208+
209+
1. **Read source** — Form a mental model of intended behavior
210+
2. **Run locally** — Test that model: "does it actually do X? what happens if Y?"
211+
3. **Conclude** — "This code behaves as I understand it. It's safe."
212+
213+
The auditor's conclusion is based on **what they ran**, not what they read. Reading code is necessary but not sufficient—you have to see it execute.
214+
215+
### The Behavioral Gap Threat
216+
217+
Here's the problem: what the auditor ran locally might differ from what's deployed.
218+
219+
```
220+
┌─────────────────────────────────────────────────────────────────┐
221+
│ The Behavioral Gap │
222+
│ │
223+
│ Auditor builds locally → observes behavior A → "safe" │
224+
│ Production build → has behavior B (subtly different) │
225+
│ Attestation proves → production runs *something* │
226+
│ │
227+
│ The auditor certified behavior A. │
228+
│ Production has behavior B. │
229+
│ The audit doesn't apply. │
230+
└─────────────────────────────────────────────────────────────────┘
231+
```
232+
233+
This gap can arise from:
234+
- Different dependency versions resolved at build time
235+
- Timestamps or randomness affecting behavior
236+
- Build environment differences (compiler, OS, architecture)
237+
- Intentional divergence (malicious or accidental)
238+
239+
**The hash question isn't abstract.** When an auditor asks "does my local build produce the same hash as production?"—they're really asking: *"Is my local model of the system actually the production system, or just a similar-looking approximation?"*
240+
241+
### What Reproducibility Actually Provides
242+
243+
Reproducibility closes the behavioral gap. If:
244+
- Auditor builds from source → gets hash X
245+
- Production attestation shows → hash X
246+
247+
Then the auditor's local testing environment **is** the production system. Their conclusions apply. The audit is meaningful.
248+
249+
Without reproducibility, the auditor has two options:
250+
1. **Trust the developer's build** — "I audited something similar, probably fine"
251+
2. **Pull the production image and diff manually** — Tedious, error-prone, incomplete
252+
253+
Neither is satisfactory. Reproducibility makes the audit rigorous.
254+
255+
### The Smart Contract Analogy
256+
257+
Smart contracts solved this problem:
258+
- Source code on Etherscan
259+
- Compiler version specified
260+
- Anyone can recompile and verify the bytecode matches on-chain codehash
261+
- DYOR is actually possible
262+
263+
TEE apps need the same pattern. The attestation is like the on-chain codehash. But without reproducible builds, there's no way to connect it back to auditable source.
264+
265+
---
266+
267+
**Next:** [01a-reproducible-builds](../01a-reproducible-builds) shows how developers can provide the evidence auditors need—and protect against bitrot that breaks verification over time.
268+
269+
---
270+
162271
## Next Steps
163272

273+
- [01a-reproducible-builds](../01a-reproducible-builds): Make builds verifiable for auditors
164274
- [02-kms-and-signing](../02-kms-and-signing): Derive persistent keys and sign messages
165275
- [03-gateway-and-tls](../03-gateway-and-tls): Custom domains and TLS
166276

@@ -173,7 +283,7 @@ cat response.json | jq -r '.statement.tlsFingerprint'
173283

174284
```
175285
01-attestation/
176-
├── docker-compose.yaml # Oracle app (self-contained)
177-
├── verify_full.py # Python verification script
178-
└── README.md # This file
286+
├── docker-compose.yaml # Oracle app (quick-start, non-reproducible)
287+
├── verify_full.py # Attestation verification script
288+
└── README.md
179289
```
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Reproducible build for TEE Oracle
2+
# See README.md "Critical Thinking About TEE Apps" for why this matters
3+
4+
ARG SOURCE_DATE_EPOCH=0
5+
6+
# Pin base image by digest, not tag
7+
FROM node:22-slim@sha256:773413f36941ce1e4baf74b4a6110c03dcc4f968daffc389d4caef3f01412d2a
8+
9+
ARG SOURCE_DATE_EPOCH
10+
ENV SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH}
11+
ENV npm_config_cache=/tmp/npm-cache
12+
13+
WORKDIR /app
14+
15+
# Copy lockfile first for layer caching
16+
COPY package.json package-lock.json ./
17+
18+
# Install with ci (uses lockfile exactly) and clean all caches
19+
# NODE_COMPILE_CACHE creates non-deterministic bytecode - must be disabled or cleaned
20+
RUN npm ci --omit=dev --ignore-scripts && \
21+
rm -rf /tmp/npm-cache /tmp/node-compile-cache && \
22+
find /app -exec touch -d "@${SOURCE_DATE_EPOCH}" {} + 2>/dev/null || true
23+
24+
COPY app.mjs ./
25+
RUN touch -d "@${SOURCE_DATE_EPOCH}" /app/app.mjs
26+
27+
CMD ["node", "app.mjs"]

0 commit comments

Comments
 (0)