Skip to content

Commit 3509171

Browse files
h4x3rotabclaude
andcommitted
feat(kms): add auth-simple config-based authorization server
Add auth-simple as a production-ready alternative to auth-eth for operators who prefer config-file-based whitelisting over on-chain governance. New components: - kms/auth-simple/: Hono-based webhook server with Zod validation - kms/dstack-app/compose-simple.yaml: KMS compose for external auth - kms/dstack-app/deploy-simple.sh: Deploy script for auth-simple mode Auth server ecosystem: - auth-simple: Config-file whitelisting (production, centralized) - auth-eth: Smart contract governance (production, decentralized) - auth-mock: Always allows (dev/testing only) Documentation: - docs/deployment.md: Simplified auth-simple config for initial deploy - docs/auth-simple-operations.md: Day-to-day operations guide 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 6d23c43 commit 3509171

12 files changed

Lines changed: 1919 additions & 93 deletions

docs/auth-simple-operations.md

Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
# auth-simple Operations Guide
2+
3+
This guide covers day-to-day operations for managing apps and devices with auth-simple.
4+
5+
For initial deployment setup, see [Deployment Guide](./deployment.md).
6+
7+
## Overview
8+
9+
auth-simple uses a JSON config file to whitelist:
10+
- **OS images** - Which guest OS versions can boot
11+
- **KMS nodes** - Which KMS instances can onboard (mrAggregated, devices)
12+
- **Apps** - Which applications can boot (appId, composeHash, devices)
13+
14+
The config is re-read on each request, so changes take effect immediately without restart.
15+
16+
---
17+
18+
## Config File Structure
19+
20+
```json
21+
{
22+
"osImages": ["0x..."],
23+
"gatewayAppId": "0x...",
24+
"kms": {
25+
"mrAggregated": ["0x..."],
26+
"devices": ["0x..."],
27+
"allowAnyDevice": true
28+
},
29+
"apps": {
30+
"0x<app-id>": {
31+
"composeHashes": ["0x..."],
32+
"devices": ["0x..."],
33+
"allowAnyDevice": true
34+
}
35+
}
36+
}
37+
```
38+
39+
> **Note:** Only `osImages` is required. Add `gatewayAppId` after deploying the Gateway. Add `apps` entries as you deploy applications.
40+
41+
---
42+
43+
## Adding an App
44+
45+
### Step 1: Generate App ID
46+
47+
App IDs are typically the contract address (for on-chain) or a unique identifier you choose.
48+
49+
For auth-simple, you can use any unique hex string (40 characters / 20 bytes):
50+
51+
```bash
52+
# Generate a random app ID
53+
openssl rand -hex 20
54+
# Output: 7a3b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b
55+
```
56+
57+
### Step 2: Get Compose Hash
58+
59+
The compose hash is computed from the normalized docker-compose file. The VMM displays it when deploying:
60+
61+
```
62+
Docker compose file:
63+
...
64+
Compose hash: 0x700a50336df7c07c82457b116e144f526c29f6d8...
65+
```
66+
67+
Or query from a running CVM:
68+
69+
```bash
70+
curl -s --unix-socket /var/run/dstack.sock http://localhost/Info | \
71+
jq -r '"0x" + (.tcb_info | fromjson | .compose_hash)'
72+
```
73+
74+
> **Note:** The VMM normalizes YAML to JSON before hashing. For exact hash, use the value shown during deployment.
75+
76+
### Step 3: Add to Config
77+
78+
Edit your `auth-config.json`:
79+
80+
```json
81+
{
82+
"apps": {
83+
"0x7a3b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b": {
84+
"composeHashes": [
85+
"0x700a50336df7c07c82457b116e144f526c29f6d8..."
86+
],
87+
"devices": [],
88+
"allowAnyDevice": true
89+
}
90+
}
91+
}
92+
```
93+
94+
### Step 4: Deploy via VMM
95+
96+
Use the App ID when deploying through VMM:
97+
98+
```bash
99+
./vmm-cli.py deploy \
100+
--app-id 7a3b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b \
101+
--compose docker-compose.yaml \
102+
...
103+
```
104+
105+
---
106+
107+
## Updating an App
108+
109+
When you change your docker-compose.yaml, a new compose hash is generated.
110+
111+
### Add New Hash (Keep Old Running)
112+
113+
Add the new hash to the `composeHashes` array:
114+
115+
```json
116+
{
117+
"apps": {
118+
"0x<app-id>": {
119+
"composeHashes": [
120+
"0x<old-hash>",
121+
"0x<new-hash>"
122+
]
123+
}
124+
}
125+
}
126+
```
127+
128+
### Replace Hash (Force Upgrade)
129+
130+
Remove the old hash to prevent old versions from booting:
131+
132+
```json
133+
{
134+
"apps": {
135+
"0x<app-id>": {
136+
"composeHashes": [
137+
"0x<new-hash>"
138+
]
139+
}
140+
}
141+
}
142+
```
143+
144+
---
145+
146+
## Device Management
147+
148+
Devices are identified by their TDX device ID (hardware-specific).
149+
150+
### Get Device ID
151+
152+
The `deviceId` is sent by the booting app/KMS in its auth request. Check auth-simple logs:
153+
154+
```
155+
app boot auth request: { appId: '0x...', deviceId: '0x...', ... }
156+
```
157+
158+
> **Tip:** Use `allowAnyDevice: true` initially, then restrict to specific devices after capturing IDs from logs.
159+
160+
### Restrict App to Specific Devices
161+
162+
```json
163+
{
164+
"apps": {
165+
"0x<app-id>": {
166+
"composeHashes": ["0x..."],
167+
"devices": [
168+
"0xe5a0c70bb6503de2d31c11d85914fe3776ed5b33a078ed856327c371a60fe0fd"
169+
],
170+
"allowAnyDevice": false
171+
}
172+
}
173+
}
174+
```
175+
176+
### Allow Any Device
177+
178+
For initial testing or when device restriction isn't needed:
179+
180+
```json
181+
{
182+
"apps": {
183+
"0x<app-id>": {
184+
"allowAnyDevice": true
185+
}
186+
}
187+
}
188+
```
189+
190+
---
191+
192+
## Removing an App
193+
194+
Delete the app entry from the `apps` object:
195+
196+
```json
197+
{
198+
"apps": {
199+
// "0x<removed-app-id>": { ... } <- deleted
200+
}
201+
}
202+
```
203+
204+
Running instances will continue until restarted. New boot requests will be rejected.
205+
206+
---
207+
208+
## Setting the Gateway App (After Gateway Deployment)
209+
210+
The `gatewayAppId` field is **optional** during initial KMS deployment. Add it after deploying the Gateway.
211+
212+
The Gateway is a special app that routes traffic to other apps. Once deployed, add its App ID to your config:
213+
214+
```json
215+
{
216+
"gatewayAppId": "0x75537828f2ce51be7289709686A69CbFDbB714F1",
217+
"apps": {
218+
"0x75537828f2ce51be7289709686A69CbFDbB714F1": {
219+
"composeHashes": ["0x..."],
220+
"allowAnyDevice": true
221+
}
222+
}
223+
}
224+
```
225+
226+
The `gatewayAppId` is returned in boot responses and used by KMS for key derivation.
227+
228+
---
229+
230+
## KMS Onboarding (Multi-Node)
231+
232+
To allow additional KMS nodes to onboard (receive root keys from the primary KMS), whitelist their `mrAggregated` value.
233+
234+
### Get mrAggregated
235+
236+
The `mrAggregated` is sent by the booting KMS in its auth request. To get this value:
237+
238+
1. **From auth-simple logs**: When a KMS boots, auth-simple logs the mrAggregated:
239+
```
240+
KMS boot auth request: { osImageHash: '0x...', mrAggregated: '0x...', ... }
241+
```
242+
243+
2. **Initial setup**: Leave `kms.mrAggregated` empty for the first KMS (empty array allows any). After it boots, check the logs and add the value.
244+
245+
### Add to Config
246+
247+
```json
248+
{
249+
"kms": {
250+
"mrAggregated": ["0x<mr-aggregated-hash>"],
251+
"allowAnyDevice": true
252+
}
253+
}
254+
```
255+
256+
> **Note:** All KMS nodes using the same OS image and compose will have the same mrAggregated, so you only need to capture it once.
257+
258+
---
259+
260+
## Verification
261+
262+
### Check Config is Valid
263+
264+
```bash
265+
curl -s http://localhost:3001/ | jq
266+
```
267+
268+
Returns current config status including `gatewayAppId`.
269+
270+
### Test Boot Authorization
271+
272+
```bash
273+
# Test app boot
274+
curl -s -X POST http://localhost:3001/bootAuth/app \
275+
-H "Content-Type: application/json" \
276+
-d '{
277+
"appId": "0x<app-id>",
278+
"composeHash": "0x<compose-hash>",
279+
"osImageHash": "0x<os-image-hash>",
280+
"deviceId": "0x<device-id>",
281+
"mrAggregated": "0x...",
282+
"instanceId": "0x...",
283+
"tcbStatus": "UpToDate"
284+
}' | jq
285+
```
286+
287+
Expected responses:
288+
- `{"isAllowed": true, ...}` - App is authorized
289+
- `{"isAllowed": false, "reason": "app not registered", ...}` - App ID not in config
290+
- `{"isAllowed": false, "reason": "compose hash not allowed", ...}` - Hash not whitelisted
291+
292+
---
293+
294+
## See Also
295+
296+
- [Deployment Guide](./deployment.md) - Initial setup
297+
- [auth-simple README](../kms/auth-simple/README.md) - Developer reference
298+
- [On-Chain Governance](./onchain-governance.md) - Smart contract-based alternative

0 commit comments

Comments
 (0)