Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
162 commits
Select commit Hold shift + click to select a range
4b05277
docs: add KMS emergency key rotation protocol design
kvinwang Nov 6, 2026
dac94a1
kms: register root key epochs on chain and gate auth on the current one
kvinwang Nov 6, 2026
274e36d
fix(kms): reject invalid root epoch configuration
kvinwang Nov 6, 2026
064f759
fix(kms): bind root epoch activation to its chain hash
kvinwang Nov 6, 2026
220480b
fix(kms): require root epoch registry support in auth backends
kvinwang Nov 6, 2026
7b76414
fix(kms): bind epoch evidence updates to their chain hash
kvinwang Nov 6, 2026
c9427b5
fix(kms): keep evidence URL updates independent of chain hashes
kvinwang Nov 7, 2026
ef26d46
fix(kms): remove legacy identity setters
kvinwang Nov 8, 2026
92525da
fix(ci): pin SDK tests to supported Python 3.11
kvinwang Nov 8, 2026
21f356f
kms: keep a keyring of all root epochs and serve the current one
kvinwang Nov 6, 2026
533d18d
feat(kms): unify authorization and return the current root epoch
kvinwang Nov 6, 2026
1a778c9
style(kms): format authorization regression test
kvinwang Nov 6, 2026
61ccda2
feat(kms): select requested epochs from authorization results
kvinwang Nov 6, 2026
c3e9319
refactor(kms): rename rejectionReason consistently
kvinwang Nov 6, 2026
2f3d785
test(kms): retain hash-bound activation after rebase
kvinwang Nov 7, 2026
f697616
refactor(kms): remove temporary CA bootstrap and fetch keys directly
kvinwang Nov 7, 2026
9c90d54
docs(kms): align unreleased notes with direct key retrieval
kvinwang Nov 7, 2026
8237ca9
docs(kms): record temporary CA protocol retirement
kvinwang Nov 7, 2026
846180f
refactor(ra-rpc): name CA bypass explicitly and isolate TLS configura…
kvinwang Nov 7, 2026
8fdbd3d
refactor(kms): separate KMS and app authorization and reserve app epochs
kvinwang Nov 7, 2026
91934bd
fix(cert-client): keep KMS CA pins independent of root epoch selection
kvinwang Nov 7, 2026
f8dff0a
refactor(kms): name requested root and app epochs explicitly
kvinwang Nov 7, 2026
ee4be5a
feat(kms): reserve optional app epochs and report currentAppEpoch
kvinwang Nov 7, 2026
2f0968e
refactor(kms): split authorization by caller kind
kvinwang Nov 7, 2026
4a2a8d1
refactor(kms): rename authorization endpoints consistently
kvinwang Nov 7, 2026
de25eab
refactor(kms): name optional integer wrapper explicitly
kvinwang Nov 7, 2026
3eefe36
refactor(kms): name optional uint256 wrapper precisely
kvinwang Nov 7, 2026
697920c
test(cert-client): retain direct retrieval TLS authentication coverage
kvinwang Nov 7, 2026
913ce0c
fix(auth): implement epoch authorization in the local backend
kvinwang Nov 8, 2026
bff2fd9
style(auth-eth): format epoch authorization declarations
kvinwang Nov 8, 2026
3587d24
refactor(kms): separate app and handover authorization
kvinwang Nov 8, 2026
fdf0e31
fix(kms): retain temporary CA compatibility for existing clients
kvinwang Nov 8, 2026
8608761
feat(kms): authorize explicit operations on both sides of handover
kvinwang Nov 8, 2026
35772d8
refactor(auth): name app certificate retrieval explicitly
kvinwang Nov 8, 2026
27bf966
refactor(auth): prefix operations with their subject scope
kvinwang Nov 8, 2026
65180ea
refactor(kms): align Rust authorization method names
kvinwang Nov 8, 2026
0a8f311
style(auth): format scoped operations in the base PR
kvinwang Nov 8, 2026
46c5ec2
style(auth): format scoped Solidity operation predicates
kvinwang Nov 8, 2026
2ca1679
refactor(dstack-util): move app key retrieval to shared setup state
kvinwang Nov 7, 2026
e7bacf8
feat(dstack-util): re-key data disks left on an older KMS root epoch
kvinwang Nov 7, 2026
0455c68
refactor(dstack-util): simplify shared app key request name
kvinwang Nov 7, 2026
37b9e08
refactor(dstack-util): keep disk header operations in luks module
kvinwang Nov 8, 2026
5c42c47
guest-agent: derive GetKey keys under a selected KMS root epoch
kvinwang Nov 6, 2026
839785d
fix(guest): release epoch cache lock during key fetch
kvinwang Nov 8, 2026
9b236bf
fix(sdk): validate root epochs as uint32
kvinwang Nov 8, 2026
067897d
test(sdk): initialize root epoch in key response fixture
kvinwang Nov 8, 2026
0e6ff36
feat: seal environment variables with epoch-aware HPKE
kvinwang Nov 7, 2026
999a4be
refactor(sealed-env): encode binary fields with serde
kvinwang Nov 7, 2026
6bdc417
feat(sealed-env): reserve app epochs and gate encryption by image cap…
kvinwang Nov 7, 2026
7e3a956
fix(vmm): reject SealedEnv for incompatible guest images
kvinwang Nov 7, 2026
30953cf
refactor(kms): serve only current environment public keys
kvinwang Nov 7, 2026
b8f2def
fix(sealed-env): preserve current ciphertext and honor image capabili…
kvinwang Nov 7, 2026
90f6bd9
fix(guest): try accessible roots when migrating legacy env
kvinwang Nov 8, 2026
3672f39
fix(sealed-env): reject unauthenticated protocol downgrade
kvinwang Nov 8, 2026
512e684
refactor(dstack-util): isolate sealed environment encoding
kvinwang Nov 8, 2026
f8906e7
fix(vmm): validate sealed environment support before one-shot setup
kvinwang Nov 8, 2026
5e1fd5e
style(sealed-env): satisfy Python checks across CLI and SDK
kvinwang Nov 8, 2026
c5d06f4
fix(sealed-env): accept uppercase public key prefixes
kvinwang Nov 8, 2026
2fb6492
docs(sdk): place sealed environment guidance before license
kvinwang Nov 8, 2026
a31bc5d
docs(sealed-env): state browser signer verification limits
kvinwang Nov 8, 2026
48ee692
test(vmm): verify sealed env injection and transport isolation
kvinwang Nov 8, 2026
90c9459
fix(kms): use scoped serve operation for sealed environment keys
kvinwang Nov 8, 2026
da5089a
test(sdk): avoid duplicate epoch in sealed environment fixture
kvinwang Nov 8, 2026
c5fd176
feat(kms): rotate application keys independently of root epochs
kvinwang Nov 7, 2026
8fc8a74
fix(auth-simple): normalize app IDs when selecting epochs
kvinwang Nov 8, 2026
05e004e
fix(auth): support application epochs in the local backend
kvinwang Nov 8, 2026
04b58ca
refactor(auth-simple): reuse the app policy across authorization checks
kvinwang Nov 8, 2026
5543e7e
docs(kms): include the application epoch in authorization responses
kvinwang Nov 8, 2026
ae04475
style(sdk): format epoch-aware Python key requests
kvinwang Nov 8, 2026
0dd4fad
fix(cert-client): preserve optional app key epoch selectors
kvinwang Nov 8, 2026
bfd13af
style(guest): group key epoch fields in setup initializers
kvinwang Nov 8, 2026
57822fe
docs(kms): clarify rotation features and disk rollback
kvinwang Nov 8, 2026
ddf13de
test(auth): carry operations through application epoch checks
kvinwang Nov 8, 2026
48d151d
test(sdk): retain paired epoch fixture after app epoch rebase
kvinwang Nov 8, 2026
1ec0d4b
feat(auth-eth): scope material allowlists to exact key epochs
kvinwang Nov 7, 2026
c8d8b96
refactor(auth-eth): name epoch-aware app authorization consistently
kvinwang Nov 7, 2026
e8198a1
docs(kms): describe highest-epoch handover authorization
kvinwang Nov 8, 2026
b05d34d
feat(auth-eth): forward operations to epoch-scoped app policies
kvinwang Nov 8, 2026
276e44a
test(auth): use the app certificate retrieval operation
kvinwang Nov 8, 2026
8945cb6
test(auth): use scoped app certificate operation
kvinwang Nov 8, 2026
e29f743
refactor(kms): consolidate app epoch policy interface
kvinwang Nov 8, 2026
08b3f26
test(auth): verify scoped operations on the HTTP wire
kvinwang Nov 8, 2026
bace10c
fix(auth-eth): report the current root epoch in wrong-kind rejections
kvinwang Nov 9, 2026
3e807ac
Merge pull request #1538 from Dstack-TEE/fix/auth-rejection-root-epoch
kvinwang Nov 9, 2026
b544849
fix(auth-eth): pin legacy authorization checks to epoch 0
kvinwang Nov 9, 2026
c3e6d63
fix(guest): migrate LUKS key epochs in place with atomic steps
kvinwang Nov 9, 2026
1c04d3f
fix(auth-eth): apply epoch-less KMS setters from current to pending rows
kvinwang Nov 9, 2026
f461393
test(kms): cover every check on the key handover path
kvinwang Nov 9, 2026
d81cf50
test(auth): assert backends honor the requested operation and epochs
kvinwang Nov 9, 2026
6bd5c15
docs(auth-eth-bun): describe the finality confirmation trade-off
kvinwang Nov 9, 2026
bf76318
Revert "docs(auth-eth-bun): describe the finality confirmation trade-…
kvinwang Nov 9, 2026
81ebdec
fix(auth-eth): let app owners prepare the next app epoch before advan…
kvinwang Nov 9, 2026
b1c2760
fix(auth): fail closed when the app epoch cannot be determined
kvinwang Nov 9, 2026
35e027f
fix(auth): stop serving pre-epoch KMS binaries once a rotation is active
kvinwang Nov 9, 2026
e7e6a1e
fix(auth-eth): refuse the legacy DstackApp check at a nonzero app epoch
kvinwang Nov 9, 2026
170fc4a
fix(auth-eth): key root epoch policy rows by chain hash
kvinwang Nov 9, 2026
b27b66a
fix(dstack-auth): treat empty device and OS image lists as allowing n…
kvinwang Nov 9, 2026
8d93767
test(auth-eth): validate upgrades from the deployed contract releases
kvinwang Nov 9, 2026
190565c
chore(auth-eth): keep verbatim release references out of forge fmt
kvinwang Nov 9, 2026
a8343c1
docs(kms): scope the legacy source certificate fallback
kvinwang Nov 9, 2026
116eb99
fix(kms): refuse onboarding sources without an OS image hash
kvinwang Nov 9, 2026
7d8c9e4
docs(vmm-cli): remove the old KMS signer after a root rotation
kvinwang Nov 9, 2026
8314ab7
docs(kms): describe skipping refused epochs in legacy env migration
kvinwang Nov 9, 2026
6420a3f
docs(kms): leave re-sealed env verification to integration tests
kvinwang Nov 9, 2026
0886782
docs(kms): correct self-check caching notes and scope relaxation swit…
kvinwang Nov 9, 2026
842c5a1
docs(auth-eth): mark legacy getters and events as epoch 0 only
kvinwang Nov 9, 2026
c3b0afd
docs(kms): recommend rather than require admin authorization for rota…
kvinwang Nov 9, 2026
2db9d40
fix(kms): attest every rotated root epoch with the v1 bootstrap encoding
kvinwang Nov 9, 2026
8735ab4
docs(auth-eth): describe what in the root epoch registry is immutable
kvinwang Nov 9, 2026
dbd7004
fix(kms): create historical root epoch directories durably
kvinwang Nov 9, 2026
ddff6b3
docs(guest-agent): describe what the historical root cache actually does
kvinwang Nov 9, 2026
8d215d4
docs(sdk): warn against holding assets in derived wallets
kvinwang Nov 9, 2026
a0863da
fix(kms): cache app epochs read by the env public key RPCs
kvinwang Nov 9, 2026
ee73e17
fix(guest): resume a LUKS migration interrupted before a later rotation
kvinwang Nov 9, 2026
29605ec
docs(guest): note the interrupted-then-rotated case in sync_luks_epochs
kvinwang Nov 9, 2026
e4a3c54
Merge pull request #1539 from Dstack-TEE/fix/pr1533-review-decisions
kvinwang Nov 9, 2026
d488db6
feat(kms): audit key releases on both listeners
kvinwang Nov 9, 2026
76a0149
test(kms): adapt key release audit to the handover tests and count re…
kvinwang Nov 9, 2026
5fcc62f
Merge pull request #1540 from Dstack-TEE/feat/kms-key-release-audit
kvinwang Nov 9, 2026
e9e761d
refactor(kms): rename AuthorizationResult.isAllowed to authorized
kvinwang Nov 9, 2026
6fbf0f8
refactor(kms): forward AuthorizationRequest to app epoch policies
kvinwang Nov 9, 2026
82026c9
fix(auth): return AuthorizationResult shape for rejected authorize re…
kvinwang Nov 9, 2026
961f88c
feat(auth): report the latest registered root epoch in authorization …
kvinwang Nov 9, 2026
b7f2cd0
fix(kms): check onboarding handovers against the latest registered ro…
kvinwang Nov 9, 2026
e564535
fix(kms): refuse a handover tail that stops short of the latest epoch
kvinwang Nov 9, 2026
5162574
test(auth): adapt tests merged in #1539 to the unified authorization …
kvinwang Nov 9, 2026
7bcc23f
refactor(auth-eth): rename the private KMS policy helper to _kmsPolicy
kvinwang Nov 9, 2026
be23bf1
Merge pull request #1542 from Dstack-TEE/refactor/authorization-resul…
kvinwang Nov 9, 2026
adc189d
Merge pull request #1544 from Dstack-TEE/refactor/authorization-polic…
kvinwang Nov 9, 2026
619f24f
feat(auth-eth): read policy at a configurable block tag, finalized by…
kvinwang Nov 9, 2026
a2e62a9
feat(auth-eth): refuse to start when the RPC cannot serve ETH_BLOCK_TAG
kvinwang Nov 9, 2026
8bda194
test(auth-eth): adapt block tag tests to the latest root epoch fields
kvinwang Nov 9, 2026
2536f2c
Merge pull request #1543 from Dstack-TEE/feat/auth-eth-block-tag
kvinwang Nov 9, 2026
ef9331d
fix(vmm): normalize pinned KMS signer prefixes
kvinwang Nov 8, 2026
fc81d86
Merge pull request #1535 from Dstack-TEE/fix/vmm-kms-signer-prefix
kvinwang Nov 9, 2026
d659510
fix(auth-eth): refuse legacy authorization once a later root epoch is…
kvinwang Nov 9, 2026
ff136ad
fix(guest): start applications only after the env update window is cl…
kvinwang Nov 9, 2026
d1608cd
Merge pull request #1546 from Dstack-TEE/fix/sealed-env-window-fail-c…
kvinwang Nov 9, 2026
e974ce1
Merge pull request #1545 from Dstack-TEE/fix/legacy-auth-reject-rotated
kvinwang Nov 9, 2026
60fa172
test(auth-eth): add Halmos symbolic tests for DstackApp app epochs
kvinwang Nov 9, 2026
791cc22
test(auth-eth): prove DstackApp authorization matches epoch policy
kvinwang Nov 9, 2026
5523b07
test(auth-eth): add Halmos symbolic tests for DstackKms root epochs
kvinwang Nov 9, 2026
b4cbe2b
test(auth-eth): sync the epoch symbolic tests with the reviewed contr…
kvinwang Nov 9, 2026
0d6f266
docs(formal): add TLA+ models of the key rotation protocol
kvinwang Nov 9, 2026
45ed57f
docs(formal): sync the key rotation models with the reviewed implemen…
kvinwang Nov 9, 2026
297a1e2
test(auth-eth): check that legacy entry points refuse once rotated
kvinwang Nov 9, 2026
e43bb2c
Merge pull request #1537 from Dstack-TEE/test/halmos-app-epoch
kvinwang Nov 9, 2026
ecaf4e7
Merge pull request #1541 from Dstack-TEE/docs/key-rotation-model
kvinwang Nov 9, 2026
15fafad
chore(kms): remove the auth-mock webhook backend
kvinwang Nov 9, 2026
3d953a6
Merge pull request #1547 from Dstack-TEE/chore/remove-auth-mock
kvinwang Nov 9, 2026
d83ed68
feat(dstack-auth): accept the full auth-simple config, with opt-in TC…
kvinwang Nov 9, 2026
5d6457e
chore(kms): remove auth-simple in favor of dstack-auth
kvinwang Nov 9, 2026
de64795
docs: migrate auth-simple references to dstack-auth
kvinwang Nov 9, 2026
889d022
Merge pull request #1548 from Dstack-TEE/chore/replace-auth-simple-wi…
kvinwang Nov 9, 2026
5bea4f5
chore(kms): remove the Node auth-eth webhook server
kvinwang Nov 9, 2026
aded7ab
chore(kms): rename auth-eth-bun to auth-eth
kvinwang Nov 9, 2026
15999eb
Merge pull request #1549 from Dstack-TEE/chore/remove-auth-eth-server
kvinwang Nov 9, 2026
bf19f4c
Merge pull request #1550 from Dstack-TEE/chore/rename-auth-eth-bun
kvinwang Nov 9, 2026
b229b8a
ci(prek): skip whitespace fixers on reference contracts
kvinwang Nov 10, 2026
d32b6e0
Merge pull request #1551 from Dstack-TEE/fix/prek-exclude-reference-c…
kvinwang Nov 10, 2026
2388ea1
feat(kms)!: turn off the public KMS key handover by default
kvinwang Nov 10, 2026
ba34bd9
Merge pull request #1552 from Dstack-TEE/chore/kms-public-key-handove…
kvinwang Nov 10, 2026
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
6 changes: 5 additions & 1 deletion .github/workflows/foundry-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@ jobs:
id: build

