diff --git a/CHANGELOG.md b/CHANGELOG.md index d0684cbff..47f2f17b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - Slack: accept slash commands with or without leading `/` for custom command configs. (#798 — thanks @thewilloftheshadow) - Onboarding/Configure: refuse to proceed with invalid configs; run `clawdbot doctor` first to avoid wiping custom fields. (#764 — thanks @mukhtharcm) - Onboarding: quote Windows browser URLs when launching via `cmd start` to preserve OAuth query params. (#794 — thanks @roshanasingh4) +- Gateway/Auth: allow Tailscale Serve identity headers to satisfy token auth when `allowTailscale` is enabled. (#823 — thanks @roshanasingh4) - Anthropic: merge consecutive user turns (preserve newest metadata) before validation to avoid “Incorrect role information” errors. (#804 — thanks @ThomsenDrake) - Discord/Slack: centralize reply-thread planning so auto-thread replies stay in the created thread without parent reply refs. - Telegram: respect account-scoped bindings when webhook mode is enabled. (#821 — thanks @gumadeiras) diff --git a/docs/gateway/configuration.md b/docs/gateway/configuration.md index 2582a737d..25fe5db92 100644 --- a/docs/gateway/configuration.md +++ b/docs/gateway/configuration.md @@ -2191,7 +2191,12 @@ Auth and Tailscale: - `gateway.auth.token` stores the shared token for token auth (used by the CLI on the same machine). - When `gateway.auth.mode` is set, only that method is accepted (plus optional Tailscale headers). - `gateway.auth.password` can be set here, or via `CLAWDBOT_GATEWAY_PASSWORD` (recommended). -- `gateway.auth.allowTailscale` controls whether Tailscale identity headers can satisfy auth. +- `gateway.auth.allowTailscale` allows Tailscale Serve identity headers + (`tailscale-user-login`) to satisfy auth when the request arrives on loopback + with `x-forwarded-for`, `x-forwarded-proto`, and `x-forwarded-host`. When + `true`, Serve requests do not need a token/password; set `false` to require + explicit credentials. Defaults to `true` when `tailscale.mode = "serve"` and + auth mode is not `password`. - `gateway.tailscale.mode: "serve"` uses Tailscale Serve (tailnet only, loopback bind). - `gateway.tailscale.mode: "funnel"` exposes the dashboard publicly; requires auth. - `gateway.tailscale.resetOnExit` resets Serve/Funnel config on shutdown. diff --git a/docs/gateway/security.md b/docs/gateway/security.md index 84e380741..3110df279 100644 --- a/docs/gateway/security.md +++ b/docs/gateway/security.md @@ -145,6 +145,20 @@ Doctor can generate one for you: `clawdbot doctor --generate-gateway-token`. Note: `gateway.remote.token` is **only** for remote CLI calls; it does not protect local WS access. +### 0.6) Tailscale Serve identity headers + +When `gateway.auth.allowTailscale` is `true` (default for Serve), Clawdbot +accepts Tailscale Serve identity headers (`tailscale-user-login`) as +authentication. This only triggers for requests that hit loopback and include +`x-forwarded-for`, `x-forwarded-proto`, and `x-forwarded-host` as injected by +Tailscale. + +**Security rule:** do not forward these headers from your own reverse proxy. If +you terminate TLS or proxy in front of the gateway, disable +`gateway.auth.allowTailscale` and use token/password auth instead. + +See [Tailscale](/gateway/tailscale) and [Web overview](/web). + ### 1) DMs: pairing by default ```json5 diff --git a/docs/gateway/tailscale.md b/docs/gateway/tailscale.md index d7f4f8ff0..586c80dc0 100644 --- a/docs/gateway/tailscale.md +++ b/docs/gateway/tailscale.md @@ -23,9 +23,13 @@ Set `gateway.auth.mode` to control the handshake: - `token` (default when `CLAWDBOT_GATEWAY_TOKEN` is set) - `password` (shared secret via `CLAWDBOT_GATEWAY_PASSWORD` or config) -When `tailscale.mode = "serve"`, the gateway trusts Tailscale identity headers by -default unless you force `gateway.auth.mode` to `password` or set -`gateway.auth.allowTailscale: false`. +When `tailscale.mode = "serve"` and `gateway.auth.allowTailscale` is `true`, +valid Serve proxy requests can authenticate via Tailscale identity headers +(`tailscale-user-login`) without supplying a token/password. Clawdbot only +treats a request as Serve when it arrives from loopback with Tailscale’s +`x-forwarded-for`, `x-forwarded-proto`, and `x-forwarded-host` headers. +To require explicit credentials, set `gateway.auth.allowTailscale: false` or +force `gateway.auth.mode: "password"`. ## Config examples diff --git a/docs/web/control-ui.md b/docs/web/control-ui.md index fa2124081..758d58f4e 100644 --- a/docs/web/control-ui.md +++ b/docs/web/control-ui.md @@ -77,8 +77,12 @@ clawdbot gateway --tailscale serve Open: - `https:///` (or your configured `gateway.controlUi.basePath`) -By default, the gateway trusts Tailscale identity headers in serve mode. You can still set -`gateway.auth` (or `CLAWDBOT_GATEWAY_TOKEN`) if you want a shared secret instead. +By default, Serve requests can authenticate via Tailscale identity headers +(`tailscale-user-login`) when `gateway.auth.allowTailscale` is `true`. Clawdbot +only accepts these when the request hits loopback with Tailscale’s +`x-forwarded-*` headers. Set `gateway.auth.allowTailscale: false` (or force +`gateway.auth.mode: "password"`) if you want to require a token/password even +for Serve traffic. ### Bind to tailnet + token diff --git a/docs/web/index.md b/docs/web/index.md index daf9bfd91..82ca62205 100644 --- a/docs/web/index.md +++ b/docs/web/index.md @@ -94,7 +94,10 @@ Open: - Binding the Gateway to a non-loopback address **requires** auth (`gateway.auth` or `CLAWDBOT_GATEWAY_TOKEN`). - The wizard generates a gateway token by default (even on loopback). - The UI sends `connect.params.auth.token` or `connect.params.auth.password`. -- Use `gateway.auth.allowTailscale: false` to require explicit credentials even in Serve mode. +- With Serve, Tailscale identity headers can satisfy auth when + `gateway.auth.allowTailscale` is `true` (no token/password required). Set + `gateway.auth.allowTailscale: false` to require explicit credentials. See + [Tailscale](/gateway/tailscale) and [Security](/gateway/security). - `gateway.tailscale.mode: "funnel"` requires `gateway.auth.mode: "password"` (shared password). ## Building the UI