mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-21 14:11:26 +00:00
feat(cli): add trusted-proxy auth mode to gateway configuration
- Add 'trusted-proxy' option to gateway auth mode selection - Prompt for trusted-proxy config: userHeader, requiredHeaders, allowUsers - Prompt for trustedProxies IP list (required for trusted-proxy mode) - Update buildGatewayAuthConfig to handle trusted-proxy mode - Add helpful note explaining trusted-proxy use cases and docs link Enables CLI configuration of trusted-proxy auth during: - Initial onboarding (openclaw onboard) - Gateway configuration (openclaw configure) Example prompts: - User identity header: x-forwarded-user (default) - Required headers: x-forwarded-proto,x-forwarded-host (optional) - Allowed users: nick@example.com,admin@company.com (optional) - Trusted proxy IPs: 10.0.1.10,192.168.1.5 (required) Refs: feat/trusted-proxy auth implementation
This commit is contained in:
committed by
Peter Steinberger
parent
164c2053ee
commit
e1ce11c4b7
@@ -14,7 +14,7 @@ import {
|
||||
import { promptCustomApiConfig } from "./onboard-custom.js";
|
||||
import { randomToken } from "./onboard-helpers.js";
|
||||
|
||||
type GatewayAuthChoice = "token" | "password";
|
||||
type GatewayAuthChoice = "token" | "password" | "trusted-proxy";
|
||||
|
||||
/** Reject undefined, empty, and common JS string-coercion artifacts for token auth. */
|
||||
function sanitizeTokenValue(value: string | undefined): string | undefined {
|
||||
@@ -40,6 +40,11 @@ export function buildGatewayAuthConfig(params: {
|
||||
mode: GatewayAuthChoice;
|
||||
token?: string;
|
||||
password?: string;
|
||||
trustedProxy?: {
|
||||
userHeader: string;
|
||||
requiredHeaders?: string[];
|
||||
allowUsers?: string[];
|
||||
};
|
||||
}): GatewayAuthConfig | undefined {
|
||||
const allowTailscale = params.existing?.allowTailscale;
|
||||
const base: GatewayAuthConfig = {};
|
||||
@@ -52,8 +57,17 @@ export function buildGatewayAuthConfig(params: {
|
||||
const token = sanitizeTokenValue(params.token) ?? randomToken();
|
||||
return { ...base, mode: "token", token };
|
||||
}
|
||||
const password = params.password?.trim();
|
||||
return { ...base, mode: "password", ...(password && { password }) };
|
||||
if (params.mode === "password") {
|
||||
const password = params.password?.trim();
|
||||
return { ...base, mode: "password", ...(password && { password }) };
|
||||
}
|
||||
if (params.mode === "trusted-proxy") {
|
||||
if (!params.trustedProxy) {
|
||||
throw new Error("trustedProxy config is required when mode is trusted-proxy");
|
||||
}
|
||||
return { ...base, mode: "trusted-proxy", trustedProxy: params.trustedProxy };
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
export async function promptAuthConfig(
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
validateGatewayPasswordInput,
|
||||
} from "./onboard-helpers.js";
|
||||
|
||||
type GatewayAuthChoice = "token" | "password";
|
||||
type GatewayAuthChoice = "token" | "password" | "trusted-proxy";
|
||||
|
||||
export async function promptGatewayConfig(
|
||||
cfg: OpenClawConfig,
|
||||
@@ -103,6 +103,11 @@ export async function promptGatewayConfig(
|
||||
options: [
|
||||
{ value: "token", label: "Token", hint: "Recommended default" },
|
||||
{ value: "password", label: "Password" },
|
||||
{
|
||||
value: "trusted-proxy",
|
||||
label: "Trusted Proxy",
|
||||
hint: "Behind reverse proxy (Pomerium, Caddy, Traefik, etc.)",
|
||||
},
|
||||
],
|
||||
initialValue: "token",
|
||||
}),
|
||||
@@ -177,6 +182,8 @@ export async function promptGatewayConfig(
|
||||
|
||||
let gatewayToken: string | undefined;
|
||||
let gatewayPassword: string | undefined;
|
||||
let trustedProxyConfig: { userHeader: string; requiredHeaders?: string[]; allowUsers?: string[] } | undefined;
|
||||
let trustedProxies: string[] | undefined;
|
||||
let next = cfg;
|
||||
|
||||
if (authMode === "token") {
|
||||
@@ -201,11 +208,82 @@ export async function promptGatewayConfig(
|
||||
gatewayPassword = String(password ?? "").trim();
|
||||
}
|
||||
|
||||
if (authMode === "trusted-proxy") {
|
||||
note(
|
||||
[
|
||||
"Trusted proxy mode: OpenClaw trusts user identity from a reverse proxy.",
|
||||
"The proxy must authenticate users and pass identity via headers.",
|
||||
"Only requests from specified proxy IPs will be trusted.",
|
||||
"",
|
||||
"Common use cases: Pomerium, Caddy + OAuth, Traefik + forward auth",
|
||||
"Docs: https://docs.openclaw.ai/gateway/trusted-proxy",
|
||||
].join("\n"),
|
||||
"Trusted Proxy Auth",
|
||||
);
|
||||
|
||||
const userHeader = guardCancel(
|
||||
await text({
|
||||
message: "Header containing user identity",
|
||||
placeholder: "x-forwarded-user",
|
||||
initialValue: "x-forwarded-user",
|
||||
validate: (value) => (value?.trim() ? undefined : "User header is required"),
|
||||
}),
|
||||
runtime,
|
||||
);
|
||||
|
||||
const requiredHeadersRaw = guardCancel(
|
||||
await text({
|
||||
message: "Required headers (comma-separated, optional)",
|
||||
placeholder: "x-forwarded-proto,x-forwarded-host",
|
||||
}),
|
||||
runtime,
|
||||
);
|
||||
const requiredHeaders = requiredHeadersRaw
|
||||
? String(requiredHeadersRaw).split(",").map((h) => h.trim()).filter(Boolean)
|
||||
: [];
|
||||
|
||||
const allowUsersRaw = guardCancel(
|
||||
await text({
|
||||
message: "Allowed users (comma-separated, blank = all authenticated users)",
|
||||
placeholder: "nick@example.com,admin@company.com",
|
||||
}),
|
||||
runtime,
|
||||
);
|
||||
const allowUsers = allowUsersRaw
|
||||
? String(allowUsersRaw).split(",").map((u) => u.trim()).filter(Boolean)
|
||||
: [];
|
||||
|
||||
const trustedProxiesRaw = guardCancel(
|
||||
await text({
|
||||
message: "Trusted proxy IPs (comma-separated)",
|
||||
placeholder: "10.0.1.10,192.168.1.5",
|
||||
validate: (value) => {
|
||||
if (!value || String(value).trim() === "") {
|
||||
return "At least one trusted proxy IP is required";
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
}),
|
||||
runtime,
|
||||
);
|
||||
trustedProxies = String(trustedProxiesRaw)
|
||||
.split(",")
|
||||
.map((ip) => ip.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
trustedProxyConfig = {
|
||||
userHeader: String(userHeader).trim(),
|
||||
requiredHeaders: requiredHeaders.length > 0 ? requiredHeaders : undefined,
|
||||
allowUsers: allowUsers.length > 0 ? allowUsers : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
const authConfig = buildGatewayAuthConfig({
|
||||
existing: next.gateway?.auth,
|
||||
mode: authMode,
|
||||
token: gatewayToken,
|
||||
password: gatewayPassword,
|
||||
trustedProxy: trustedProxyConfig,
|
||||
});
|
||||
|
||||
next = {
|
||||
@@ -217,6 +295,7 @@ export async function promptGatewayConfig(
|
||||
bind,
|
||||
auth: authConfig,
|
||||
...(customBindHost && { customBindHost }),
|
||||
...(trustedProxies && { trustedProxies }),
|
||||
tailscale: {
|
||||
...next.gateway?.tailscale,
|
||||
mode: tailscaleMode,
|
||||
|
||||
Reference in New Issue
Block a user