Serve KMS ClearImageCache on a dedicated authenticated admin listener#802
Merged
Conversation
kvinwang
force-pushed
the
kms-admin-port
branch
2 times, most recently
from
July 20, 2026 10:18
91209da to
6f3960f
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
This PR moves the KMS admin-only ClearImageCache RPC off the public KMS RPC surface and onto a dedicated [core.admin] listener protected by the shared dstack-api-auth HTTP authenticator, aligning KMS with the gateway/VMM admin authentication model.
Changes:
- Split
ClearImageCacheinto a newKmsAdminproto service and remove the request-body token field (credential now comes from HTTP headers). - Add a new KMS admin listener configuration (
[core.admin]) and wire up a second Rocket instance guarded by anAdminAuthFairing(fail-closed unless explicitly configured). - Relocate cache-clearing logic into
KmsStateand update templates/scripts/config snippets to drop the old[core] admin_token_hash.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| dstack/test-scripts/snp-e2e-smoke.sh | Removes the obsolete admin_token_hash field from SNP smoke config snippet. |
| dstack/kms/src/main.rs | Boots an optional second Rocket instance for admin RPCs on [core.admin], attaching shared HTTP auth. |
| dstack/kms/src/main_service.rs | Moves cache-clearing logic into KmsState and adds unit tests for cache deletion safety. |
| dstack/kms/src/config.rs | Replaces the legacy admin_token_hash field with a structured AdminConfig under core.admin. |
| dstack/kms/src/admin_service.rs | Introduces a dedicated KmsAdmin RPC handler serving ClearImageCache. |
| dstack/kms/src/admin_auth.rs | Adds KMS adapter fairing that constructs/attaches the shared HTTP authenticator (fail-closed). |
| dstack/kms/rpc/proto/kms_rpc.proto | Creates service KmsAdmin and removes the token from ClearImageCacheRequest. |
| dstack/kms/README.md | Documents the new admin listener, header-based auth, and example curl invocation. |
| dstack/kms/kms.toml | Adds [core.admin] template and removes old [core] admin_token_hash. |
| dstack/kms/dstack-app/entrypoint.sh | Drops writing the removed [core] admin_token_hash into generated config. |
| dstack/kms/dstack-app/compose-simple.yaml | Removes the removed admin_token_hash from template config. |
| dstack/kms/dstack-app/compose-dev.yaml | Removes the removed admin_token_hash from template config. |
| dstack/crates/dstack-cli-core/src/config.rs | Removes the removed admin_token_hash from embedded config snippet. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
kvinwang
force-pushed
the
kms-admin-port
branch
2 times, most recently
from
July 20, 2026 11:40
c4d8163 to
12de815
Compare
kvinwang
added a commit
that referenced
this pull request
Jul 20, 2026
kvinwang
added a commit
that referenced
this pull request
Jul 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The KMS admin RPC
ClearImageCachewas authenticated differently from every other admin surface in dstack, and in a way that is easy to get wrong:[rpc]listener asGetAppKey/SignCert), gated only by a hand-rolledensure_admincheck inside the handler.ClearImageCacheRequest.token), compared against[core] admin_token_hash. It did not use the shareddstack-api-authHTTP authenticator, so — unlike VMM and gateway —Authorization: Bearer/X-Admin-Tokenheaders were ignored.ensure_adminwould be unauthenticated, with no framework backstop.This divergence already caused a documentation error (a sibling PR initially documented the KMS admin token as an
Authorization: Bearerheader, which the server silently ignored).Fix
Move
ClearImageCacheonto a dedicated admin listener that reuses the same shared HTTP authenticator as the gateway, so all three services (VMM, gateway, KMS) authenticate admin/management traffic the same way.ClearImageCacheout ofservice KMSinto a newservice KmsAdmin, and drop thetokenfield fromClearImageCacheRequest(the credential now travels in the HTTP header).[core] admin_token_hashwith a gateway-style[core.admin]section, configured identically to the gateway —enabled,address/port,admin_token(plaintext, or theDSTACK_KMS_ADMIN_TOKEN/ADMIN_API_TOKENenv vars),htpasswd_file,insecure_no_auth.kms/src/admin_auth.rsmirrors the gatewayAdminAuthFairing— resolves the token from config or env, adds optional bcrypt htpasswd, and fails closed (enabled with no credential andinsecure_no_auth = falserefuses to start).ClearImageCachemoves to a newAdminRpcHandlerserved on a second Rocket instance bound to[core.admin], behind theHttpAuthFairing.ensure_adminand the in-handler token check are deleted; the cache-clearing logic moves toKmsState.[core] admin_token_hashfromkms.toml, the KMS dstack-app templates, the dstackup KMS template, and the SNP smoke test. The admin API is disabled by default; operators opt in via[core.admin].No backward-compat shim: the RPC had no known callers.
Verification
cargo build(full workspace),cargo clippy -p dstack-kms,cargo fmt --all --check— all clean.cargo test -p dstack-kms(37) /-p dstack-cli-core(12) pass, including new tests:admin_auth: fail-closed when enabled with no credential (config or env);insecure_no_authallowed; a configured token builds.config: the defaultkms.tomlparses with[core.admin]disabled and an empty token (fail-closed).main_service::remove_cache_only_deletes_the_named_hex_entry: the relocated cache-clear logic keeps its hex-key guard andallbehavior.dstack-api-authHttpAuthFairing, which already has passing Rocket integration tests (protects_all_methods_and_accepts_compatible_credentials,enabled_with_no_credentials_denies_access).Not covered: a live HTTP round-trip against a running KMS admin listener. That needs a fully bootstrapped KMS keyset (genesis attestation), which this change does not stand up. The auth enforcement is exercised by the shared fairing's own tests; the KMS-specific wiring is covered by the unit tests above. Happy to add a fixture-based
rocket::localintegration test if desired.Coordination
Supersedes the KMS-admin-token documentation in the docs/tooling PR (which described the old request-field mechanism). If that PR lands first, its
kms/README.md/deployment.md/security-best-practices.mdKMS-admin notes should be reconciled to the header-based mechanism documented here.