Saltar al contenido principal

Autenticación de proxy de confianza

⚠️ Función sensible a la seguridad. Este modo delega la autenticación por completo a tu proxy inverso. Una configuración incorrecta puede exponer tu Gateway a accesos no autorizados. Lee esta página detenidamente antes de habilitarla.

Cuándo usarla

Usa el modo de autenticación trusted-proxy cuando:
  • Ejecutas OpenClaw detrás de un proxy con reconocimiento de identidad (Pomerium, Caddy + OAuth, nginx + oauth2-proxy, Traefik + forward auth)
  • Tu proxy gestiona toda la autenticación y pasa la identidad del usuario mediante encabezados
  • Estás en un entorno de Kubernetes o contenedores donde el proxy es la única ruta hacia el Gateway
  • Estás encontrando errores WebSocket 1008 unauthorized porque los navegadores no pueden pasar tokens en cargas útiles WS

Cuándo NO usarla

  • Si tu proxy no autentica usuarios (solo termina TLS o actúa como balanceador de carga)
  • Si existe cualquier ruta hacia el Gateway que omita el proxy (huecos en el firewall, acceso a la red interna)
  • Si no estás seguro de que tu proxy elimine/sobrescriba correctamente los encabezados reenviados
  • Si solo necesitas acceso personal de un único usuario (considera Tailscale Serve + loopback para una configuración más simple)

Cómo funciona

  1. Tu proxy inverso autentica a los usuarios (OAuth, OIDC, SAML, etc.)
  2. El proxy añade un encabezado con la identidad del usuario autenticado (por ejemplo, x-forwarded-user: nick@example.com)
  3. OpenClaw comprueba que la solicitud provino de una IP de proxy de confianza (configurada en gateway.trustedProxies)
  4. OpenClaw extrae la identidad del usuario del encabezado configurado
  5. Si todo es correcto, la solicitud se autoriza

Comportamiento de emparejamiento de la UI de Control

Cuando gateway.auth.mode = "trusted-proxy" está activo y la solicitud supera las comprobaciones de proxy de confianza, las sesiones WebSocket de la UI de Control pueden conectarse sin identidad de emparejamiento del dispositivo. Implicaciones:
  • El emparejamiento ya no es la barrera principal para el acceso a la UI de Control en este modo.
  • Tu política de autenticación del proxy inverso y allowUsers pasan a ser el control de acceso efectivo.
  • Mantén el ingreso al gateway restringido solo a las IP de proxy de confianza (gateway.trustedProxies + firewall).

Configuración

{
  gateway: {
    // La autenticación trusted-proxy espera solicitudes desde un origen de proxy de confianza no loopback
    bind: "lan",

    // CRÍTICO: Añade aquí solo la(s) IP(s) de tu proxy
    trustedProxies: ["10.0.0.1", "172.17.0.1"],

    auth: {
      mode: "trusted-proxy",
      trustedProxy: {
        // Encabezado que contiene la identidad del usuario autenticado (obligatorio)
        userHeader: "x-forwarded-user",

        // Opcional: encabezados que DEBEN estar presentes (verificación del proxy)
        requiredHeaders: ["x-forwarded-proto", "x-forwarded-host"],

        // Opcional: restringir a usuarios específicos (vacío = permitir a todos)
        allowUsers: ["nick@example.com", "admin@company.org"],
      },
    },
  },
}
Regla importante de runtime:
  • La autenticación de proxy de confianza rechaza solicitudes con origen loopback (127.0.0.1, ::1, CIDR de loopback).
  • Los proxies inversos loopback en el mismo host no satisfacen la autenticación de proxy de confianza.
  • Para configuraciones de proxy loopback en el mismo host, usa autenticación por token/contraseña en su lugar, o enruta mediante una dirección de proxy de confianza no loopback que OpenClaw pueda verificar.
  • Los despliegues de la UI de Control que no sean loopback siguen necesitando gateway.controlUi.allowedOrigins explícito.

Referencia de configuración

CampoObligatorioDescripción
gateway.trustedProxiesArreglo de direcciones IP de proxy en las que confiar. Se rechazan las solicitudes de otras IP.
gateway.auth.modeDebe ser "trusted-proxy"
gateway.auth.trustedProxy.userHeaderNombre del encabezado que contiene la identidad del usuario autenticado
gateway.auth.trustedProxy.requiredHeadersNoEncabezados adicionales que deben estar presentes para que la solicitud sea de confianza
gateway.auth.trustedProxy.allowUsersNoLista de permitidos de identidades de usuario. Vacío significa permitir a todos los usuarios autenticados.

Terminación TLS y HSTS

Usa un único punto de terminación TLS y aplica HSTS allí.

Patrón recomendado: terminación TLS en el proxy

