Aller au contenu

Authentification par proxy de confiance

Utilisez le mode d’auth trusted-proxy lorsque :

  • Vous exécutez OpenClaw derrière un proxy conscient de l’identité (Pomerium, Caddy + OAuth, nginx + oauth2-proxy, Traefik + authentification forward).
  • Votre proxy gère toute l’authentification et transmet l’identité de l’utilisateur via des en-têtes.
  • Vous êtes dans un environnement Kubernetes ou conteneurisé où le proxy est le seul chemin d’accès au Gateway.
  • Vous rencontrez des erreurs WebSocket 1008 unauthorized car les navigateurs ne peuvent pas transmettre de jetons dans les charges utiles WS.
  • Si votre proxy n’authentifie pas les utilisateurs (simplement un terminateur TLS ou un équilibreur de charge).
  • S’il existe un chemin vers le Gateway qui contourne le proxy (trous dans le pare-feu, accès au réseau interne).
  • Si vous n’êtes pas sûr que votre proxy supprime/écrase correctement les en-têtes transférés.
  • Si vous avez uniquement besoin d’un accès personnel mono-utilisateur (envisagez Tailscale Serve + boucle locale pour une configuration plus simple).
  1. Le proxy authentifie l'utilisateur

    Votre proxy inverse authentifie les utilisateurs (OAuth, OIDC, SAML, etc.).

  2. Le proxy ajoute un en-tête d'identité

    Le proxy ajoute un en-tête avec l’identité de l’utilisateur authentifié (par exemple, x-forwarded-user: [email protected]).

  3. Gateway vérifie la source approuvée

    OpenClaw vérifie que la requête provient d’une IP de proxy approuvée (configurée dans gateway.trustedProxies).

  4. La passerelle extrait l'identité

    Gateway extrait l’identité de l’utilisateur de l’en-tête configuré.

  5. Autoriser

    Si tout est vérifié, la demande est autorisée.

Contrôler le comportement de l’appairage de l’interface de contrôle

Section intitulée « Contrôler le comportement de l’appairage de l’interface de contrôle »

Lorsque gateway.auth.mode = "trusted-proxy" est actif et que la requête passe les vérifications du proxy approuvé, les sessions WebSocket de l’interface de contrôle peuvent se connecter sans identité d’appareil associée.

Implications :

  • L’appairage n’est plus la porte principale pour l’accès à l’interface de contrôle dans ce mode.
  • Votre stratégie d’authentification de proxy inverse et allowUsers deviennent le contrôle d’accès effectif.
  • Maintenez l’entrée de la Gateway verrouillée uniquement aux adresses IP de proxy approuvées (gateway.trustedProxies + pare-feu).
{
gateway: {
// Trusted-proxy auth expects requests from a non-loopback trusted proxy source by default
bind: "lan",
// CRITICAL: Only add your proxy's IP(s) here
trustedProxies: ["10.0.0.1", "172.17.0.1"],
auth: {
mode: "trusted-proxy",
trustedProxy: {
// Header containing authenticated user identity (required)
userHeader: "x-forwarded-user",
// Optional: headers that MUST be present (proxy verification)
requiredHeaders: ["x-forwarded-proto", "x-forwarded-host"],
// Optional: restrict to specific users (empty = allow all)
// Optional: allow a same-host loopback proxy after explicit opt-in
allowLoopback: false,
},
},
},
}
Tableau d'adresses IP de proxy à faire confiance. Les requêtes provenant d'autres adresses IP sont rejetées. Doit être `"trusted-proxy"`. Nom de l'en-tête contenant l'identité de l'utilisateur authentifié. En-têtes supplémentaires qui doivent être présents pour que la requête soit approuvée. Liste blanche des identités des utilisateurs. Vide signifie autoriser tous les utilisateurs authentifiés. Support opt-in pour les proxies inversés de bouclage sur le même hôte. La valeur par défaut est `false`.

Utilisez un seul point de terminaison TLS et appliquez HSTS à cet endroit.

Lorsque votre proxy inverse gère le HTTPS pour https://control.example.com, définissez Strict-Transport-Security au niveau du proxy pour ce domaine.

  • Convient bien aux déploiements accessibles sur Internet.
  • Garde le certificat + la politique de durcissement HTTP au même endroit.
  • OpenClaw peut rester sur HTTP de bouclage derrière le proxy.

Exemple de valeur d’en-tête :

Strict-Transport-Security: max-age=31536000; includeSubDomains
  • Commencez par une durée max-age courte (par exemple max-age=300) lors de la validation du trafic.
  • Augmentez vers des valeurs de longue durée (par exemple max-age=31536000) uniquement lorsque vous êtes pleinement confiant.
  • Ajoutez includeSubDomains uniquement si chaque sous-domaine est prêt pour HTTPS.
  • Utilisez le préchargement (preload) uniquement si vous répondez sciemment aux exigences de préchargement pour l’ensemble de vos domaines.
  • Le développement local en boucle locale (loopback-only) ne bénéficie pas de HSTS.