- name: Install OpenZeppelin upgrades validator
run: npm install --no-save --package-lock=false @openzeppelin/upgrades-core@^1.37.0
# The upgrade-safety tests run `npx @openzeppelin/upgrades-core@^1.37.0`;
# warm the npx cache with that spec once so parallel tests reuse it.
# `npm install` here would also resolve the webhook server's
# package.json, which is managed by Bun.
run: npx --yes @openzeppelin/upgrades-core@^1.37.0 --help > /dev/null

- name: Run Forge tests
# The upgrade-safety validator rejects a contract found in more than one
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,41 @@
#
# SPDX-License-Identifier: Apache-2.0

name: KMS auth-eth-bun
name: KMS auth-eth

# The auth-eth-bun webhook ships on its own cadence, separate from the KMS
# image: a `kms-auth-eth-bun-v*` tag publishes
# ghcr.io/dstack-tee/dstack-kms-auth-eth-bun:<version>. Pull requests and
# The auth-eth webhook ships on its own cadence, separate from the KMS
# image: a `kms-auth-eth-v*` tag publishes
# ghcr.io/dstack-tee/dstack-kms-auth-eth:<version>. Pull requests and
# pushes that touch the backend run the checks and build the image without
# pushing it.
on:
workflow_dispatch:
inputs:
version:
description: Existing release tag version without the kms-auth-eth-bun-v prefix
description: Existing release tag version without the kms-auth-eth-v prefix
required: true
type: string
push:
branches: [ next, 'release/**' ]
tags:
- 'kms-auth-eth-bun-v*'
- 'kms-auth-eth-v*'
# Top-level files only: the server lives next to the Foundry project, whose
# contracts/, lib/, test/ and script/ are covered by foundry-test.yml.
paths:
- 'dstack/kms/auth-eth-bun/**'
- '.github/workflows/kms-auth-eth-bun.yml'
- 'dstack/kms/auth-eth/*'
- '.github/workflows/kms-auth-eth.yml'
pull_request:
branches: [ next, 'release/**' ]
paths:
- 'dstack/kms/auth-eth-bun/**'
- '.github/workflows/kms-auth-eth-bun.yml'
- 'dstack/kms/auth-eth/*'
- '.github/workflows/kms-auth-eth.yml'

