From 4bf6b65bb8099412b42c82ebc60e87759f1f49bb Mon Sep 17 00:00:00 2001 From: whit3rabbit Date: Fri, 27 Mar 2026 15:17:53 -0500 Subject: [PATCH] security: configurable admin token path via ADMIN_TOKEN_PATH Extract resolve_admin_token_path() function to read ADMIN_TOKEN_PATH env var (falling back to .admin_token). Replaces the previous inline ADMIN_TOKEN_FILE env var. Updates non-Unix warning to reference the new env var name. Co-Authored-By: Claude Sonnet 4.6 --- crates/proxy/src/main.rs | 17 +++++++++++++---- docs/ENV.md | 6 +++--- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/crates/proxy/src/main.rs b/crates/proxy/src/main.rs index b337e74..b4fb58f 100644 --- a/crates/proxy/src/main.rs +++ b/crates/proxy/src/main.rs @@ -324,8 +324,8 @@ async fn main() { // Admin token: use env var or generate random UUID written to a file. let admin_token = std::env::var("ADMIN_TOKEN").unwrap_or_else(|_| { let token = uuid::Uuid::new_v4().to_string(); - let token_path = std::env::var("ADMIN_TOKEN_FILE") - .unwrap_or_else(|_| ".admin_token".into()); + let token_path = resolve_admin_token_path(); + let token_path = token_path.to_string_lossy().to_string(); // Write token to file with restrictive permissions instead of stderr, // because stderr is captured by container log drivers in production. if let Err(e) = write_token_file(&token_path, &token) { @@ -523,6 +523,15 @@ fn parse_env_file(path: &str) -> Vec<(String, String)> { pairs } +/// Resolve admin token file path from `ADMIN_TOKEN_PATH` env var, +/// falling back to `.admin_token` in the current directory. +fn resolve_admin_token_path() -> std::path::PathBuf { + match std::env::var("ADMIN_TOKEN_PATH") { + Ok(p) => std::path::PathBuf::from(p), + Err(_) => std::path::PathBuf::from(".admin_token"), + } +} + /// Write the admin token to a file with mode 0600 (owner-only read/write). /// On Unix, sets permissions atomically at creation to avoid a TOCTOU race /// where the file is briefly world-readable before chmod. @@ -544,8 +553,8 @@ fn write_token_file(path: &str, token: &str) -> std::io::Result<()> { let mut file = { tracing::warn!( path = %path, - "non-Unix platform: admin token file may be world-readable. \ - Set ADMIN_TOKEN env var explicitly in production." + "admin token file written without restrictive permissions (non-Unix platform); \ + secure this file manually or set ADMIN_TOKEN_PATH to a protected location" ); std::fs::File::create(path)? }; diff --git a/docs/ENV.md b/docs/ENV.md index 511b14a..4d777b0 100644 --- a/docs/ENV.md +++ b/docs/ENV.md @@ -151,15 +151,15 @@ The dashboard binds to `localhost:3001` only (never externally accessible). It s | Variable | Default | Description | |----------|---------|-------------| | `ADMIN_PORT` | `3001` | Port for the admin dashboard. Must differ from `LISTEN_PORT`. | -| `ADMIN_TOKEN` | (generated) | Bearer token for the admin API. If unset, a random UUID is generated at startup and written to `ADMIN_TOKEN_FILE`. | -| `ADMIN_TOKEN_FILE` | `.admin_token` | File path where the generated admin token is written. Permissions are set to `0600` on Unix. | +| `ADMIN_TOKEN` | (generated) | Bearer token for the admin API. If unset, a random UUID is generated at startup and written to `ADMIN_TOKEN_PATH`. | +| `ADMIN_TOKEN_PATH` | `.admin_token` | File path where the generated admin token is written. Permissions are set to `0600` on Unix. | | `ADMIN_DB_PATH` | `admin.db` | SQLite database path for request logging and config overrides (model mappings, log level). Config overrides survive restarts. | | `ADMIN_LOG_RETENTION_DAYS` | `7` | Days to retain request log entries before automatic purge. | | `DISABLE_ADMIN` | (unset) | Set to `1`, `true`, or `yes` to force-disable the admin server even when `--webui` is passed. Useful in container deployments where the flag might be baked into the entrypoint. | ### Token security -The admin token is printed to `ADMIN_TOKEN_FILE` (default `.admin_token`) rather than stdout/stderr, because container log drivers capture stderr and persist it in centralized logging systems. On Unix, the file is created with mode `0600`. +The admin token is printed to `ADMIN_TOKEN_PATH` (default `.admin_token`) rather than stdout/stderr, because container log drivers capture stderr and persist it in centralized logging systems. On Unix, the file is created with mode `0600`. In production, set `ADMIN_TOKEN` explicitly: