Autenticación con proxy de confianza

Funcionalidad sensible para la seguridad. Este modo delega la autenticación completamente a tu proxy reverso. Una configuración incorrecta puede exponer tu Gateway a acceso no autorizado. Lee esta página detenidamente antes de habilitarlo.

Cuándo usarlo

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 maneja toda la autenticación y pasa la identidad del usuario vía headers
  • Estás en un entorno Kubernetes o de contenedores donde el proxy es el único camino al Gateway
  • Estás experimentando errores WebSocket 1008 unauthorized porque los navegadores no pueden pasar tokens en payloads WS

Cuándo NO usarlo

  • Si tu proxy no autentica usuarios (solo un terminador TLS o balanceador de carga)
  • Si existe algún camino al Gateway que omita el proxy (agujeros de firewall, acceso de red interna)
  • Si no estás seguro de que tu proxy quita/sobrescribe correctamente los headers de reenvío
  • Si solo necesitas acceso personal de un solo usuario (considera Tailscale Serve + loopback para una configuración más simple)

Cómo funciona

  1. Tu proxy reverso autentica a los usuarios (OAuth, OIDC, SAML, etc.)
  2. El proxy agrega un header con la identidad del usuario autenticado (ej., x-forwarded-user: [email protected])
  3. OpenClaw verifica que la solicitud provino de una IP de proxy de confianza (configurada en gateway.trustedProxies)
  4. OpenClaw extrae la identidad del usuario del header configurado
  5. Si todo coincide, la solicitud se autoriza

Comportamiento de emparejamiento en la UI de control

Cuando gateway.auth.mode = "trusted-proxy" está activo y la solicitud pasa las verificaciones de proxy de confianza, las sesiones WebSocket de la UI de control pueden conectarse sin identidad de emparejamiento de dispositivo.

Implicaciones:

  • El emparejamiento ya no es la compuerta principal para el acceso a la UI de control en este modo.
  • La política de autenticación de tu proxy reverso y allowUsers se convierten en el control de acceso efectivo.
  • Mantén el ingreso al gateway bloqueado solo a las IPs de proxy de confianza (gateway.trustedProxies + firewall).

Configuración

{
  gateway: {
    // Usa loopback para configuraciones de proxy en el mismo host; usa lan/custom para hosts de proxy remotos
    bind: "loopback",

    // FUNDAMENTAL: Solo agrega las IP(s) de tu proxy aquí
    trustedProxies: ["10.0.0.1", "172.17.0.1"],

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

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

        // Opcional: restringir a usuarios específicos (vacío = permitir todos)
        allowUsers: ["[email protected]", "[email protected]"],
      },
    },
  },
}

Si gateway.bind es loopback, incluye una dirección de proxy loopback en gateway.trustedProxies (127.0.0.1, ::1, o un CIDR loopback equivalente).

Referencia de configuración

CampoObligatorioDescripción
gateway.trustedProxiesArray de direcciones IP de proxy a confiar. Las solicitudes de otras IPs se rechazan.
gateway.auth.modeDebe ser "trusted-proxy"
gateway.auth.trustedProxy.userHeaderNombre del header que contiene la identidad del usuario autenticado
gateway.auth.trustedProxy.requiredHeadersNoHeaders adicionales que deben estar presentes para que la solicitud sea confiable
gateway.auth.trustedProxy.allowUsersNoLista de identidades de usuario permitidas. Vacío significa permitir todos los usuarios autenticados.

Terminación TLS y HSTS

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

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

Cuando tu proxy reverso maneja HTTPS para https://control.example.com, configura Strict-Transport-Security en el proxy para ese dominio.

  • Buena opción 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.

Ejemplo de valor del header:

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

Terminación TLS en el Gateway

Si OpenClaw mismo sirve HTTPS directamente (sin proxy que termine TLS), configura:

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

strictTransportSecurity acepta un valor de string de header, o false para deshabilitar explícitamente.

