From 2e935f60f4b0ef6b31f5c1e845b54ef57db60088 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Mon, 20 Jul 2026 05:10:39 -0700 Subject: [PATCH] refactor(gateway): rename core.admin.admin_token to auth_token (alias-compatible) --- dstack/gateway/docs/cluster-deployment.md | 2 +- .../gateway/dstack-app/builder/entrypoint.sh | 2 +- dstack/gateway/gateway.toml | 4 ++-- dstack/gateway/src/admin_auth.rs | 8 +++---- dstack/gateway/src/config.rs | 23 +++++++++++++++++-- .../test-run/e2e/configs/gateway-1.toml | 2 +- .../test-run/e2e/configs/gateway-2.toml | 2 +- .../test-run/e2e/configs/gateway-3.toml | 2 +- dstack/gateway/test-run/e2e/test.sh | 2 +- 9 files changed, 33 insertions(+), 14 deletions(-) diff --git a/dstack/gateway/docs/cluster-deployment.md b/dstack/gateway/docs/cluster-deployment.md index 191d4c0ef..2a80a5514 100644 --- a/dstack/gateway/docs/cluster-deployment.md +++ b/dstack/gateway/docs/cluster-deployment.md @@ -289,7 +289,7 @@ Important: ### 2.7 Verify Cluster Sync -The admin API requires a bearer token (see `core.admin.admin_token` in `gateway.toml`, +The admin API requires a bearer token (see `core.admin.auth_token` in `gateway.toml`, or the `ADMIN_API_TOKEN` env injected by `deploy-to-vmm.sh`). Export it once: ```bash diff --git a/dstack/gateway/dstack-app/builder/entrypoint.sh b/dstack/gateway/dstack-app/builder/entrypoint.sh index 1a3811ad0..8125cc163 100755 --- a/dstack/gateway/dstack-app/builder/entrypoint.sh +++ b/dstack/gateway/dstack-app/builder/entrypoint.sh @@ -95,7 +95,7 @@ sync_connections_interval = "${SYNC_CONNECTIONS_INTERVAL:-30s}" enabled = true address = "${ADMIN_LISTEN_ADDR:-0.0.0.0}" port = ${ADMIN_LISTEN_PORT:-8001} -admin_token = "${ADMIN_API_TOKEN}" +auth_token = "${ADMIN_API_TOKEN}" [core.wg] public_key = "$PUBLIC_KEY" diff --git a/dstack/gateway/gateway.toml b/dstack/gateway/gateway.toml index d8e5e1b4d..74afe9c2b 100644 --- a/dstack/gateway/gateway.toml +++ b/dstack/gateway/gateway.toml @@ -28,8 +28,8 @@ address = "127.0.0.1:8011" # be supplied via the `DSTACK_GATEWAY_ADMIN_TOKEN` or `ADMIN_API_TOKEN` env # vars. Clients send it as `Authorization: Bearer `, `X-Admin-Token`, # or (GET only, for dashboard links) `?token=...`. Required unless -# `insecure_no_auth = true`. -admin_token = "" +# `insecure_no_auth = true`. (The legacy key `admin_token` is still accepted.) +auth_token = "" # Optional Apache htpasswd file for HTTP Basic authentication. htpasswd_file = "" # Development/testing escape hatch only. Never enable this on an admin diff --git a/dstack/gateway/src/admin_auth.rs b/dstack/gateway/src/admin_auth.rs index 25bec64c1..06c9f0b62 100644 --- a/dstack/gateway/src/admin_auth.rs +++ b/dstack/gateway/src/admin_auth.rs @@ -23,8 +23,8 @@ impl AdminAuthFairing { http_config(), ))); } - let token = if !config.admin_token.is_empty() { - config.admin_token.trim().to_owned() + let token = if !config.auth_token.is_empty() { + config.auth_token.trim().to_owned() } else { std::env::var(ENV_ADMIN_TOKEN) .or_else(|_| std::env::var(ENV_ADMIN_TOKEN_COMPAT)) @@ -34,8 +34,8 @@ impl AdminAuthFairing { }; if token.is_empty() && config.htpasswd_file.as_os_str().is_empty() { bail!( - "admin API is enabled but neither admin_token nor htpasswd_file is configured; \ - set core.admin.admin_token, {ENV_ADMIN_TOKEN}, {ENV_ADMIN_TOKEN_COMPAT}, \ + "admin API is enabled but neither auth_token nor htpasswd_file is configured; \ + set core.admin.auth_token, {ENV_ADMIN_TOKEN}, {ENV_ADMIN_TOKEN_COMPAT}, \ core.admin.htpasswd_file, or insecure_no_auth = true (testing only)" ); } diff --git a/dstack/gateway/src/config.rs b/dstack/gateway/src/config.rs index 4d208d22d..e69965aee 100644 --- a/dstack/gateway/src/config.rs +++ b/dstack/gateway/src/config.rs @@ -296,8 +296,10 @@ pub struct AdminConfig { /// Shared secret required to call any admin endpoint (RPC + dashboard). /// Can also be supplied via `DSTACK_GATEWAY_ADMIN_TOKEN` / `ADMIN_API_TOKEN` /// env vars. Required unless `insecure_no_auth = true`. - #[serde(default)] - pub admin_token: String, + /// + /// Accepts the legacy `admin_token` key for backward compatibility. + #[serde(default, alias = "admin_token")] + pub auth_token: String, /// Optional Apache htpasswd file. Enables standard HTTP Basic auth while /// preserving token authentication for existing clients. #[serde(default)] @@ -354,8 +356,25 @@ pub fn setup_wireguard(config: &WgConfig) -> Result<()> { #[cfg(test)] mod tests { use super::*; + use rocket::figment::providers::{Format, Toml}; use std::str::FromStr; + #[test] + fn admin_auth_token_reads_new_and_legacy_keys() { + // new key + let cfg: AdminConfig = + Figment::from(Toml::string("enabled = true\nauth_token = \"new\"\n")) + .extract() + .unwrap(); + assert_eq!(cfg.auth_token, "new"); + // legacy `admin_token` key still deserializes via the serde alias + let cfg: AdminConfig = + Figment::from(Toml::string("enabled = true\nadmin_token = \"legacy\"\n")) + .extract() + .unwrap(); + assert_eq!(cfg.auth_token, "legacy"); + } + #[test] fn test_validate() { // Valid configuration diff --git a/dstack/gateway/test-run/e2e/configs/gateway-1.toml b/dstack/gateway/test-run/e2e/configs/gateway-1.toml index dc8e6f3b3..350b1d177 100644 --- a/dstack/gateway/test-run/e2e/configs/gateway-1.toml +++ b/dstack/gateway/test-run/e2e/configs/gateway-1.toml @@ -19,7 +19,7 @@ rpc_domain = "gateway-1" enabled = true port = 9016 address = "0.0.0.0" -admin_token = "e2e-admin-token" +auth_token = "e2e-admin-token" [core.debug] insecure_enable_debug_rpc = true diff --git a/dstack/gateway/test-run/e2e/configs/gateway-2.toml b/dstack/gateway/test-run/e2e/configs/gateway-2.toml index c733710b2..0838921bd 100644 --- a/dstack/gateway/test-run/e2e/configs/gateway-2.toml +++ b/dstack/gateway/test-run/e2e/configs/gateway-2.toml @@ -19,7 +19,7 @@ rpc_domain = "gateway-2" enabled = true port = 9016 address = "0.0.0.0" -admin_token = "e2e-admin-token" +auth_token = "e2e-admin-token" [core.debug] insecure_enable_debug_rpc = true diff --git a/dstack/gateway/test-run/e2e/configs/gateway-3.toml b/dstack/gateway/test-run/e2e/configs/gateway-3.toml index b02a57fc9..9be8d04e0 100644 --- a/dstack/gateway/test-run/e2e/configs/gateway-3.toml +++ b/dstack/gateway/test-run/e2e/configs/gateway-3.toml @@ -19,7 +19,7 @@ rpc_domain = "gateway-3" enabled = true port = 9016 address = "0.0.0.0" -admin_token = "e2e-admin-token" +auth_token = "e2e-admin-token" [core.debug] insecure_enable_debug_rpc = true diff --git a/dstack/gateway/test-run/e2e/test.sh b/dstack/gateway/test-run/e2e/test.sh index 1ed9df3fa..223fc5219 100755 --- a/dstack/gateway/test-run/e2e/test.sh +++ b/dstack/gateway/test-run/e2e/test.sh @@ -22,7 +22,7 @@ GATEWAY_PROXIES="gateway-1:9014 gateway-2:9014 gateway-3:9014" GATEWAY_DEBUG_URLS="http://gateway-1:9015 http://gateway-2:9015 http://gateway-3:9015" GATEWAY_ADMIN="http://gateway-1:9016" -# Must match `admin_token` in configs/gateway-*.toml +# Must match `auth_token` in configs/gateway-*.toml ADMIN_TOKEN="e2e-admin-token" ADMIN_AUTH_HEADER="Authorization: Bearer ${ADMIN_TOKEN}"