Gateway
Uwierzytelnianie zaufanego serwera proxy
Kiedy używać
- Uruchamiasz OpenClaw za serwerem proxy rozpoznającym tożsamość (Pomerium, Caddy + OAuth, nginx + oauth2-proxy, Traefik + forward auth).
- Serwer proxy obsługuje całe uwierzytelnianie i przekazuje tożsamość użytkownika w nagłówkach.
- Korzystasz ze środowiska Kubernetes lub kontenerowego, w którym serwer proxy jest jedyną drogą do Gateway.
- Napotykasz błędy WebSocket
1008 unauthorized, ponieważ przeglądarki nie mogą przekazywać tokenów w ładunkach WS.
Kiedy NIE używać
- Serwer proxy nie uwierzytelnia użytkowników (jest tylko terminatorem TLS lub modułem równoważenia obciążenia).
- Istnieje jakakolwiek droga do Gateway omijająca serwer proxy (luki w zaporze, dostęp z sieci wewnętrznej).
- Nie masz pewności, czy serwer proxy prawidłowo usuwa lub nadpisuje przekazywane nagłówki.
- Potrzebujesz tylko osobistego dostępu dla jednego użytkownika (zamiast tego rozważ Tailscale Serve + local loopback).
Jak to działa
Serwer proxy uwierzytelnia użytkownika
Odwrotny serwer proxy uwierzytelnia użytkowników (OAuth, OIDC, SAML itd.).
Serwer proxy dodaje nagłówek tożsamości
Serwer proxy dodaje nagłówek z tożsamością uwierzytelnionego użytkownika (np. x-forwarded-user: nick@example.com).
Gateway weryfikuje zaufane źródło
OpenClaw sprawdza, czy żądanie pochodzi z adresu IP zaufanego serwera proxy (gateway.trustedProxies) i nie jest adresem local loopback ani adresem lokalnego interfejsu samego Gateway.
Gateway wyodrębnia tożsamość
OpenClaw odczytuje wymagane nagłówki, a następnie tożsamość użytkownika ze skonfigurowanego nagłówka.
Autoryzacja
Jeśli wszystkie kontrole zakończą się powodzeniem, a użytkownik przejdzie kontrolę allowUsers (gdy jest ustawiona), żądanie zostaje autoryzowane.
Konfiguracja
{ gateway: { // Uwierzytelnianie przez zaufany serwer proxy domyślnie wymaga, aby źródłowy adres IP serwera proxy nie był adresem pętli zwrotnej bind: "lan", // KRYTYCZNE: dodaj tutaj wyłącznie adresy IP swojego serwera proxy trustedProxies: ["10.0.0.1", "172.17.0.1"], auth: { mode: "trusted-proxy", trustedProxy: { // Nagłówek zawierający tożsamość uwierzytelnionego użytkownika (wymagany) userHeader: "x-forwarded-user", // Opcjonalnie: nagłówki, które MUSZĄ być obecne (weryfikacja serwera proxy) requiredHeaders: ["x-forwarded-proto", "x-forwarded-host"], // Opcjonalnie: ograniczenie do określonych użytkowników (pusta lista = zezwól wszystkim) allowUsers: ["nick@example.com", "admin@company.org"], // Opcjonalnie: zezwolenie na serwer proxy local loopback na tym samym hoście po jawnym włączeniu allowLoopback: false, }, }, },}Dokumentacja konfiguracji
gateway.trustedProxiesstring[]requiredTablica zaufanych adresów IP serwerów proxy (lub zakresów CIDR). Żądania z innych adresów IP są odrzucane.
gateway.auth.modestringrequiredMusi mieć wartość "trusted-proxy".
gateway.auth.trustedProxy.userHeaderstringrequiredNazwa nagłówka zawierającego tożsamość uwierzytelnionego użytkownika.
gateway.auth.trustedProxy.requiredHeadersstring[]Dodatkowe nagłówki, które muszą być obecne, aby żądanie zostało uznane za zaufane.
gateway.auth.trustedProxy.allowUsersstring[]Lista dozwolonych tożsamości użytkowników. Pusta lista oznacza zezwolenie wszystkim uwierzytelnionym użytkownikom.
gateway.auth.trustedProxy.allowLoopbackbooleandefault: falseOpcjonalna obsługa odwrotnych serwerów proxy local loopback działających na tym samym hoście.
Zachowanie parowania interfejsu Control UI
Gdy aktywne jest gateway.auth.mode = "trusted-proxy", a żądanie przejdzie kontrole zaufanego serwera proxy, sesje WebSocket interfejsu Control UI mogą łączyć się bez tożsamości parowanego urządzenia.
Konsekwencje dotyczące zakresów:
- Sesje WebSocket interfejsu Control UI bez urządzenia łączą się, ale domyślnie nie otrzymują żadnych zakresów operatora. OpenClaw czyści listę żądanych zakresów do
[], aby sesja niepowiązana z zatwierdzonym sparowanym urządzeniem lub tokenem nie mogła samodzielnie deklarować uprawnień. - Jeśli po pomyślnym połączeniu WebSocket metody kończą się błędem
missing scope, użyj HTTPS, aby przeglądarka mogła wygenerować tożsamość urządzenia i ukończyć parowanie. Zobacz niezabezpieczony HTTP interfejsu Control UI. - Wyłącznie awaryjnie:
gateway.controlUi.dangerouslyDisableDeviceAuth=truezachowuje żądane zakresy nawet bez tożsamości urządzenia. Jest to poważne obniżenie poziomu bezpieczeństwa; szybko wycofaj tę zmianę. Zobacz niezabezpieczony HTTP interfejsu Control UI.
Ograniczanie zakresów przez odwrotny serwer proxy: jeśli serwer proxy wysyła x-openclaw-scopes w żądaniu uaktualnienia WebSocket interfejsu Control UI, OpenClaw ogranicza zakresy sesji do części wspólnej zakresów żądanych i zadeklarowanych. Ten nagłówek nie przyznaje zakresów; jedynie ogranicza zakresy, które może posiadać sesja.
Konsekwencje:
- W tym trybie parowanie nie jest już podstawową bramą dostępu do interfejsu Control UI.
- Zasady uwierzytelniania odwrotnego serwera proxy i
allowUsersstają się faktycznym mechanizmem kontroli dostępu. - Ogranicz ruch przychodzący do Gateway wyłącznie do adresów IP zaufanych serwerów proxy (
gateway.trustedProxies+ zapora).
Niestandardowi klienci WebSocket nie są sesjami interfejsu Control UI. gateway.controlUi.dangerouslyDisableDeviceAuth nie przyznaje zakresów dowolnym klientom o client.mode: "backend" ani klientom o strukturze CLI. Niestandardowa automatyzacja powinna używać tożsamości urządzenia i parowania, zastrzeżonej bezpośredniej lokalnej ścieżki pomocniczej zaplecza client.id: "gateway-client" albo pluginu administracyjnego HTTP RPC, gdy interfejs żądanie/odpowiedź HTTP jest lepiej dopasowany.
Nagłówek zakresów operatora
Uwierzytelnianie przez zaufany serwer proxy jest trybem HTTP przenoszącym tożsamość, dlatego wywołujący mogą opcjonalnie deklarować zakresy operatora za pomocą x-openclaw-scopes w żądaniach API HTTP.
Uwaga: zakresy WebSocket są określane przez uzgadnianie protokołu Gateway i powiązanie tożsamości urządzenia. W żądaniach uaktualnienia WebSocket interfejsu Control UI nagłówek x-openclaw-scopes jedynie ogranicza wynegocjowane zakresy sesji, a ich nie przyznaje. Zobacz zachowanie parowania interfejsu Control UI.
Przykłady:
x-openclaw-scopes: operator.readx-openclaw-scopes: operator.read,operator.writex-openclaw-scopes: operator.admin,operator.write
Zachowanie:
- Gdy nagłówek jest obecny, OpenClaw respektuje zadeklarowany zestaw zakresów.
- Gdy nagłówek jest obecny, ale pusty, żądanie deklaruje brak zakresów operatora.
- Gdy nagłówek jest nieobecny, standardowe interfejsy API HTTP przenoszące tożsamość używają standardowego domyślnego zestawu zakresów operatora (
operator.admin,operator.read,operator.write,operator.approvals,operator.pairing,operator.talk.secrets). - Trasy HTTP pluginów uwierzytelniane przez Gateway są domyślnie bardziej ograniczone: gdy
x-openclaw-scopesjest nieobecny, ich zakres działania ogranicza się wyłącznie dooperator.write. - Żądania HTTP pochodzące z przeglądarki nadal muszą przejść kontrolę
gateway.controlUi.allowedOrigins(lub celowo włączony awaryjny tryb nagłówka Host), nawet po pomyślnym uwierzytelnieniu przez zaufany serwer proxy.
Praktyczna zasada: wysyłaj x-openclaw-scopes jawnie, gdy żądanie zaufanego serwera proxy ma mieć węższe uprawnienia niż domyślne albo gdy trasa pluginu uwierzytelniana przez Gateway wymaga zakresu silniejszego niż zakres zapisu.
Terminowanie TLS i HSTS
Użyj jednego punktu terminowania TLS i zastosuj w nim HSTS.
Terminowanie TLS na serwerze proxy (zalecane)
Gdy odwrotny serwer proxy obsługuje HTTPS dla https://control.example.com, ustaw Strict-Transport-Security na serwerze proxy dla tej domeny.
- Dobre rozwiązanie dla wdrożeń dostępnych z internetu.
- Utrzymuje certyfikat i zasady zabezpieczeń HTTP w jednym miejscu.
- OpenClaw może pozostać dostępny przez HTTP na local loopback za serwerem proxy.
Przykładowa wartość nagłówka:
Strict-Transport-Security: max-age=31536000; includeSubDomainsTerminowanie TLS w Gateway
Jeśli OpenClaw samodzielnie i bezpośrednio udostępnia HTTPS (bez serwera proxy terminującego TLS), ustaw:
{ gateway: { tls: { enabled: true }, http: { securityHeaders: { strictTransportSecurity: "max-age=31536000; includeSubDomains", }, }, },}strictTransportSecurity przyjmuje wartość nagłówka jako ciąg znaków albo false, aby jawnie go wyłączyć.
Wskazówki dotyczące wdrażania
- Zacznij od krótkiego maksymalnego czasu ważności (na przykład
max-age=300) podczas weryfikowania ruchu. - Zwiększ go do wartości długoterminowych (na przykład
max-age=31536000) dopiero po uzyskaniu wysokiego poziomu pewności. - Dodaj
includeSubDomainstylko wtedy, gdy każda subdomena jest gotowa do obsługi HTTPS. - Używaj preload tylko wtedy, gdy świadomie spełniasz wymagania wstępnego ładowania dla całego zestawu domen.
- Lokalne programowanie ograniczone wyłącznie do local loopback nie odnosi korzyści z HSTS.
Przykłady konfiguracji serwera proxy
Pomerium
Pomerium przekazuje tożsamość w x-pomerium-claim-email (lub innych nagłówkach deklaracji) oraz JWT w x-pomerium-jwt-assertion.
{ gateway: { bind: "lan", trustedProxies: ["10.0.0.1"], // Adres IP Pomerium auth: { mode: "trusted-proxy", trustedProxy: { userHeader: "x-pomerium-claim-email", requiredHeaders: ["x-pomerium-jwt-assertion"], }, }, },}Fragment konfiguracji Pomerium:
routes: - from: https://openclaw.example.com to: http://openclaw-gateway:18789 policy: - allow: or: - email: is: nick@example.com pass_identity_headers: trueCaddy z OAuth
Caddy z pluginem caddy-security może uwierzytelniać użytkowników i przekazywać nagłówki tożsamości.
{ gateway: { bind: "lan", trustedProxies: ["10.0.0.1"], // Caddy/sidecar proxy IP auth: { mode: "trusted-proxy", trustedProxy: { userHeader: "x-forwarded-user", }, }, },}Fragment pliku Caddyfile:
openclaw.example.com { authenticate with oauth2_provider authorize with policy1 reverse_proxy openclaw:18789 { header_up X-Forwarded-User {http.auth.user.email} }}nginx + oauth2-proxy
oauth2-proxy uwierzytelnia użytkowników i przekazuje tożsamość w nagłówku x-auth-request-email.
{ gateway: { bind: "lan", trustedProxies: ["10.0.0.1"], // nginx/oauth2-proxy IP auth: { mode: "trusted-proxy", trustedProxy: { userHeader: "x-auth-request-email", }, }, },}Fragment konfiguracji nginx:
location / { auth_request /oauth2/auth; auth_request_set $user $upstream_http_x_auth_request_email; proxy_pass http://openclaw:18789; proxy_set_header X-Auth-Request-Email $user; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";}Traefik with forward auth
{ gateway: { bind: "lan", trustedProxies: ["172.17.0.1"], // Traefik container IP auth: { mode: "trusted-proxy", trustedProxy: { userHeader: "x-forwarded-user", }, }, },}Konfiguracja mieszana z tokenem
Gateway odrzuca podczas uruchamiania uwierzytelnianie przez zaufane proxy, jeśli skonfigurowano również współdzielony token (gateway.auth.token lub OPENCLAW_GATEWAY_TOKEN). Te opcje wzajemnie się wykluczają, ponieważ współdzielony token umożliwiłby procesom na tym samym hoście uwierzytelnianie całkowicie inną ścieżką niż tożsamość zweryfikowana przez proxy, której egzekwowanie jest celem tego trybu.
Jeśli uruchamianie kończy się niepowodzeniem z błędem takim jak gateway auth mode is trusted-proxy, but a shared token is also configured:
- Usuń współdzielony token podczas korzystania z trybu zaufanego proxy albo
- Zmień
gateway.auth.modena"token", jeśli zamierzasz korzystać z uwierzytelniania opartego na tokenie.
Nagłówki tożsamości zaufanego proxy pochodzące z interfejsu pętli zwrotnej nadal są odrzucane w razie wątpliwości: procesy na tym samym hoście nie są niejawnie uwierzytelniane jako użytkownicy proxy. Wewnętrzne procesy OpenClaw, które omijają proxy, mogą zamiast tego uwierzytelniać się za pomocą gateway.auth.password / OPENCLAW_GATEWAY_PASSWORD. Uwierzytelnianie zapasowe tokenem pozostaje celowo nieobsługiwane w trybie zaufanego proxy.
Lista kontrolna bezpieczeństwa
Przed włączeniem uwierzytelniania przez zaufane proxy sprawdź:
- [ ] Proxy jest jedyną ścieżką: Port Gateway jest chroniony zaporą przed wszystkim poza Twoim proxy.
- [ ] Lista trustedProxies jest minimalna: Zawiera wyłącznie rzeczywiste adresy IP proxy, a nie całe podsieci.
- [ ] Źródło proxy w interfejsie pętli zwrotnej jest zamierzone: Uwierzytelnianie przez zaufane proxy odrzuca w razie wątpliwości żądania pochodzące z interfejsu pętli zwrotnej, chyba że dla proxy na tym samym hoście jawnie włączono
gateway.auth.trustedProxy.allowLoopback. - [ ] Proxy usuwa nagłówki: Twoje proxy nadpisuje (zamiast dołączać) nagłówki
x-forwarded-*pochodzące od klientów. - [ ] Terminacja TLS: Twoje proxy obsługuje TLS; użytkownicy łączą się przez HTTPS.
- [ ] Lista allowedOrigins jest jawna: Interfejs sterowania używany poza interfejsem pętli zwrotnej korzysta z jawnej wartości
gateway.controlUi.allowedOrigins. - [ ] Ustawiono allowUsers (zalecane): Ogranicz dostęp do znanych użytkowników zamiast zezwalać każdemu uwierzytelnionemu użytkownikowi.
- [ ] Brak mieszanej konfiguracji tokenu: Nie ustawiaj jednocześnie
gateway.auth.tokenigateway.auth.mode: "trusted-proxy". - [ ] Lokalne uwierzytelnianie zapasowe hasłem jest prywatne: Jeśli konfigurujesz
gateway.auth.passworddla wewnętrznych klientów łączących się bezpośrednio, zabezpiecz port Gateway zaporą, aby zdalni klienci niekorzystający z proxy nie mogli uzyskać do niego bezpośredniego dostępu.
Audyt bezpieczeństwa
Polecenie openclaw security audit zgłasza uwierzytelnianie przez zaufane proxy jako problem o krytycznym poziomie ważności. Jest to zamierzone przypomnienie, że przekazujesz odpowiedzialność za bezpieczeństwo konfiguracji proxy.
Audyt sprawdza:
- Podstawowe ostrzeżenie lub krytyczne przypomnienie
gateway.trusted_proxy_auth. - Brak konfiguracji
trustedProxies. - Brak konfiguracji
userHeader. - Pustą listę
allowUsers(zezwala każdemu uwierzytelnionemu użytkownikowi). - Włączoną opcję
allowLoopbackdla źródeł proxy na tym samym hoście.
Gdy interfejs sterowania jest udostępniony, obowiązują również osobne ustalenia niezwiązane bezpośrednio z zaufanym proxy: symbol wieloznaczny lub brak gateway.controlUi.allowedOrigins oraz zapasowe określanie źródła na podstawie nagłówka Host.
Rozwiązywanie problemów
trusted_proxy_untrusted_source
Żądanie nie pochodziło z adresu IP znajdującego się w gateway.trustedProxies. Sprawdź:
- Czy adres IP proxy jest prawidłowy? (Adresy IP kontenerów Docker mogą się zmieniać).
- Czy przed Twoim proxy znajduje się moduł równoważenia obciążenia?
- Użyj
docker inspectlubkubectl get pods -o wide, aby znaleźć rzeczywiste adresy IP.
trusted_proxy_loopback_source
OpenClaw odrzucił żądanie zaufanego proxy pochodzące z interfejsu pętli zwrotnej.
Sprawdź:
- Czy proxy łączy się z adresu
127.0.0.1/::1? - Czy próbujesz używać uwierzytelniania przez zaufane proxy z odwrotnym proxy działającym na tym samym hoście i korzystającym z interfejsu pętli zwrotnej?
Rozwiązanie:
- Preferuj uwierzytelnianie tokenem lub hasłem dla wewnętrznych klientów na tym samym hoście, którzy nie korzystają z proxy, albo
- Kieruj ruch przez adres zaufanego proxy spoza interfejsu pętli zwrotnej i zachowaj ten adres IP w
gateway.trustedProxies, albo - W przypadku celowo skonfigurowanego odwrotnego proxy na tym samym hoście ustaw
gateway.auth.trustedProxy.allowLoopback = true, zachowaj adres interfejsu pętli zwrotnej wgateway.trustedProxiesi upewnij się, że proxy usuwa lub nadpisuje nagłówki tożsamości.
trusted_proxy_local_interface_source / trusted_proxy_local_interface_check_failed
Źródłowy adres IP żądania odpowiadał jednemu z własnych adresów interfejsów sieciowych hosta Gateway innych niż interfejs pętli zwrotnej (a nie adresowi proxy). Jest to zabezpieczenie przed podszytym ruchem z tego samego hosta w sieciach tailnet lub sieciach mostkowych Docker. Błąd ..._check_failed oznacza, że samo wykrywanie interfejsów zakończyło się błędem, dlatego OpenClaw odrzuca żądanie w razie wątpliwości.
Sprawdź:
- Czy proces działający bezpośrednio na hoście Gateway wysyła nagłówki tożsamości, omijając proxy?
- Czy proxy działa w tej samej przestrzeni nazw sieci co Gateway, a jego adres IP jest również widoczny jako interfejs lokalny?
Rozwiązanie: kieruj ruch proxy przez adres, który nie jest jednocześnie powiązany lokalnie z hostem Gateway, albo używaj allowLoopback wyłącznie w rzeczywistej konfiguracji proxy na tym samym hoście.
trusted_proxy_user_missing
Nagłówek użytkownika był pusty lub nieobecny. Sprawdź:
- Czy Twoje proxy jest skonfigurowane do przekazywania nagłówków tożsamości?
- Czy nazwa nagłówka jest prawidłowa? (Wielkość liter nie ma znaczenia, ale pisownia tak).
- Czy użytkownik został rzeczywiście uwierzytelniony przez proxy?
trusted_proxy_missing_header_*
Wymagany nagłówek nie był obecny. Sprawdź:
- Konfigurację proxy dotyczącą tych konkretnych nagłówków.
- Czy nagłówki nie są usuwane gdzieś w łańcuchu.
trusted_proxy_user_not_allowed
Użytkownik jest uwierzytelniony, ale nie znajduje się na liście allowUsers. Dodaj go albo usuń listę dozwolonych użytkowników.
trusted_proxy_no_proxies_configured / trusted_proxy_config_missing
Wartość gateway.auth.mode to "trusted-proxy", ale lista gateway.trustedProxies jest pusta albo brakuje samej konfiguracji gateway.auth.trustedProxy. Każde żądanie jest odrzucane, dopóki nie zostaną ustawione obie wartości.
trusted_proxy_origin_not_allowed
Uwierzytelnianie przez zaufane proxy powiodło się, ale nagłówek przeglądarki Origin nie przeszedł kontroli źródła interfejsu sterowania.
Sprawdź:
- Czy
gateway.controlUi.allowedOriginszawiera dokładne źródło przeglądarki. - Czy nie polegasz na źródłach z symbolem wieloznacznym, chyba że celowo chcesz zezwolić na wszystkie źródła.
- Jeśli celowo używasz trybu zapasowego opartego na nagłówku Host, upewnij się, że
gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=trueustawiono świadomie.
Connection succeeds but methods report missing scope
Połączenie WebSocket zostaje nawiązane, ale wywołanie chat.history, sessions.list lub
models.list kończy się błędem missing scope: operator.read.
Typowe przyczyny:
- Sesja interfejsu sterowania bez tożsamości urządzenia: uwierzytelnianie przez zaufane proxy może dopuścić połączenie WebSocket bez tożsamości urządzenia, ale OpenClaw z założenia usuwa zakresy z sesji bez urządzenia.
- Niestandardowy klient zaplecza: opcja
gateway.controlUi.dangerouslyDisableDeviceAuthdotyczy interfejsu sterowania i nie przyznaje zakresów dowolnym klientom WebSocket zaplecza ani klientom o strukturze CLI. - Zbyt wąski zakres
x-openclaw-scopes: jeśli proxy wstrzykuje ten nagłówek do żądania aktualizacji połączenia WebSocket interfejsu sterowania, zakresy sesji są ograniczane do tego zestawu. Pusta wartość nagłówka oznacza brak zakresów.
Rozwiązanie:
- W przypadku interfejsu sterowania użyj HTTPS, aby przeglądarka mogła wygenerować tożsamość urządzenia i ukończyć parowanie.
- W przypadku niestandardowej automatyzacji użyj tożsamości urządzenia i parowania, zastrzeżonej bezpośredniej lokalnej ścieżki pomocniczej zaplecza
gateway-clientalbo administracyjnego RPC HTTP. - Używaj
gateway.controlUi.dangerouslyDisableDeviceAuth: truewyłącznie jako tymczasowej, awaryjnej ścieżki dostępu do interfejsu sterowania.
WebSocket still failing
Upewnij się, że Twoje proxy:
- Obsługuje aktualizację połączeń WebSocket (
Upgrade: websocket,Connection: upgrade). - Przekazuje nagłówki tożsamości w żądaniach aktualizacji połączenia WebSocket (nie tylko HTTP).
- Nie ma osobnej ścieżki uwierzytelniania dla połączeń WebSocket.
Migracja z uwierzytelniania tokenem
Configure the proxy
Skonfiguruj proxy tak, aby uwierzytelniało użytkowników i przekazywało nagłówki.
Test the proxy independently
Niezależnie przetestuj konfigurację proxy (użyj curl z nagłówkami).
Update OpenClaw config
Zaktualizuj konfigurację OpenClaw, dodając uwierzytelnianie przez zaufane proxy.
Restart the Gateway
Uruchom ponownie Gateway.
Test WebSocket
Przetestuj połączenia WebSocket z interfejsu sterowania.
Audit
Uruchom openclaw security audit i przejrzyj ustalenia.
Powiązane materiały
- Konfiguracja — dokumentacja konfiguracji
- Zakresy operatora — role, zakresy i kontrole zatwierdzeń
- Dostęp zdalny — inne wzorce dostępu zdalnego
- Bezpieczeństwo — pełny przewodnik dotyczący bezpieczeństwa
- Tailscale — prostsza alternatywa dla dostępu ograniczonego do sieci tailnet