permissions:
contents: read

env:
IMAGE: ghcr.io/dstack-tee/dstack-kms-auth-eth-bun
BACKEND_DIR: dstack/kms/auth-eth-bun
IMAGE: ghcr.io/dstack-tee/dstack-kms-auth-eth
BACKEND_DIR: dstack/kms/auth-eth

jobs:
check:
Expand All @@ -43,7 +45,7 @@ jobs:
- name: Checkout repository
uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
with:
ref: ${{ github.event_name == 'workflow_dispatch' && format('kms-auth-eth-bun-v{0}', inputs.version) || github.sha }}
ref: ${{ github.event_name == 'workflow_dispatch' && format('kms-auth-eth-v{0}', inputs.version) || github.sha }}
persist-credentials: false

- name: Set up Bun
Expand Down Expand Up @@ -88,7 +90,7 @@ jobs:
VERSION=$DISPATCH_VERSION
else
case "$GITHUB_REF" in
refs/tags/kms-auth-eth-bun-v*) VERSION=${GITHUB_REF#refs/tags/kms-auth-eth-bun-v} ;;
refs/tags/kms-auth-eth-v*) VERSION=${GITHUB_REF#refs/tags/kms-auth-eth-v} ;;
esac
fi
if [ -n "$VERSION" ]; then
Expand All @@ -107,7 +109,7 @@ jobs:
- name: Checkout repository
uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
with:
ref: ${{ github.event_name == 'workflow_dispatch' && format('kms-auth-eth-bun-v{0}', inputs.version) || github.sha }}
ref: ${{ github.event_name == 'workflow_dispatch' && format('kms-auth-eth-v{0}', inputs.version) || github.sha }}
persist-credentials: false

- name: Resolve the revision to build
Expand Down Expand Up @@ -151,12 +153,12 @@ jobs:
IMAGE_DIGEST: ${{ steps.build.outputs.digest }}
run: |
token=$(curl -fsSL \
"https://ghcr.io/token?scope=repository:dstack-tee/dstack-kms-auth-eth-bun:pull" \
"https://ghcr.io/token?scope=repository:dstack-tee/dstack-kms-auth-eth:pull" \
| jq -er .token)
curl -fsSL -o /dev/null \
-H "Authorization: Bearer $token" \
-H "Accept: application/vnd.oci.image.manifest.v1+json, application/vnd.docker.distribution.manifest.v2+json" \
"https://ghcr.io/v2/dstack-tee/dstack-kms-auth-eth-bun/manifests/$IMAGE_DIGEST"
"https://ghcr.io/v2/dstack-tee/dstack-kms-auth-eth/manifests/$IMAGE_DIGEST"

- name: Generate artifact attestation
if: env.PUBLISH == '1'
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/sdk.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ jobs:
# the entries that are actually shared.
save-if: ${{ github.event_name == 'push' }}

- name: Set up Python
if: steps.changes.outputs.relevant == 'true'
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: SDK tests
if: steps.changes.outputs.relevant == 'true'
run: cd sdk && ./run-tests.sh
Expand Down
83 changes: 72 additions & 11 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,89 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- KMS root and application key epochs, epoch-scoped authorization, SealedEnv
HPKE encryption, automatic environment migration, and epoch-aware SDK key
selection.
- dstack-auth: opt-in `allowedTcbStatuses` and `allowedAdvisoryIds` allowlists,
applied to app and KMS requests on `/authorize*` and `/bootAuth/*`. When set,
a `tcbStatus` outside the list, or any advisory ID outside the list, denies;
when absent, neither is checked. `GET /` reports the configured `chainId` and
`appImplementation`, and each decision is logged with the device ID,
measurements and TCB status.

### Changed

- KMS: `core.onboard.public_key_handover` defaults to `false`, so
`KMS.GetKmsKey` is no longer served on the public port. Onboard through the
source's admin listener with `source_token`; a source that still onboards
0.5.x KMS nodes must set the option to `true` until they are upgraded.
- KMS: onboarding refuses a source whose certificate carries no OS image hash,
which drops the fallback for KMS 0.5.x sources. Join only from a 0.6+ source;
upgrade a 0.5.x cluster to 0.6.x first.
- dstack-auth: an empty `devices` list no longer allows any device; set
`allowAnyDevice: true` for that. An empty `osImages` list now denies every
app instead of skipping the OS image check. Allowlists generated by
`dstack-cli` already set both explicitly.
- Auth backends: once a root epoch other than 0 is activated, `/bootAuth/kms`
denies a KMS that reports no root epoch, as `/bootAuth/app` already did, so
KMS binaries predating root epochs stop serving at activation. Upgrade every
KMS before activating a new root epoch.
- auth-eth, auth-eth-bun: policy is read at the `finalized` block by default
instead of `latest`, so on-chain changes, including revocations, take effect
only once finalized. Set `ETH_BLOCK_TAG=latest` (or `safe`) to override; an
OP-stack chain read through the Helios light client requires `latest`. The
server refuses to start if the RPC cannot serve the configured tag. In
auth-eth-bun, `ETH_FINALITY_CONFIRMATIONS` now counts back from that block.
- KMS: retain `GetTempCaCert`, temporary CA files and legacy handover fields so
KMS nodes can be upgraded before existing OS images.

- dstack-util, cert-client: guests mint self-issued RA-TLS client
certificates for KMS calls instead of fetching the temp CA and minting from
it; the KMS authenticates the quote inside the certificate, not its issuer.
The KMS root CA now comes from `GetMeta`, over the same unauthenticated
connection `GetTempCaCert` used, so the trust posture is unchanged: relying
parties bind the KMS through the `key-provider` launch event (RTMR3/PCR14)
against the on-chain `kmsInfo` or a pinned key, and `verify_key_provider_id`
also enforces it in-guest when the app pins `key_provider_id`. A guest built
from this change needs KMS 0.6.0 or later; older KMS releases pin the temp CA
and refuse the certificate at the TLS handshake
Guests fetch the root CA with the key response and bind it to the attested
RPC certificate, without a metadata preflight. Provider pins and the
`key-provider` launch event (RTMR3/PCR14) retain the root identity binding.
The new flow requires an attested KMS that accepts self-issued certificates.
- dstack-types: `KeyProvider::Kms` drops `tmp_ca_key` and `tmp_ca_cert`, so
`.appkeys.json` no longer carries them. Files written by older images still
parse, but out-of-tree readers that require those fields fail on new files

- KMS: `auth-eth-bun` is renamed to `auth-eth`. The Bun webhook server moves
from `dstack/kms/auth-eth-bun` into `dstack/kms/auth-eth`, next to the
contracts. New releases are tagged `kms-auth-eth-v*` and published as
`ghcr.io/dstack-tee/dstack-kms-auth-eth`; images already published as
`ghcr.io/dstack-tee/dstack-kms-auth-eth-bun` remain available. Update image
references and source paths in deployments.

### Removed

- KMS: the `auth-mock` webhook backend. For development, use the built-in
`[core.auth_api] type = "dev"`, which allows everything.
- `auth-simple` (`dstack/kms/auth-simple`). Use `dstack-auth`, which reads the
same config file. Differences: the TCB status and advisories are not checked
unless `allowedTcbStatuses` / `allowedAdvisoryIds` are set (auth-simple
defaulted to `["UpToDate"]` and `[]`); `/authorize*` requires
`kmsContractAddr`; KMS requests are not matched against `osImages`; the
config path and port are `--config` / `--port` flags instead of
`AUTH_CONFIG_PATH` / `PORT`, and it binds to `127.0.0.1` by default. See
`docs/dstack-auth-operations.md#migrating-from-auth-simple`.
- KMS: the Node `auth-eth` webhook server (`dstack/kms/auth-eth/src`) is
removed. Use the Bun server (formerly `auth-eth-bun`, now in the same
directory, see Changed), which serves the same webhook API and reads the
same environment variables, except that it binds all interfaces and ignores
`HOST`, and `PORT` defaults to 3000 from source (8000 in its image). The
`DstackKms`/`DstackApp` contracts, Foundry tests and deployment scripts stay
in `dstack/kms/auth-eth`. `kms/dstack-app/compose-dev.yaml` now builds
the Bun server.

### Fixed

- kms: onboarding from a source older than 0.6.0 (no `source_token`) now
verifies the source's attestation on the connection that returns the root
keys, and checks it against local policy before using them. It used to
verify the source only on the earlier `GetTempCaCert` connection
- kms: onboarding with or without `source_token` verifies the source's
attestation on the connection that returns the root keys and checks local
policy before using them. Legacy sources requiring temp-CA-issued clients
must be upgraded.

## [0.6.3] - 2026-11-01

Expand Down
16 changes: 9 additions & 7 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,22 +70,24 @@ cargo clippy -- -D warnings --allow unused_variables

```bash
cd dstack/kms/auth-eth
npm install # Install Node.js dependencies for bootAuth server
forge install # Install Foundry dependencies (submodules)
git submodule update --init --recursive lib/forge-std \
lib/openzeppelin-contracts-upgradeable lib/openzeppelin-foundry-upgrades
# Upgrade-safety validator called by `forge test --ffi`
npx --yes @openzeppelin/upgrades-core@^1.37.0 --help > /dev/null

# Build
forge build # Compile smart contracts
npm run build # Build TypeScript server

# Test
forge test --ffi # Run Foundry contract tests
npm test # Run TypeScript server tests
npm run test:coverage # Run TypeScript tests with coverage
forge clean && forge test --ffi # Run Foundry contract tests

# Local development
anvil # Start local Ethereum node
```

The KMS webhook server for these contracts lives in the same directory
(`bun install && bun run check`).

### Python SDK

```bash
Expand Down Expand Up @@ -130,7 +132,7 @@ cargo test --all-features -- --show-output --test-threads=1
cd dstack/kms/auth-eth

# Run all Foundry tests
forge test
forge test --ffi

# Run with verbosity
forge test -vv
Expand Down
11 changes: 2 additions & 9 deletions REUSE.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,15 @@ path = [
"**/tsconfig.json",
"**/tsconfig.node.json",
"**/tsconfig.browser.json",
"dstack/kms/auth-eth-bun/.oxlintrc.json",
"dstack/kms/auth-eth/.oxlintrc.json",
"dstack/kms/auth-eth/slither.config.json",
"**/package-lock.json",
"dstack/kms/auth-eth/.openzeppelin/unknown-2035.json",
"dstack/kms/auth-mock/.oxlintrc.json",
"dstack/kms/auth-simple/.oxlintrc.json",
"dstack/kms/auth-simple/auth-config.example.json",
"tools/sca/examples/heartbeat/config.json",
"tools/sca/examples/hello-c/config.json",
"tools/sca/examples/heartbeat/rootfs/etc/heartbeat/interval",
"sdk/simulator/*.json",
"sdk/fixtures/sealed-env/*.json",
"sdk/go/go.sum",
"sdk/go/ratls/go.sum",
"dstack/kms/dstack-app/builder/shared/builder-pinned-packages.txt",
Expand Down Expand Up @@ -194,11 +192,6 @@ precedence = "override"

# Generated files

[[annotations]]
path = "dstack/kms/auth-eth/typechain-types/**"
SPDX-FileCopyrightText = "NONE"
SPDX-License-Identifier = "CC0-1.0"

[[annotations]]
path = "**/*.lock"
SPDX-FileCopyrightText = "NONE"
Expand Down
Loading
Loading