Cuando tu proxy inverso gestiona HTTPS para https://control.example.com, establece Strict-Transport-Security en el proxy para ese dominio.
  • Buen ajuste para despliegues expuestos a Internet.
  • Mantiene el certificado + la política de endurecimiento HTTP en un solo lugar.
  • OpenClaw puede permanecer en HTTP loopback detrás del proxy.
Valor de ejemplo del encabezado:
Strict-Transport-Security: max-age=31536000; includeSubDomains

Terminación TLS en el Gateway

Si OpenClaw sirve HTTPS directamente (sin proxy que termine TLS), establece:
{
  gateway: {
    tls: { enabled: true },
    http: {
      securityHeaders: {
        strictTransportSecurity: "max-age=31536000; includeSubDomains",
      },
    },
  },
}
strictTransportSecurity acepta un valor de encabezado de tipo cadena, o false para deshabilitarlo explícitamente.

Guía de despliegue

  • Empieza primero con un max age corto (por ejemplo max-age=300) mientras validas el tráfico.
  • Auméntalo a valores de larga duración (por ejemplo max-age=31536000) solo cuando tengas alta confianza.
  • Añade includeSubDomains solo si todos los subdominios están listos para HTTPS.
  • Usa preload solo si cumples intencionadamente los requisitos de preload para todo tu conjunto de dominios.
  • El desarrollo local solo con loopback no se beneficia de HSTS.

Ejemplos de configuración de proxy

Pomerium

Pomerium pasa la identidad en x-pomerium-claim-email (u otros encabezados de claims) y un JWT en x-pomerium-jwt-assertion.
{
  gateway: {
    bind: "lan",
    trustedProxies: ["10.0.0.1"], // IP de Pomerium
    auth: {
      mode: "trusted-proxy",
      trustedProxy: {
        userHeader: "x-pomerium-claim-email",
        requiredHeaders: ["x-pomerium-jwt-assertion"],
      },
    },
  },
}
Fragmento de configuración de Pomerium:
routes:
  - from: https://openclaw.example.com
    to: http://openclaw-gateway:18789
    policy:
      - allow:
          or:
            - email:
                is: nick@example.com
    pass_identity_headers: true

Caddy con OAuth

Caddy con el plugin caddy-security puede autenticar usuarios y pasar encabezados de identidad.
{
  gateway: {
    bind: "lan",
    trustedProxies: ["10.0.0.1"], // IP del proxy Caddy/sidecar
    auth: {
      mode: "trusted-proxy",
      trustedProxy: {
        userHeader: "x-forwarded-user",
      },
    },
  },
}
Fragmento de 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 autentica usuarios y pasa la identidad en x-auth-request-email.
{
  gateway: {
    bind: "lan",
    trustedProxies: ["10.0.0.1"], // IP de nginx/oauth2-proxy
    auth: {
      mode: "trusted-proxy",
      trustedProxy: {
        userHeader: "x-auth-request-email",
      },
    },
  },
}
Fragmento de configuración de 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 con Forward Auth

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

Configuración mixta de token

OpenClaw rechaza configuraciones ambiguas en las que tanto gateway.auth.token (o OPENCLAW_GATEWAY_TOKEN) como el modo trusted-proxy están activos al mismo tiempo. Las configuraciones mixtas de token pueden hacer que las solicitudes loopback se autentiquen silenciosamente por la ruta de autenticación equivocada. Si ves un error mixed_trusted_proxy_token al iniciar:
  • Elimina el token compartido cuando uses el modo trusted-proxy, o
  • Cambia gateway.auth.mode a "token" si pretendes usar autenticación basada en token.
La autenticación de proxy de confianza en loopback también falla de forma cerrada: los llamantes en el mismo host deben proporcionar los encabezados de identidad configurados mediante un proxy de confianza en lugar de autenticarse silenciosamente.

Encabezado de ámbitos de operador

La autenticación de proxy de confianza es un modo HTTP portador de identidad, por lo que las llamadas pueden declarar opcionalmente ámbitos de operador con x-openclaw-scopes. Ejemplos:
  • x-openclaw-scopes: operator.read
  • x-openclaw-scopes: operator.read,operator.write
  • x-openclaw-scopes: operator.admin,operator.write
Comportamiento:
  • Cuando el encabezado está presente, OpenClaw respeta el conjunto de ámbitos declarado.
  • Cuando el encabezado está presente pero vacío, la solicitud declara ningún ámbito de operador.
  • Cuando el encabezado está ausente, las API HTTP normales portadoras de identidad recurren al conjunto predeterminado estándar de ámbitos de operador.
  • Las rutas HTTP de plugins autenticadas por gateway son más restringidas de forma predeterminada: cuando x-openclaw-scopes está ausente, su ámbito de runtime recurre a operator.write.
  • Las solicitudes HTTP originadas en el navegador todavía tienen que pasar gateway.controlUi.allowedOrigins (o el modo deliberado de respaldo de encabezado Host) incluso después de que la autenticación trusted-proxy tenga éxito.