Guía de implementación

  • Comienza con un max age corto primero (por ejemplo max-age=300) mientras validas el tráfico.
  • Aumenta a valores de larga duración (por ejemplo max-age=31536000) solo después de tener confianza.
  • Agrega includeSubDomains solo si cada subdominio está listo para HTTPS.
  • Usa preload solo si cumples intencionalmente los requisitos de preload para todo tu conjunto de dominios.
  • El desarrollo local solo en loopback no se beneficia de HSTS.

Ejemplos de configuración de proxy

Pomerium

Pomerium pasa la identidad en x-pomerium-claim-email (u otros headers 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: [email protected]
    pass_identity_headers: true

Caddy con OAuth

Caddy con el plugin caddy-security puede autenticar usuarios y pasar headers de identidad.

{
  gateway: {
    bind: "lan",
    trustedProxies: ["127.0.0.1"], // IP de Caddy (si está en el mismo host)
    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 de Traefik
    auth: {
      mode: "trusted-proxy",
      trustedProxy: {
        userHeader: "x-forwarded-user",
      },
    },
  },
}

Lista de verificación de seguridad

Antes de habilitar la autenticación con proxy de confianza, verifica:

  • El proxy es el único camino: El puerto del Gateway está protegido por firewall de todo excepto tu proxy
  • trustedProxies es mínimo: Solo las IPs reales de tu proxy, no subredes completas
  • El proxy quita headers: Tu proxy sobrescribe (no agrega) los headers x-forwarded-* de los clientes
  • Terminación TLS: Tu proxy maneja TLS; los usuarios se conectan vía HTTPS
  • allowUsers está configurado (recomendado): Restringe a usuarios conocidos en lugar de permitir cualquier persona autenticada

Auditoría de seguridad

openclaw security audit marcará la autenticación con proxy de confianza con un hallazgo de severidad crítica. Esto es intencional: es un recordatorio de que estás delegando la seguridad a tu configuración de proxy.

La auditoría verifica:

  • Configuración de trustedProxies faltante
  • Configuración de userHeader faltante
  • allowUsers vacío (permite cualquier usuario autenticado)

Solución de problemas

”trusted_proxy_untrusted_source”

La solicitud no provino de una IP en gateway.trustedProxies. Verifica:

  • ¿La IP del proxy es correcta? (Las IPs de contenedores Docker pueden cambiar)
  • ¿Hay un balanceador de carga frente a tu proxy?
  • Usa docker inspect o kubectl get pods -o wide para encontrar las IPs reales

”trusted_proxy_user_missing”

El header del usuario estaba vacío o faltaba. Verifica:

  • ¿Tu proxy está configurado para pasar headers de identidad?
  • ¿El nombre del header es correcto? (insensible a mayúsculas, pero la ortografía importa)
  • ¿El usuario está realmente autenticado en el proxy?

“trustedproxy_missing_header*”

Un header requerido no estaba presente. Verifica:

  • Tu configuración del proxy para esos headers específicos
  • Si los headers se están quitando en algún punto de la cadena

”trusted_proxy_user_not_allowed”

El usuario está autenticado pero no está en allowUsers. Agrégalo o elimina la lista de permitidos.

WebSocket sigue fallando

Asegúrate de que tu proxy:

  • Soporta upgrades de WebSocket (Upgrade: websocket, Connection: upgrade)
  • Pasa los headers de identidad en las solicitudes de upgrade de 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 migrando de autenticación por token a proxy de confianza:

  1. Configura tu proxy para autenticar usuarios y pasar headers
  2. Prueba la configuración del proxy independientemente (curl con headers)
  3. Actualiza la configuración de OpenClaw con autenticación por proxy de confianza
  4. Reinicia el Gateway
  5. Prueba las conexiones WebSocket desde la UI de control
  6. Ejecuta openclaw security audit y revisa los hallazgos

Relacionado