Bezpieczeństwo instancji OpenClaw: bind, auth, sekrety i kopie
Umowy, RODO i papiery to lekcja siódma i szesnasta. Ta jest o portach, tokenach i uprawnieniach plików. Żadna z tych rzeczy nie zajmuje więcej niż kwadrans, a pominięcie jednej potrafi wystawić Twoje dane na otwarty port.
Zanim otworzysz port: pięć trybów gateway.bind
Gateway multipleksuje WebSocket i HTTP na jednym porcie, domyślnie 18789, a o tym, kto może się do niego dobić, decyduje gateway.bind. Tryby to loopback (domyślny, tylko połączenia lokalne), lan, tailnet, auto i custom. Loopback jest opisany jako zalecany punkt startu dla instalacji typu osobisty asystent i naprawdę nie ma powodu, żeby ruszać go pierwszego dnia.
Dokumentacja formułuje warunek bardzo bezpośrednio: szersza ekspozycja wymaga uwierzytelniania gatewaya (współdzielonego tokenu, hasła albo poprawnie skonfigurowanego zaufanego proxy) oraz prawdziwej zapory. Wystawianie gatewaya na 0.0.0.0 bez auth jest odradzane wprost, bez żadnych zastrzeżeń typu „chyba że w sieci wewnętrznej”.
Zamiast otwierać LAN, dokumentacja poleca Tailscale Serve i tryb tailnet. Wtedy dostęp opiera się na tożsamości urządzenia w sieci prywatnej, a nie na tym, że ktoś zna adres IP i port. Audyt bezpieczeństwa ma zresztą osobny check gateway.tailscale_funnel, bo Funnel wystawia usługę do publicznego internetu i to jest już całkiem inna decyzja niż Serve.
Osobna warstwa to Control UI. gateway.controlUi.enabled jest domyślnie włączone, basePath domyślnie prowadzi do /openclaw, a gateway.controlUi.allowedOrigins staje się obowiązkowa przy dostępie spoza pętli zwrotnej. Istnieje też zmienna OPENCLAW_ALLOW_INSECURE_PRIVATE_WS, która zdejmuje wymóg szyfrowania na prywatnych nazwach DNS. Ustawiasz ją tylko w środowisku procesu i tylko na czas jednej awarii, nie w configu i nie na stałe.
Nazwa trybu auto sugeruje, że coś się samo domyśli. Nie domyśli się, że siedzisz w kontenerze, i to akurat mocno myli ludzi. Sprawdź to, zanim spędzisz wieczór na szukaniu, czemu przeglądarka nie widzi dashboardu.
openclaw config get gateway.bind
openclaw config get gateway.port
openclaw gateway status --deep --jsonDlaczego -p 18789:18789 nie wystarcza w Dockerze
W kontenerze domyślny loopback oznacza 127.0.0.1 wewnątrz kontenera, a nie na Twoim hoście. Przy zwykłym mapowaniu -p 18789:18789 ruch przychodzi na interfejs kontenera, gateway nasłuchuje wyłącznie na pętli zwrotnej i połączenie nie dochodzi. Nie ma trybu, który włączy się sam po wykryciu kontenera, gateway.bind trzeba zmienić świadomie i od razu dołożyć uwierzytelnianie.
Dlatego oficjalny skrypt ./scripts/docker/setup.sh ustawia bind na lan i przy okazji generuje token podczas onboardingu. Konsekwencja jest prosta: skoro proces musi nasłuchiwać poza pętlą, auth przestaje być opcjonalne. Dashboard otwierasz potem pod http://127.0.0.1:18789/ z wygenerowanym tokenem. Obrazy oficjalne to ghcr.io/openclaw/openclaw:latest jako główne źródło i openclaw/openclaw:latest jako lustro na Docker Hubie.
Druga część pułapki jest sieciowa i kosztuje więcej. Publikowanie portów przez -p przepuszcza ruch przez łańcuchy forwardowania Dockera, a nie tylko przez INPUT hosta. Twoje reguły UFW mogą wyglądać na szczelne i nie łapać niczego, bo decyzja zapada w łańcuchu DOCKER-USER. Dokumentacja pokazuje przykładowy zestaw reguł dla tego łańcucha (przepuszczone 80, 443 i SSH plus połączenia established, reszta odrzucona) oraz osobne reguły IPv6 w /etc/ufw/after6.rules.
Przy pisaniu tych reguł nie zaszywaj nazw interfejsów w rodzaju eth0. Różnią się między obrazami VPS-ów, a reguła, która nie pasuje do niczego, po cichu nie blokuje niczego. To jest ten rodzaj błędu, którego nie widać w żadnym logu, dopóki ktoś nie zeskanuje Ci portu.
Trwałość stanu zapewniają trzy podpięte katalogi: /home/node/.openclaw na config, /home/node/.config/openclaw na profile uwierzytelniania i /home/node/.openclaw/workspace na przestrzeń roboczą. Znany objaw rozjechanego właścicielstwa to komunikat „blocked plugin candidate: suspicious ownership (uid=1000, expected uid=0 or root)”. Naprawa jest krótka: sudo chown -R 1000:1000 na katalog konfiguracji i workspace, potem openclaw doctor --fix.
docker pull ghcr.io/openclaw/openclaw:latest
# gdy plugin nie chce się załadować w kontenerze:
sudo chown -R 1000:1000 <config> <workspace>
openclaw doctor --fixUwierzytelnianie Gatewaya jest fail-closed, ustaw je świadomie
Uwierzytelnianie jest wymagane domyślnie i działa fail-closed: bez poprawnie skonfigurowanej ścieżki auth gateway odmawia połączeń WebSocket. Gateway odmawia bindowania bez skonfigurowanego auth, a w logu zostawia wtedy „refusing to bind gateway without auth”. Tryb ustawia gateway.auth.mode i przyjmuje wartości none, token, password oraz trusted-proxy.
Zalecany jest tryb token, czyli współdzielony bearer token w gateway.auth.token. Nie wymyślaj go sam, openclaw doctor --generate-gateway-token zrobi to za Ciebie. Odpowiedniki środowiskowe to OPENCLAW_GATEWAY_TOKEN i OPENCLAW_GATEWAY_PASSWORD, przy czym hasło lepiej trzymać właśnie w zmiennej niż w pliku konfiguracyjnym.
Tryb trusted-proxy ma dwie pułapki, na które dokumentacja zwraca uwagę osobno. Pierwsza: Twoje proxy musi nadpisywać nagłówek X-Forwarded-For, a nie dopisywać do niego kolejne wartości, inaczej klient sam podstawi sobie tożsamość. Druga: reverse proxy stojące na pętli zwrotnej musi mieć jawnie ustawione gateway.auth.trustedProxy.allowLoopback na true, bez tego i tak wymagany jest token albo hasło. Tożsamość przychodzi nagłówkiem wskazanym w userHeader.
Webhooki i hooki uwierzytelniają się nagłówkiem Authorization: Bearer albo x-openclaw-token. Audyt ma na to osobny check hooks.token_reuse_gateway_token, bo używanie tego samego sekretu do gatewaya i do hooków oznacza, że rotacja jednego wymusza rotację drugiego, a zwykle zapomina się o tym drugim. Drugi check z tej rodziny, hooks.allowed_agent_ids_unrestricted, wyłapuje hooki, które mogą trafić do dowolnego agenta.
Jedna rzecz proceduralna, o którą wszyscy się potykają: zmiana portu i zmiana ustawień uwierzytelniania to zmiany infrastrukturalne. Hot reload ich nie podniesie. Po edycji trzeba zrestartować gateway, inaczej będziesz debugować konfigurację, która jeszcze nie działa.
openclaw doctor --generate-gateway-token
openclaw config set gateway.auth.mode token
openclaw gateway restartSekrety mają leżeć na hoście gatewaya, nie w workspace
Zasada, którą dokumentacja formułuje najkrócej: zakładaj, że cokolwiek leży pod ~/.openclaw, może zawierać sekrety albo dane prywatne. Stąd konkretne uprawnienia. 600 na ~/.openclaw/openclaw.json, 700 na sam katalog ~/.openclaw, 600 na wszystko w ~/.openclaw/credentials oraz 600 na ~/.openclaw/state/openclaw.sqlite, gdzie siedzą tokeny MCP i stan runtime.
Poświadczenia dostawców modeli nie mają prawa leżeć w pliku .env wewnątrz workspace agenta. Ich miejsce to środowisko procesu gatewaya, globalny dotenv albo config. Powód jest prozaiczny: workspace projekt zaleca trzymać w prywatnym repozytorium git, a narzędzia agenta czytają go swobodnie. Klucz w tym katalogu to klucz w historii commitów.
Sekrety wczytywane są z trzech źródeł w ustalonej kolejności: zmienne procesu rodzica, plik .env z bieżącego katalogu roboczego, na końcu globalny ~/.openclaw/.env jako fallback. W samym configu działają podstawienia ${NAZWA_ZMIENNEJ} wewnątrz stringów, ale tylko dla nazw pisanych wielkimi literami. Gdy gateway chodzi jako usługa systemowa i nie widzi zmiennych użytkownika, ratuje OPENCLAW_LOAD_SHELL_ENV=1.
Katalogu ~/.openclaw nie wrzucaj do repozytorium nigdy. Są tam poświadczenia kanałów, tokeny OAuth, transkrypty sesji i zaszyfrowane payloady sekretów. Workspace i katalog stanu to dwie osobne lokalizacje, obie wymagają kopii, ale tylko jedna nadaje się do gita.
Przy zgłoszeniach do wsparcia i przy migracji przydaje się nawyk sprawdzania obecności tokenu bez wypisywania jego wartości. Do samego zgłoszenia lepiej nadaje się openclaw status --all, to diagnoza tylko do odczytu z ogonem logów i zredagowanymi tokenami.
chmod 700 ~/.openclaw
chmod 600 ~/.openclaw/openclaw.json
chmod -R 600 ~/.openclaw/credentials
openclaw status --allSandbox ogranicza zasięg błędu, ale nie zastępuje polityki narzędzi
Sandbox oddziela wykonywanie narzędzi od procesu gatewaya i domyślnie jest wyłączony. Włączasz go w agents.defaults.sandbox globalnie albo w agents.entries.*.sandbox dla pojedynczego agenta. Trzy ustawienia sterują całością: sandbox.mode przyjmuje off, non-main i all (domyślnie off), sandbox.scope przyjmuje agent, session i shared (domyślnie agent), a sandbox.backend to docker, ssh albo openshell (domyślnie docker). Wariantu shared lepiej unikać.
Dostęp sandboxa do workspace ustawia workspaceAccess. Wartość none jest domyślna i daje narzędziom tylko workspace sandboxa, ro montuje workspace agenta do odczytu pod /agent, a rw daje zapis pod /workspace. Backend dockerowy startuje z restrykcyjnymi wartościami: network ustawiony na none, czyli brak ruchu wychodzącego, readOnlyRoot włączone i zrzucone capability. Obraz sandboxa budujesz skryptem scripts/sandbox-setup.sh, a w instalacji dockerowej włącza go OPENCLAW_SANDBOX=1 przed uruchomieniem setup.sh.
Dokumentacja nie udaje, że sandbox jest granicą bezpieczeństwa. Ogranicza dostęp do plików i procesów, gdy model zrobi coś głupiego, i na tym kończy się jego rola (sam gateway zostaje poza nim. Osobne wyjście awaryjne stanowi tools.elevated) uruchamia exec poza sandboxem i obchodzi całą tę warstwę. Trzymaj tools.elevated.enabled na false, a jeśli musisz go włączyć, tools.elevated.allowFrom ma być wąskie.
Twarda podstawa na start wygląda tak: gateway.mode local, gateway.bind loopback, gateway.auth.mode token, session.dmScope ustawione na per-channel-peer, tools.profile na messaging, tools.fs.workspaceOnly na true, tools.exec.security na deny i tools.exec.ask na always, tools.elevated.enabled na false. Do tego dmPolicy pairing na kanałach i requireMention w grupach.
Po stronie kanałów są dwa szczegóły, które lubią zaskakiwać. Tryb dmPolicy „open” wymaga jawnego wpisu „*” na allowliście kanału, bez niego wiadomości nadal będą blokowane. A w grupach działa groupAllowFrom; allowFrom pełni tam tylko rolę fallbacku. Ustawienie samego allowFrom i zdziwienie, że nic nie przechodzi, to klasyk.
{
agents: {
defaults: {
sandbox: { mode: "all", scope: "agent", backend: "docker", workspaceAccess: "none" }
}
},
tools: {
profile: "messaging",
fs: { workspaceOnly: true },
exec: { security: "deny", ask: "always" },
elevated: { enabled: false }
}
}openclaw security audit robi to, czego nie chce Ci się sprawdzać ręcznie
Zamiast przechodzić powyższą listę z pamięci, odpal openclaw security audit. Komenda wykonuje ponad 80 sprawdzeń, każde z własnym identyfikatorem checkId i przypisaną wagą: critical, warn albo info. Przy każdym znalezisku widać też, czy istnieje automatyczna naprawa.
Zakres pokrywa dokładnie te miejsca, w których ludzie się mylą. Uprawnienia plików łapią fs.state_dir.perms_world_writable i fs.config.perms_writable. Ekspozycję sieciową i brak auth, gateway.bind_no_auth, gateway.http.no_auth oraz gateway.tailscale_funnel. Control UI, gateway.control_ui.allowed_origins_required i gateway.control_ui.device_auth_disabled. Sandbox, sandbox.dangerous_bind_mount i sandbox.dangerous_network_mode. Politykę wykonywania poleceń, tools.exec.security_full_configured. A dostępność narzędzi z otwartych kanałów: security.exposure.open_channels_with_exec.
Flaga --deep dokłada żywe sondowanie gatewaya i kolektory bezpieczeństwa pluginów, w tym checki plugins.code_safety i skills.code_safety szukające podejrzanych wzorców w kodzie. Do sondowania trzeba podać poświadczenia: --deep --token <token> albo --deep --password <hasło>. Wyjście maszynowe daje --json.
Flaga --fix jest celowo wąska i to jej zaleta. Stosuje naprawy deterministyczne: zaciska uprawnienia do 600 na plikach i 700 na katalogach oraz przestawia otwarte polityki grupowe na allowlisty. Nie rotuje poświadczeń i nie wyłącza narzędzi, takie decyzje zostają po Twojej stronie. Jeśli świadomie akceptujesz jakieś ryzyko, zapisz to w security.audit.suppressions, zamiast uczyć się ignorować czerwony wynik.
Praktyczny moment na uruchomienie audytu jest jeden: przed każdą zmianą ekspozycji sieciowej albo polityki dostępu. Nie po. Różnica polega na tym, że przed zmianą naprawiasz konfigurację, a po zmianie już tylko odtwarzasz, co się wydarzyło.
openclaw security audit
openclaw security audit --deep --token <token>
openclaw security audit --fix
openclaw security audit --jsonKopia zapasowa i plan na noc, w której coś wycieknie
Kopię robisz komendą openclaw backup create z flagą --verify, która waliduje archiwum od razu po utworzeniu. Obejmuje katalog stanu, aktywny plik konfiguracyjny, katalog credentials, katalogi workspace, profile uwierzytelniania, stan sesji i bazy SQLite. Bazy zrzucane są przez online backup API SQLite i kompaktowane przez VACUUM, więc gatewaya nie trzeba zatrzymywać.
Przydatne flagi: --dry-run do podglądu, --json do wyjścia maszynowego, --no-include-workspace, gdy workspace i tak żyje w gicie, oraz --only-config, gdy chcesz zapisać sam plik konfiguracyjny. Flaga --agent <id> nie należy do backup create, używa się jej przy openclaw backup sqlite create. Podkomendy create, list, verify i restore wskazują repozytorium snapshotów flagą --repository <katalog> i to ona jest tam obowiązkowa.
Plan na incydent ma trzy fazy i dobrze mieć go zapisany, zanim będzie potrzebny. Powstrzymanie: zatrzymujesz gateway, ustawiasz gateway.bind na loopback, wyłączasz ryzykowne polityki DM i grup. Rotacja: zmieniasz gateway.auth.token, gateway.remote.token oraz poświadczenia dostawców. Przegląd: czytasz openclaw logs, transkrypty sesji z ~/.openclaw/agents/<agentId>/sessions/ oraz ostatnie zmiany w konfiguracji.
Odrzucone konfiguracje zostają obok pliku jako openclaw.json.rejected.<timestamp>, a nadpisane jako *.clobbered.*. Gateway przyjmuje wyłącznie pliki w pełni zgodne ze schematem, więc literówka nie nadpisze działającej wersji. Do przywrócenia ostatniej znanej dobrej kopii służy openclaw doctor --fix.
Jeśli utrzymywanie tej warstwy samodzielnie nie jest pracą, którą chcesz wykonywać, istnieje wariant chmurowy: ClawLabs uruchamia instancję OpenClaw w chmurze EU (Hetzner), z własnymi kluczami API w modelu BYOK i DPA na żądanie, plany od 399 zł miesięcznie. Sam OpenClaw jest darmowy i otwarty, więc wybór sprowadza się do tego, kto ma pilnować portów, tokenów i kopii.
mkdir -p ~/Backups/openclaw
openclaw backup create --output ~/Backups/openclaw --verify
openclaw backup sqlite list --repository ~/Backups/openclaw-sqlite
openclaw doctor --fixCo warto zapamiętać
- Domyślny gateway.bind to loopback, a w kontenerze oznacza to 127.0.0.1 wewnątrz kontenera, przy zwykłym -p 18789:18789 gateway pozostaje nieosiągalny, dopóki nie zmienisz bindu i nie dołożysz uwierzytelniania.
- Publikowanie portu przez -p omija reguły INPUT hosta: decyzje zapadają w łańcuchu DOCKER-USER, a reguły IPv6 trzeba dopisać osobno w /etc/ufw/after6.rules.
- gateway.auth.mode przyjmuje none, token, password i trusted-proxy; token generuje openclaw doctor --generate-gateway-token, a proxy musi nadpisywać X-Forwarded-For, nie dopisywać do niego.
- Uprawnienia z dokumentacji: 700 na ~/.openclaw, 600 na openclaw.json, 600 na ~/.openclaw/credentials/** i 600 na ~/.openclaw/state/openclaw.sqlite, gdzie leżą tokeny MCP.
- Sandbox jest domyślnie wyłączony; sandbox.mode ma wartości off, non-main i all, scope domyślnie agent, backend domyślnie docker, workspaceAccess domyślnie none. tools.elevated omija sandbox całkowicie.
- openclaw security audit wykonuje ponad 80 sprawdzeń z identyfikatorami takimi jak gateway.bind_no_auth czy sandbox.dangerous_network_mode; --fix zaciska uprawnienia do 600/700 i zamienia otwarte polityki grup na allowlisty, ale nie rotuje poświadczeń.
Częste pytania
Uruchomiłem OpenClaw w Dockerze z -p 18789:18789 i nie mogę wejść na dashboard. Co jest nie tak?+
Prawie na pewno bind. Domyślny loopback oznacza 127.0.0.1 wewnątrz kontenera, a ruch z mapowania portu przychodzi na interfejs kontenera, więc nikt go nie odbiera. Trzeba świadomie zmienić gateway.bind i od razu włączyć uwierzytelnianie, bo bez auth gateway odmówi bindowania poza pętlą. Oficjalny skrypt ./scripts/docker/setup.sh robi obie rzeczy naraz: ustawia bind na lan i generuje token podczas onboardingu.
Mam UFW i przepuszczone tylko 22, 80 i 443. Czy port 18789 z kontenera jest zablokowany?+
Niekoniecznie. Publikowanie portów przez -p przepuszcza ruch przez łańcuchy forwardowania Dockera, a nie tylko przez INPUT hosta, więc reguły UFW mogą go w ogóle nie dotykać. Reguły trzeba dopisać w łańcuchu DOCKER-USER, a dla IPv6 osobno w /etc/ufw/after6.rules. Przy pisaniu nie zaszywaj nazw interfejsów w rodzaju eth0: różnią się między obrazami VPS-ów, a reguła, która nie pasuje, po cichu niczego nie blokuje.
Czy sandbox wystarczy, żeby agent nie zrobił szkód na serwerze?+
Nie wystarczy sam z siebie. Dokumentacja opisuje sandbox jako mechanizm, który realnie ogranicza dostęp do plików i procesów, ale nie jest doskonałą granicą bezpieczeństwa. Sam gateway działa poza sandboxem, a tools.elevated uruchamia exec z jego pominięciem. Sandbox trzeba więc łączyć z polityką narzędzi: tools.profile, tools.fs.workspaceOnly, tools.exec.security oraz tools.elevated.enabled ustawione na false.
Co zrobić najpierw, gdy podejrzewam, że ktoś dostał się do instancji?+
Trzy fazy w tej kolejności. Powstrzymanie: zatrzymaj gateway, ustaw gateway.bind na loopback, wyłącz ryzykowne polityki DM i grup. Rotacja: zmień gateway.auth.token, gateway.remote.token oraz poświadczenia dostawców modeli i kanałów. Przegląd: przejrzyj openclaw logs, transkrypty sesji w ~/.openclaw/agents/<agentId>/sessions/ i ostatnie zmiany konfiguracji. Dopiero potem wracaj do normalnej ekspozycji.
Źródła danych z tej lekcji
- OpenClaw Docs: Gateway Security (bind, auth, sekrety, incydenty)
- OpenClaw Docs, Security audit checks
- OpenClaw Docs, CLI: security
- OpenClaw Docs, Sandboxing
- OpenClaw Docs, Docker install
- OpenClaw Docs, Configuration reference
- OpenClaw Docs, CLI: backup
- ClawLabs, konfiguracja OpenClaw po polsku
- ClawLabs, bezpieczeństwo i dane
Chcesz to przećwiczyć na żywo?
Uruchom własnego agenta i wypróbuj to, o czym przed chwilą przeczytałeś. Pierwsza subskrypcja pakietu Premium ma 5 dni za darmo, a kurs czytasz dalej niezależnie od tego.
Zobacz plany