사용해야 하는 경우
- OpenClaw를 ID 인식 프록시(Pomerium, Caddy + OAuth, nginx + oauth2-proxy, Traefik + 전달 인증) 뒤에서 실행하는 경우.
- 프록시가 모든 인증을 처리하고 헤더를 통해 사용자 ID를 전달하는 경우.
- 프록시가 Gateway에 접근할 수 있는 유일한 경로인 Kubernetes 또는 컨테이너 환경을 사용하는 경우.
- 브라우저가 WS 페이로드로 토큰을 전달할 수 없어 WebSocket
1008 unauthorized오류가 발생하는 경우.
사용하면 안 되는 경우
- 프록시가 사용자를 인증하지 않는 경우(단순한 TLS 종단점 또는 로드 밸런서인 경우).
- 프록시를 우회하여 Gateway에 접근할 수 있는 경로가 하나라도 있는 경우(방화벽 허점, 내부 네트워크 접근).
- 프록시가 전달된 헤더를 올바르게 제거하거나 덮어쓰는지 확실하지 않은 경우.
- 개인용 단일 사용자 접근만 필요한 경우(대신 Tailscale Serve + local loopback 사용을 고려하세요).
작동 방식
1
프록시가 사용자를 인증
리버스 프록시가 사용자 인증(OAuth, OIDC, SAML 등)을 수행합니다.
2
프록시가 ID 헤더를 추가
프록시가 인증된 사용자 ID가 포함된 헤더를 추가합니다(예:
x-forwarded-user: nick@example.com).3
Gateway가 신뢰할 수 있는 출처를 확인
OpenClaw는 요청이 신뢰할 수 있는 프록시 IP(
gateway.trustedProxies)에서 왔으며 Gateway 자체의 loopback 또는 로컬 인터페이스 주소에서 오지 않았는지 확인합니다.4
Gateway가 ID를 추출
OpenClaw는 필수 헤더를 읽은 다음 구성된 헤더에서 사용자 ID를 읽습니다.
5
권한 부여
모든 검사를 통과하고 사용자가
allowUsers(설정된 경우) 검사를 통과하면 요청에 권한이 부여됩니다.구성
구성 참조
string[]
필수
신뢰할 프록시 IP 주소(또는 CIDR)의 배열입니다. 다른 IP에서 온 요청은 거부됩니다.
string
필수
반드시
"trusted-proxy"여야 합니다.string
필수
인증된 사용자 ID가 포함된 헤더 이름입니다.
string[]
요청을 신뢰하기 위해 반드시 존재해야 하는 추가 헤더입니다.
string[]
사용자 ID 허용 목록입니다. 비어 있으면 인증된 모든 사용자를 허용합니다.
boolean
기본값:"false"
동일 호스트의 loopback 리버스 프록시에 대한 선택적 지원입니다.
Control UI 페어링 동작
gateway.auth.mode = "trusted-proxy"가 활성화되어 있고 요청이 신뢰할 수 있는 프록시 검사를 통과하면 Control UI WebSocket 세션은 기기 페어링 ID 없이 연결할 수 있습니다.
범위 관련 영향:
- 기기 없는 Control UI WebSocket 세션은 연결되지만 기본적으로 운영자 범위를 받지 않습니다. OpenClaw는 승인 및 페어링된 기기/토큰에 바인딩되지 않은 세션이 권한을 자체 선언하지 못하도록 요청된 범위 목록을
[]로 초기화합니다. - WebSocket 연결에 성공한 후 메서드가
missing scope로 실패하면 브라우저가 기기 ID를 생성하고 페어링을 완료할 수 있도록 HTTPS를 사용하세요. Control UI의 안전하지 않은 HTTP를 참조하세요. - 비상시에만 사용:
gateway.controlUi.dangerouslyDisableDeviceAuth=true는 기기 ID가 없어도 요청된 범위를 유지합니다. 이는 보안을 심각하게 약화하므로 신속하게 되돌리세요. Control UI의 안전하지 않은 HTTP를 참조하세요.
x-openclaw-scopes를 보내면 OpenClaw는 세션 범위를 요청된 범위와 선언된 범위의 교집합으로 제한합니다. 이 헤더는 범위를 부여하지 않으며 세션이 보유할 수 있는 범위만 좁힙니다.
영향:
- 이 모드에서는 페어링이 더 이상 Control UI 접근의 기본 게이트가 아닙니다.
- 리버스 프록시 인증 정책과
allowUsers가 실질적인 접근 제어 수단이 됩니다. - Gateway 인그레스는 신뢰할 수 있는 프록시 IP로만 제한하세요(
gateway.trustedProxies+ 방화벽).
gateway.controlUi.dangerouslyDisableDeviceAuth는 임의의 client.mode: "backend" 또는 CLI 형태의 클라이언트에 범위를 부여하지 않습니다. 사용자 지정 자동화는 기기 ID/페어링, 예약된 직접 로컬 client.id: "gateway-client" 백엔드 도우미 경로 또는 HTTP 요청/응답 인터페이스가 더 적합한 경우 관리자 HTTP RPC Plugin을 사용해야 합니다.
운영자 범위 헤더
신뢰할 수 있는 프록시 인증은 ID를 포함하는 HTTP 모드이므로 호출자는 HTTP API 요청에x-openclaw-scopes를 사용하여 운영자 범위를 선택적으로 선언할 수 있습니다.
참고: WebSocket 범위는 Gateway 프로토콜 핸드셰이크와 기기 ID 바인딩에 의해 결정됩니다. Control UI WebSocket 업그레이드 요청에서 x-openclaw-scopes는 협상된 세션 범위의 상한일 뿐 범위를 부여하지 않습니다. Control UI 페어링 동작을 참조하세요.
예:
x-openclaw-scopes: operator.readx-openclaw-scopes: operator.read,operator.writex-openclaw-scopes: operator.admin,operator.write
- 헤더가 있으면 OpenClaw는 선언된 범위 집합을 적용합니다.
- 헤더가 있지만 비어 있으면 요청은 운영자 범위가 없음을 선언합니다.
- 헤더가 없으면 일반적인 ID 포함 HTTP API는 표준 운영자 기본 범위 집합(
operator.admin,operator.read,operator.write,operator.approvals,operator.pairing,operator.talk.secrets)으로 폴백합니다. - Gateway 인증 Plugin HTTP 경로는 기본적으로 더 제한적입니다.
x-openclaw-scopes가 없으면 런타임 범위는operator.write로만 폴백합니다. - 브라우저 출처 HTTP 요청은 신뢰할 수 있는 프록시 인증에 성공한 후에도
gateway.controlUi.allowedOrigins(또는 의도적으로 설정한 Host 헤더 폴백 모드)를 통과해야 합니다.
x-openclaw-scopes를 명시적으로 전송하세요.
TLS 종단과 HSTS
TLS 종단 지점을 하나만 사용하고 그곳에서 HSTS를 적용하세요.- 프록시 TLS 종단(권장)
- Gateway TLS 종단
리버스 프록시가
https://control.example.com의 HTTPS를 처리하는 경우 해당 도메인에 대해 프록시에서 Strict-Transport-Security를 설정하세요.- 인터넷에 노출되는 배포에 적합합니다.
- 인증서와 HTTP 보안 강화 정책을 한곳에서 관리합니다.
- OpenClaw는 프록시 뒤에서 loopback HTTP로 유지할 수 있습니다.
출시 적용 지침
- 트래픽을 검증하는 동안에는 먼저 짧은 최대 기간(예:
max-age=300)으로 시작하세요. - 충분히 확신한 후에만 장기 값(예:
max-age=31536000)으로 늘리세요. - 모든 하위 도메인이 HTTPS를 사용할 준비가 된 경우에만
includeSubDomains를 추가하세요. - 전체 도메인 집합에 대한 사전 로드 요구 사항을 의도적으로 충족하는 경우에만 사전 로드를 사용하세요.
- loopback 전용 로컬 개발에는 HSTS가 도움이 되지 않습니다.
프록시 설정 예
Pomerium
Pomerium
Pomerium은 Pomerium 구성 조각:
x-pomerium-claim-email(또는 다른 클레임 헤더)에 ID를 전달하고 x-pomerium-jwt-assertion에 JWT를 전달합니다.OAuth를 사용하는 Caddy
OAuth를 사용하는 Caddy
caddy-security Plugin을 사용하는 Caddy는 사용자를 인증하고 ID 헤더를 전달할 수 있습니다.nginx + oauth2-proxy
nginx + oauth2-proxy
oauth2-proxy는 사용자를 인증하고 nginx 구성 스니펫:
x-auth-request-email에 신원 정보를 전달합니다.전달 인증을 사용하는 Traefik
전달 인증을 사용하는 Traefik
혼합 토큰 구성
공유 토큰(gateway.auth.token 또는 OPENCLAW_GATEWAY_TOKEN)도 구성되어 있으면 Gateway 시작 시 신뢰 프록시 인증을 거부합니다. 공유 토큰을 사용하면 동일 호스트 호출자가 이 모드에서 강제하려는 프록시 검증 신원과 완전히 다른 경로로 인증할 수 있으므로 두 방식은 상호 배타적입니다.
시작 시 gateway auth mode is trusted-proxy, but a shared token is also configured와 같은 오류가 발생하면 다음 중 하나를 수행하세요.
- 신뢰 프록시 모드를 사용할 때 공유 토큰을 제거하거나
- 토큰 기반 인증을 사용하려는 경우
gateway.auth.mode를"token"으로 변경합니다.
gateway.auth.password / OPENCLAW_GATEWAY_PASSWORD로 인증할 수 있습니다. 신뢰 프록시 모드에서는 토큰 대체 인증을 의도적으로 지원하지 않습니다.
보안 체크리스트
신뢰 프록시 인증을 활성화하기 전에 다음을 확인하세요.- 프록시가 유일한 경로임: Gateway 포트는 프록시를 제외한 모든 대상에 대해 방화벽으로 차단되어 있습니다.
- trustedProxies가 최소 범위임: 전체 서브넷이 아니라 실제 프록시 IP만 포함합니다.
- local loopback 프록시 소스를 의도적으로 사용함: 동일 호스트 프록시를 위해
gateway.auth.trustedProxy.allowLoopback을 명시적으로 활성화하지 않으면 local loopback 소스 요청의 신뢰 프록시 인증은 실패 시 차단됩니다. - 프록시가 헤더를 제거함: 프록시는 클라이언트의
x-forwarded-*헤더에 값을 추가하지 않고 덮어씁니다. - TLS 종료: 프록시가 TLS를 처리하며 사용자는 HTTPS로 연결합니다.
- allowedOrigins가 명시적임: local loopback이 아닌 Control UI는 명시적인
gateway.controlUi.allowedOrigins를 사용합니다. - allowUsers가 설정됨(권장): 인증된 모든 사용자를 허용하지 않고 알려진 사용자로 제한합니다.
- 혼합 토큰 구성이 없음:
gateway.auth.token과gateway.auth.mode: "trusted-proxy"를 함께 설정하지 마세요. - 로컬 비밀번호 대체 인증이 비공개임: 내부 직접 호출자를 위해
gateway.auth.password를 구성하는 경우, 프록시를 거치지 않는 원격 클라이언트가 Gateway 포트에 직접 접근할 수 없도록 방화벽으로 차단하세요.
보안 감사
openclaw security audit는 신뢰 프록시 인증을 심각 심각도의 발견 사항으로 표시합니다. 이는 의도된 동작이며, 보안을 프록시 설정에 위임하고 있음을 상기시키기 위한 것입니다.
감사에서는 다음을 확인합니다.
- 기본
gateway.trusted_proxy_auth경고/심각 알림. trustedProxies구성 누락.userHeader구성 누락.- 비어 있는
allowUsers(인증된 모든 사용자 허용). - 동일 호스트 프록시 소스에 대해 활성화된
allowLoopback.
gateway.controlUi.allowedOrigins와 Host 헤더 출처 대체 동작이 포함됩니다.
문제 해결
trusted_proxy_untrusted_source
trusted_proxy_untrusted_source
요청이
gateway.trustedProxies의 IP에서 오지 않았습니다. 다음을 확인하세요.- 프록시 IP가 올바릅니까? (Docker 컨테이너 IP는 변경될 수 있습니다.)
- 프록시 앞에 로드 밸런서가 있습니까?
- 실제 IP를 확인하려면
docker inspect또는kubectl get pods -o wide를 사용하세요.
trusted_proxy_loopback_source
trusted_proxy_loopback_source
OpenClaw가 local loopback 소스의 신뢰 프록시 요청을 거부했습니다.다음을 확인하세요.
- 프록시가
127.0.0.1/::1에서 연결하고 있습니까? - 동일 호스트의 local loopback 역방향 프록시에서 신뢰 프록시 인증을 사용하려고 합니까?
- 프록시를 통하지 않는 내부 동일 호스트 클라이언트에는 토큰/비밀번호 인증을 사용하는 것이 좋습니다. 또는
- local loopback이 아닌 신뢰할 수 있는 프록시 주소를 통해 라우팅하고 해당 IP를
gateway.trustedProxies에 유지합니다. 또는 - 의도적으로 동일 호스트 역방향 프록시를 사용하는 경우
gateway.auth.trustedProxy.allowLoopback = true를 설정하고, local loopback 주소를gateway.trustedProxies에 유지하며, 프록시가 신원 헤더를 제거하거나 덮어쓰는지 확인합니다.
trusted_proxy_local_interface_source / trusted_proxy_local_interface_check_failed
trusted_proxy_local_interface_source / trusted_proxy_local_interface_check_failed
요청의 소스 IP가 프록시가 아니라 Gateway 호스트 자체의 local loopback이 아닌 네트워크 인터페이스 주소 중 하나와 일치했습니다. 이는 tailnet 또는 Docker 브리지 네트워크에서 동일 호스트 트래픽을 위조하는 것을 방지하기 위한 보호 장치입니다.
..._check_failed는 인터페이스 검색 자체에서 오류가 발생했음을 의미하므로 OpenClaw는 실패 시 차단합니다.다음을 확인하세요.- Gateway 호스트 자체의 프로세스가 프록시를 우회하여 신원 헤더를 직접 전송하고 있습니까?
- 프록시가 Gateway와 동일한 네트워크 네임스페이스에서 실행되며 로컬 인터페이스에도 표시되는 IP를 사용합니까?
allowLoopback을 사용하세요.trusted_proxy_user_missing
trusted_proxy_user_missing
사용자 헤더가 비어 있거나 누락되었습니다. 다음을 확인하세요.
- 프록시가 신원 헤더를 전달하도록 구성되어 있습니까?
- 헤더 이름이 올바릅니까? (대소문자는 구분하지 않지만 철자는 정확해야 합니다.)
- 사용자가 실제로 프록시에서 인증되었습니까?
trusted_proxy_missing_header_*
trusted_proxy_missing_header_*
필수 헤더가 없습니다. 다음을 확인하세요.
- 해당 특정 헤더에 대한 프록시 구성.
- 체인의 어딘가에서 헤더가 제거되고 있는지 여부.
trusted_proxy_user_not_allowed
trusted_proxy_user_not_allowed
사용자가 인증되었지만
allowUsers에 없습니다. 사용자를 추가하거나 허용 목록을 제거하세요.trusted_proxy_no_proxies_configured / trusted_proxy_config_missing
trusted_proxy_no_proxies_configured / trusted_proxy_config_missing
gateway.auth.mode는 "trusted-proxy"이지만 gateway.trustedProxies가 비어 있거나 gateway.auth.trustedProxy 자체가 누락되었습니다. 둘 다 설정될 때까지 모든 요청이 거부됩니다.trusted_proxy_origin_not_allowed
trusted_proxy_origin_not_allowed
신뢰 프록시 인증은 성공했지만 브라우저의
Origin 헤더가 Control UI 출처 검사를 통과하지 못했습니다.다음을 확인하세요.gateway.controlUi.allowedOrigins에 정확한 브라우저 출처가 포함되어 있습니다.- 모든 출처 허용 동작을 의도하지 않는 한 와일드카드 출처에 의존하지 않습니다.
- Host 헤더 대체 모드를 의도적으로 사용하는 경우
gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true가 의도적으로 설정되어 있습니다.
연결은 성공하지만 메서드에서 범위 누락을 보고함
연결은 성공하지만 메서드에서 범위 누락을 보고함
WebSocket은 연결되지만
chat.history, sessions.list 또는
models.list가 missing scope: operator.read 오류로 실패합니다.일반적인 원인:- 기기 없는 Control UI 세션: 신뢰 프록시 인증은 기기 신원 없이 WebSocket 연결을 허용할 수 있지만, OpenClaw는 설계상 기기 없는 세션의 범위를 제거합니다.
- 사용자 지정 백엔드 클라이언트:
gateway.controlUi.dangerouslyDisableDeviceAuth는 Control UI 범위에만 적용되며 임의의 백엔드 또는 CLI 형태 WebSocket 클라이언트에 범위를 부여하지 않습니다. - 지나치게 제한적인
x-openclaw-scopes: 프록시가 Control UI WebSocket 업그레이드 요청에 이 헤더를 주입하면 세션 범위가 해당 집합으로 제한됩니다. 헤더 값이 비어 있으면 범위가 부여되지 않습니다.
- Control UI의 경우 브라우저가 기기 신원을 생성하고 페어링을 완료할 수 있도록 HTTPS를 사용하세요.
- 사용자 지정 자동화에는 기기 신원/페어링, 예약된 직접 로컬
gateway-client백엔드 도우미 경로 또는 관리자 HTTP RPC를 사용하세요. gateway.controlUi.dangerouslyDisableDeviceAuth: true는 Control UI의 임시 비상 접근 경로로만 사용하세요.
WebSocket이 계속 실패함
WebSocket이 계속 실패함
프록시가 다음을 충족하는지 확인하세요.
- WebSocket 업그레이드(
Upgrade: websocket,Connection: upgrade)를 지원합니다. - HTTP뿐만 아니라 WebSocket 업그레이드 요청에도 신원 헤더를 전달합니다.
- WebSocket 연결에 별도의 인증 경로를 사용하지 않습니다.
토큰 인증에서 마이그레이션
1
프록시 구성
사용자를 인증하고 헤더를 전달하도록 프록시를 구성합니다.
2
프록시를 독립적으로 테스트
프록시 설정을 독립적으로 테스트합니다(헤더를 포함한 curl).
3
OpenClaw 구성 업데이트
신뢰 프록시 인증을 사용하도록 OpenClaw 구성을 업데이트합니다.
4
Gateway 다시 시작
Gateway를 다시 시작합니다.
5
WebSocket 테스트
Control UI에서 WebSocket 연결을 테스트합니다.
6
감사
openclaw security audit를 실행하고 발견 사항을 검토합니다.