Regla práctica:
  • Envía x-openclaw-scopes explícitamente cuando quieras que una solicitud trusted-proxy sea más restringida que los valores predeterminados, o cuando una ruta de plugin autenticada por gateway necesite algo más fuerte que el ámbito de escritura.

Lista de comprobación de seguridad

Antes de habilitar la autenticación de proxy de confianza, verifica:
  • El proxy es la única ruta: El puerto del Gateway está protegido por firewall frente a todo excepto tu proxy
  • trustedProxies es mínimo: Solo las IP reales de tu proxy, no subredes enteras
  • Sin origen de proxy loopback: la autenticación trusted-proxy falla de forma cerrada para solicitudes con origen loopback
  • El proxy elimina encabezados: Tu proxy sobrescribe (no añade) los encabezados x-forwarded-* procedentes de clientes
  • Terminación TLS: Tu proxy gestiona TLS; los usuarios se conectan por HTTPS
  • allowedOrigins es explícito: La UI de Control que no sea loopback usa gateway.controlUi.allowedOrigins explícito
  • allowUsers está establecido (recomendado): Restringe a usuarios conocidos en lugar de permitir a cualquiera que esté autenticado
  • Sin configuración mixta de token: No establezcas a la vez gateway.auth.token y gateway.auth.mode: "trusted-proxy"

Auditoría de seguridad

openclaw security audit marcará la autenticación trusted-proxy con un hallazgo de severidad critical. Esto es intencional: es un recordatorio de que estás delegando la seguridad a la configuración de tu proxy. La auditoría comprueba:
  • Advertencia/recordatorio crítico base de gateway.trusted_proxy_auth
  • Falta de configuración de trustedProxies
  • Falta de configuración de userHeader
  • allowUsers vacío (permite a cualquier usuario autenticado)
  • Política de origen del navegador comodín o ausente en superficies expuestas de la UI de Control

Solución de problemas

”trusted_proxy_untrusted_source”

La solicitud no provino de una IP en gateway.trustedProxies. Comprueba:
  • ¿La IP del proxy es correcta? (Las IP de contenedores Docker pueden cambiar)
  • ¿Hay un balanceador de carga delante de tu proxy?
  • Usa docker inspect o kubectl get pods -o wide para encontrar las IP reales

”trusted_proxy_loopback_source”

OpenClaw rechazó una solicitud trusted-proxy con origen loopback. Comprueba:
  • ¿Se está conectando el proxy desde 127.0.0.1 / ::1?
  • ¿Estás intentando usar autenticación trusted-proxy con un proxy inverso loopback en el mismo host?
Corrección:
  • Usa autenticación por token/contraseña para configuraciones de proxy loopback en el mismo host, o
  • Enruta mediante una dirección de proxy de confianza no loopback y mantén esa IP en gateway.trustedProxies.

”trusted_proxy_user_missing”

El encabezado de usuario estaba vacío o ausente. Comprueba:
  • ¿Tu proxy está configurado para pasar encabezados de identidad?
  • ¿El nombre del encabezado es correcto? (No distingue mayúsculas/minúsculas, pero la ortografía importa)
  • ¿El usuario está realmente autenticado en el proxy?

“trustedproxy_missing_header*”

Faltaba un encabezado obligatorio. Comprueba:
  • La configuración de tu proxy para esos encabezados específicos
  • Si los encabezados se están eliminando en algún punto de la cadena

”trusted_proxy_user_not_allowed”

El usuario está autenticado, pero no está en allowUsers. Añádelo o elimina la lista de permitidos.

”trusted_proxy_origin_not_allowed”

La autenticación trusted-proxy tuvo éxito, pero el encabezado Origin del navegador no superó las comprobaciones de origen de la UI de Control. Comprueba:
  • gateway.controlUi.allowedOrigins incluye el origen exacto del navegador
  • No estás usando orígenes comodín a menos que realmente quieras un comportamiento de permitir todo
  • Si usas intencionalmente el modo de respaldo de encabezado Host, gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true está establecido deliberadamente

El WebSocket sigue fallando

Asegúrate de que tu proxy:
  • Admite actualizaciones WebSocket (Upgrade: websocket, Connection: upgrade)
  • Pasa los encabezados de identidad en las solicitudes de actualización WebSocket (no solo en HTTP)
  • No tiene una ruta de autenticación separada para conexiones WebSocket

Migración desde autenticación por token

Si estás pasando de autenticación por token a trusted-proxy:
  1. Configura tu proxy para autenticar usuarios y pasar encabezados
  2. Prueba la configuración del proxy de forma independiente (curl con encabezados)
  3. Actualiza la configuración de OpenClaw con autenticación trusted-proxy
  4. Reinicia el Gateway
  5. Prueba las conexiones WebSocket desde la UI de Control
  6. Ejecuta openclaw security audit y revisa los hallazgos

Relacionado