신뢰할 수 있는 프록시 인증

⚠️ 보안에 민감한 기능입니다. 이 모드는 인증을 완전히 리버스 프록시에 위임합니다. 잘못된 설정은 게이트웨이를 무단 접근에 노출시킬 수 있습니다. 활성화하기 전에 이 페이지를 주의 깊게 읽으세요.

사용 시기

다음과 같은 경우에 trusted-proxy 인증 모드를 사용하세요:

  • ID 인식 프록시 (Pomerium, Caddy + OAuth, nginx + oauth2-proxy, Traefik + forward auth) 뒤에서 OpenClaw를 실행하는 경우
  • 프록시가 모든 인증을 처리하고 헤더를 통해 사용자 ID를 전달하는 경우
  • Kubernetes 또는 컨테이너 환경에서 프록시가 게이트웨이에 대한 유일한 경로인 경우
  • 브라우저가 WS 페이로드에 토큰을 전달할 수 없어서 WebSocket 1008 unauthorized 오류가 발생하는 경우

사용하지 말아야 할 경우

  • 프록시가 사용자를 인증하지 않는 경우 (단순 TLS 종단자 또는 로드 밸런서)
  • 프록시를 우회하여 게이트웨이에 도달하는 경로가 있는 경우 (방화벽 홀, 내부 네트워크 접근)
  • 프록시가 포워딩 헤더를 올바르게 제거/덮어쓰는지 확실하지 않은 경우
  • 개인 단일 사용자 접근만 필요한 경우 (더 간단한 설정을 위해 Tailscale Serve + 루프백을 고려하세요)

작동 방식

  1. 리버스 프록시가 사용자를 인증합니다 (OAuth, OIDC, SAML 등).
  2. 프록시가 인증된 사용자 ID를 헤더에 추가합니다 (예: x-forwarded-user: [email protected]).
  3. OpenClaw가 요청이 신뢰할 수 있는 프록시 IP (gateway.trustedProxies에 설정)에서 왔는지 확인합니다.
  4. OpenClaw가 설정된 헤더에서 사용자 ID를 추출합니다.
  5. 모든 확인이 통과하면 요청이 승인됩니다.

Control UI 페어링 동작

gateway.auth.mode = "trusted-proxy"가 활성이고 요청이 신뢰할 수 있는 프록시 확인을 통과하면, Control UI WebSocket 세션은 디바이스 페어링 ID 없이 연결할 수 있습니다.

영향:

  • 이 모드에서는 페어링이 Control UI 접근의 주요 게이트가 아닙니다.
  • 리버스 프록시 인증 정책과 allowUsers가 실질적인 접근 제어가 됩니다.
  • 게이트웨이 인그레스를 신뢰할 수 있는 프록시 IP로만 제한하세요 (gateway.trustedProxies + 방화벽).

설정

{
  gateway: {
    // 동일 호스트 프록시 설정에는 loopback 사용; 원격 프록시 호스트에는 lan/custom 사용
    bind: "loopback",

    // 중요: 프록시의 IP만 여기에 추가
    trustedProxies: ["10.0.0.1", "172.17.0.1"],

    auth: {
      mode: "trusted-proxy",
      trustedProxy: {
        // 인증된 사용자 ID를 포함하는 헤더 (필수)
        userHeader: "x-forwarded-user",

        // 선택: 반드시 존재해야 하는 헤더 (프록시 확인)
        requiredHeaders: ["x-forwarded-proto", "x-forwarded-host"],

        // 선택: 특정 사용자로 제한 (비어 있으면 모두 허용)
        allowUsers: ["[email protected]", "[email protected]"],
      },
    },
  },
}

gateway.bindloopback이면, gateway.trustedProxies에 루프백 프록시 주소를 포함하세요 (127.0.0.1, ::1, 또는 동등한 루프백 CIDR).

설정 참고

필드필수설명
gateway.trustedProxies신뢰할 프록시 IP 주소 배열. 다른 IP의 요청은 거부됩니다.
gateway.auth.mode"trusted-proxy"여야 합니다
gateway.auth.trustedProxy.userHeader인증된 사용자 ID를 포함하는 헤더 이름
gateway.auth.trustedProxy.requiredHeaders아니오요청이 신뢰되기 위해 반드시 존재해야 하는 추가 헤더
gateway.auth.trustedProxy.allowUsers아니오사용자 ID 허용 목록. 비어 있으면 인증된 모든 사용자를 허용합니다.

TLS 종단 및 HSTS

하나의 TLS 종단 지점을 사용하고 거기에 HSTS를 적용하세요.

권장 패턴: 프록시 TLS 종단

리버스 프록시가 https://control.example.com에 대해 HTTPS를 처리할 때, 해당 도메인에 대해 프록시에서 Strict-Transport-Security를 설정하세요.

  • 인터넷 공개 배포에 적합.
  • 인증서 + HTTP 보안 정책을 한 곳에 유지.
  • OpenClaw는 프록시 뒤에서 루프백 HTTP로 유지 가능.

헤더 값 예시:

Strict-Transport-Security: max-age=31536000; includeSubDomains

게이트웨이 TLS 종단

OpenClaw 자체가 직접 HTTPS를 제공하는 경우 (TLS 종단 프록시 없음), 다음을 설정하세요:

{
  gateway: {
    tls: { enabled: true },
    http: {
      securityHeaders: {
        strictTransportSecurity: "max-age=31536000; includeSubDomains",
      },
    },
  },
}

strictTransportSecurity는 문자열 헤더 값을 받거나, 명시적으로 비활성화하려면 false를 받습니다.