Pomerium

Pomerium transmet l’identité dans x-pomerium-claim-email (ou d’autres en-têtes de revendication) et un JWT dans x-pomerium-jwt-assertion.

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

Extrait de configuration Pomerium :

routes:
- from: https://openclaw.example.com
to: http://openclaw-gateway:18789
policy:
- allow:
or:
- email:
pass_identity_headers: true
Caddy avec OAuth

Caddy avec le plugin caddy-security peut authentifier les utilisateurs et transmettre les en-têtes d’identité.

{
gateway: {
bind: "lan",
trustedProxies: ["10.0.0.1"], // Caddy/sidecar proxy IP
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-forwarded-user",
},
},
},
}

Extrait 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 authentifie les utilisateurs et transmet l’identité dans x-auth-request-email.

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

Extrait de configuration 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 avec authentification forward
{
gateway: {
bind: "lan",
trustedProxies: ["172.17.0.1"], // Traefik container IP
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-forwarded-user",
},
},
},
}

OpenClaw rejette les configurations ambiguës où un gateway.auth.token (ou OPENCLAW_GATEWAY_TOKEN) et un mode trusted-proxy sont actifs simultanément. Les configurations de jetons mixtes peuvent provoquer une authentification silencieuse des requêtes en boucle locale sur le mauvais chemin d’authentification.

Si vous voyez une erreur mixed_trusted_proxy_token au démarrage :

  • Supprimez le jeton partagé lors de l’utilisation du mode trusted-proxy, ou
  • Basculez gateway.auth.mode sur "token" si vous prévoyez une authentification par jeton.

Les en-têtes d’identité trusted-proxy en boucle locale échouent toujours en mode fermé : les appelants same-host ne sont pas authentifiés silencieusement en tant qu’utilisateurs proxy. Les appelants internes OpenClaw qui contournent le proxy peuvent plutôt s’authentifier avec gateway.auth.password / OPENCLAW_GATEWAY_PASSWORD. Le repli sur jeton reste intentionnellement non pris en charge en mode trusted-proxy.

L’authentification trusted-proxy est un mode HTTP porteur d’identité, les appelants peuvent donc déclarer facultativement des étendues d’opérateur avec x-openclaw-scopes.

Exemples :

  • x-openclaw-scopes: operator.read
  • x-openclaw-scopes: operator.read,operator.write
  • x-openclaw-scopes: operator.admin,operator.write

Comportement :

  • Lorsque l’en-tête est présent, OpenClaw respecte l’ensemble des étendues déclarées.
  • Lorsque l’en-tête est présent mais vide, la requête ne déclare aucune étendue d’opérateur.
  • Lorsque l’en-tête est absent, les API HTTP standard porteuses d’identité reviennent à l’ensemble d’étendues par défaut standard de l’opérateur.
  • Les routes HTTP de plugin d’authentification Gateway sont plus restrictives par défaut : lorsque x-openclaw-scopes est absent, leur étendue d’exécution revient à operator.write.
  • Les requêtes HTTP d’origine navigateur doivent toujours réussir gateway.controlUi.allowedOrigins (ou le mode de repli délibéré sur l’en-tête Host) même après la réussite de l’authentification trusted-proxy.

Règle pratique : envoyez x-openclaw-scopes explicitement lorsque vous souhaitez qu’une requête trusted-proxy soit plus restrictive que les valeurs par défaut, ou lorsqu’une route de plugin d’authentification gateway nécessite une étendue plus forte que l’écriture.

Avant d’activer l’authentification trusted-proxy, vérifiez :

  • Le proxy est le seul chemin : Le port Gateway est protégé par un pare-feu contre tout sauf votre proxy.
  • trustedProxies est minimal : Uniquement vos IP de proxy réelles, et non des sous-réseaux entiers.
  • La source du proxy en boucle est délibérée : l’authentification trusted-proxy échoue en mode fermé pour les requêtes provenant de la boucle locale, sauf si gateway.auth.trustedProxy.allowLoopback est explicitement activé pour un proxy same-host.
  • Le proxy supprime les en-têtes : Votre proxy remplace (n’ajoute pas) les en-têtes x-forwarded-* des clients.
  • Terminaison TLS : Votre proxy gère le TLS ; les utilisateurs se connectent via HTTPS.
  • allowedOrigins est explicite : L’interface de contrôle non-bouclage utilise un gateway.controlUi.allowedOrigins explicite.
  • allowUsers est défini (recommandé) : Limitez aux utilisateurs connus plutôt que d’autoriser toute personne authentifiée.
  • Pas de configuration mixte de jetons : Ne définissez pas à la fois gateway.auth.token et gateway.auth.mode: "trusted-proxy".
  • Le repli de mot de passe local est privé : Si vous configurez gateway.auth.password pour les appelants directs internes, gardez le port du Gateway protégé par un pare-feu afin que les clients distants non-proxy ne puissent pas l’atteindre directement.

