|
| 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