배포 가이드

  • 트래픽을 검증하는 동안 먼저 짧은 max age로 시작하세요 (예: max-age=300).
  • 신뢰도가 높아진 후에만 장기 값으로 늘리세요 (예: max-age=31536000).
  • 모든 서브도메인이 HTTPS를 사용할 준비가 된 경우에만 includeSubDomains를 추가하세요.
  • 전체 도메인 세트에 대한 preload 요구사항을 의도적으로 충족하는 경우에만 preload를 사용하세요.
  • 루프백 전용 로컬 개발에서는 HSTS가 도움이 되지 않습니다.

프록시 설정 예시

Pomerium

Pomerium은 x-pomerium-claim-email (또는 다른 claim 헤더)에 ID를 전달하고, x-pomerium-jwt-assertion에 JWT를 전달합니다.

{
  gateway: {
    bind: "lan",
    trustedProxies: ["10.0.0.1"], // Pomerium IP
    auth: {
      mode: "trusted-proxy",
      trustedProxy: {
        userHeader: "x-pomerium-claim-email",
        requiredHeaders: ["x-pomerium-jwt-assertion"],
      },
    },
  },
}

Pomerium 설정 스니펫:

routes:
  - from: https://openclaw.example.com
    to: http://openclaw-gateway:18789
    policy:
      - allow:
          or:
            - email:
                is: [email protected]
    pass_identity_headers: true

Caddy + OAuth

Caddy에 caddy-security 플러그인을 사용하면 사용자를 인증하고 ID 헤더를 전달할 수 있습니다.

{
  gateway: {
    bind: "lan",
    trustedProxies: ["127.0.0.1"], // Caddy IP (동일 호스트인 경우)
    auth: {
      mode: "trusted-proxy",
      trustedProxy: {
        userHeader: "x-forwarded-user",
      },
    },
  },
}

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가 사용자를 인증하고 x-auth-request-email에 ID를 전달합니다.

{
  gateway: {
    bind: "lan",
    trustedProxies: ["10.0.0.1"], // nginx/oauth2-proxy IP
    auth: {
      mode: "trusted-proxy",
      trustedProxy: {
        userHeader: "x-auth-request-email",
      },
    },
  },
}

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 + Forward Auth

{
  gateway: {
    bind: "lan",
    trustedProxies: ["172.17.0.1"], // Traefik 컨테이너 IP
    auth: {
      mode: "trusted-proxy",
      trustedProxy: {
        userHeader: "x-forwarded-user",
      },
    },
  },
}

보안 체크리스트

신뢰할 수 있는 프록시 인증을 활성화하기 전에 확인하세요:

  • 프록시가 유일한 경로: 게이트웨이 포트가 프록시를 제외한 모든 것으로부터 방화벽으로 보호됨
  • trustedProxies가 최소: 서브넷 전체가 아닌 실제 프록시 IP만 포함
  • 프록시가 헤더를 제거: 프록시가 클라이언트의 x-forwarded-* 헤더를 추가가 아닌 덮어쓰기
  • TLS 종단: 프록시가 TLS를 처리하고 사용자는 HTTPS로 연결
  • allowUsers 설정 (권장): 인증된 모든 사용자를 허용하지 않고 알려진 사용자로 제한

보안 감사

openclaw security audit는 신뢰할 수 있는 프록시 인증에 대해 critical 심각도 발견을 표시합니다. 이는 의도적이며, 프록시 설정에 보안을 위임하고 있다는 알림입니다.

감사가 확인하는 사항:

  • 누락된 trustedProxies 설정
  • 누락된 userHeader 설정
  • 비어 있는 allowUsers (인증된 모든 사용자 허용)

문제 해결

”trusted_proxy_untrusted_source”

요청이 gateway.trustedProxies의 IP에서 오지 않았습니다. 확인 사항:

  • 프록시 IP가 맞는지? (Docker 컨테이너 IP는 변경될 수 있음)
  • 프록시 앞에 로드 밸런서가 있는지?
  • docker inspect 또는 kubectl get pods -o wide로 실제 IP 확인

”trusted_proxy_user_missing”

사용자 헤더가 비어 있거나 없습니다. 확인 사항:

  • 프록시가 ID 헤더를 전달하도록 설정되어 있는지?
  • 헤더 이름이 맞는지? (대소문자 무관, 하지만 철자가 중요)
  • 사용자가 실제로 프록시에서 인증되었는지?

“trustedproxy_missing_header*”

필수 헤더가 존재하지 않습니다. 확인 사항:

  • 해당 특정 헤더에 대한 프록시 설정
  • 체인 어딘가에서 헤더가 제거되고 있는지

”trusted_proxy_user_not_allowed”

사용자가 인증되었지만 allowUsers에 없습니다. 추가하거나 허용 목록을 제거하세요.

WebSocket이 여전히 실패하는 경우

프록시가 다음을 충족하는지 확인하세요:

  • WebSocket 업그레이드 지원 (Upgrade: websocket, Connection: upgrade)
  • WebSocket 업그레이드 요청에서도 ID 헤더를 전달 (HTTP만이 아님)
  • WebSocket 연결에 대한 별도 인증 경로가 없는지

토큰 인증에서 마이그레이션

토큰 인증에서 신뢰할 수 있는 프록시로 전환하는 경우:

  1. 프록시가 사용자를 인증하고 헤더를 전달하도록 설정
  2. 프록시 설정을 독립적으로 테스트 (헤더와 함께 curl)
  3. OpenClaw 설정에 신뢰할 수 있는 프록시 인증 업데이트
  4. 게이트웨이 재시작
  5. Control UI에서 WebSocket 연결 테스트
  6. openclaw security audit 실행 후 발견 사항 검토

관련 문서

  • 보안 — 전체 보안 가이드
  • 설정 — 설정 참고
  • 원격 접근 — 다른 원격 접근 패턴
  • Tailscale — Tailnet 전용 접근을 위한 더 간단한 대안