openclaw security audit signalera l’authentification proxy de confiance avec un constat de sévérité critique. C’est intentionnel — c’est un rappel que vous déléguez la sécurité à votre configuration de proxy.

L’audit vérifie :

  • Rappel d’avertissement/critique de base gateway.trusted_proxy_auth
  • Configuration trustedProxies manquante
  • Configuration userHeader manquante
  • allowUsers vide (autorise tout utilisateur authentifié)
  • allowLoopback activé pour les sources proxy sur le même hôte
  • Stratégie d’origine navigateur générique ou manquante sur les surfaces exposées de l’interface de contrôle
trusted_proxy_untrusted_source

La requête ne provenait pas d’une adresse IP de gateway.trustedProxies. Vérifiez :

  • L’adresse IP du proxy est-elle correcte ? (Les IP des conteneurs Docker peuvent changer.)
  • Y a-t-il un équilibreur de charge devant votre proxy ?
  • Utilisez docker inspect ou kubectl get pods -o wide pour trouver les adresses IP réelles.
trusted_proxy_loopback_source

OpenClaw a rejeté une demande de proxy de confiance source de bouclage.

Vérifiez :

  • Le proxy se connecte-t-il à partir de 127.0.0.1 / ::1 ?
  • Essayez-vous d’utiliser l’authentification par proxy de confiance avec un proxy inverse de bouclage sur le même hôte ?

Solution :

  • Privilégiez l’authentification par jeton/mot de passe pour les clients internes sur le même hôte qui ne passent pas par le proxy, ou
  • Acheminez via une adresse de proxy de confiance non bouclage et conservez cette adresse IP dans gateway.trustedProxies, ou
  • Pour un proxy inverse délibéré sur le même hôte, définissez gateway.auth.trustedProxy.allowLoopback = true, conservez l’adresse de bouclage dans gateway.trustedProxies et assurez-vous que le proxy supprime ou écrase les en-têtes d’identité.
trusted_proxy_user_missing

L’en-tête utilisateur était vide ou manquant. Vérifiez :

  • Votre proxy est-il configuré pour transmettre les en-têtes d’identité ?
  • Le nom de l’en-tête est-il correct ? (insensible à la casse, mais l’orthographe compte)
  • L’utilisateur est-il réellement authentifié au niveau du proxy ?
trusted_proxy_missing_header_*

Un en-tête requis n’était pas présent. Vérifiez :

  • Votre configuration de proxy pour ces en-têtes spécifiques.
  • Si les en-têtes sont supprimés quelque part dans la chaîne.
trusted_proxy_user_not_allowed

L’utilisateur est authentifié mais n’est pas dans allowUsers. Ajoutez-le ou supprimez la liste d’autorisation.

trusted_proxy_origin_not_allowed

L’authentification par proxy de confiance a réussi, mais l’en-tête Origin du navigateur n’a pas passé les contrôles d’origine de l’interface de contrôle.

Vérifiez :

  • gateway.controlUi.allowedOrigins inclut l’origine exacte du navigateur.
  • Vous ne vous fiez pas aux origines génériques, sauf si vous souhaitez intentionnellement un comportement de tout autoriser.
  • Si vous utilisez intentionnellement le mode de repli d’en-tête Host, gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true est défini délibérément.
Échec persistant de WebSocket

Assurez-vous que votre proxy :

  • Prend en charge les mises à niveau WebSocket (Upgrade: websocket, Connection: upgrade).
  • Transmet les en-têtes d’identité lors des demandes de mise à niveau WebSocket (et pas seulement HTTP).
  • N’a pas de chemin d’authentification distinct pour les connexions WebSocket.

Si vous passez de l’authentification par jeton à trusted-proxy :

  1. Configurer le proxy

    Configurez votre proxy pour authentifier les utilisateurs et transmettre les en-têtes.

  2. Tester le proxy indépendamment

    Testez la configuration du proxy indépendamment (curl avec en-têtes).

  3. Mettre à jour la config OpenClaw

    Mettez à jour la config OpenClaw avec l’authentification trusted-proxy.

  4. Redémarrer le Gateway

    Redémarrez le Gateway.

  5. Tester WebSocket

    Testez les connexions WebSocket depuis l’interface de contrôle.

  6. Audit

    Exécutez openclaw security audit et examinez les résultats.