Аутентификация через доверенный прокси
⚠️ Функция, критичная к безопасности. Этот режим полностью делегирует аутентификацию вашему обратному прокси. Неправильная настройка может открыть доступ к вашему Gateway для неавторизованных пользователей. Внимательно прочтите эту страницу перед включением.
Когда использовать
Используйте режим аутентификации trusted-proxy, когда:
- OpenClaw работает за идентифицирующим прокси (Pomerium, Caddy + OAuth, nginx + oauth2-proxy, Traefik + forward auth)
- Ваш прокси обрабатывает всю аутентификацию и передаёт идентификатор пользователя через заголовки
- Вы находитесь в среде Kubernetes или контейнеров, где прокси — единственный путь к Gateway
- Вы получаете ошибки WebSocket
1008 unauthorized, потому что браузеры не могут передавать токены в полезной нагрузке WS
Когда НЕ использовать
- Если ваш прокси не аутентифицирует пользователей (просто терминатор TLS или балансировщик нагрузки)
- Если существует любой путь к Gateway, обходящий прокси (дыры в брандмауэре, доступ из внутренней сети)
- Если вы не уверены, что ваш прокси правильно удаляет/перезаписывает пересылаемые заголовки
- Если вам нужен только личный доступ для одного пользователя (рассмотрите Tailscale Serve + loopback для более простой настройки)
Как это работает
- Ваш обратный прокси аутентифицирует пользователей (OAuth, OIDC, SAML и т.д.)
- Прокси добавляет заголовок с идентификатором аутентифицированного пользователя (например,
x-forwarded-user: nick@example.com) - OpenClaw проверяет, что запрос пришёл с доверенного IP-адреса прокси (настраивается в
gateway.trustedProxies) - OpenClaw извлекает идентификатор пользователя из настроенного заголовка
- Если все проверки пройдены, запрос авторизуется
Поведение сопряжения с Control UI
Когда активен gateway.auth.mode = "trusted-proxy" и запрос проходит проверки доверенного прокси, сессии WebSocket Control UI могут подключаться без идентификатора сопряжения устройства. Последствия:
- Сопряжение больше не является основным условием доступа к Control UI в этом режиме.
- Политика аутентификации вашего обратного прокси и
allowUsersстановятся эффективным контролем доступа. - Держите входящий трафик к gateway заблокированным только для IP-адресов доверенного прокси (
gateway.trustedProxies+ брандмауэр).
Конфигурация
{
gateway: {
// Используйте loopback для настройки прокси на том же хосте; используйте lan/custom для удалённых прокси-хостов
bind: "loopback",
// КРИТИЧЕСКИ ВАЖНО: Добавляйте сюда ТОЛЬКО IP-адрес(а) вашего прокси
trustedProxies: ["10.0.0.1", "172.17.0.1"],
auth: {
mode: "trusted-proxy",
trustedProxy: {
// Заголовок, содержащий идентификатор аутентифицированного пользователя (обязательно)
userHeader: "x-forwarded-user",
// Опционально: заголовки, которые ДОЛЖНЫ присутствовать (верификация прокси)
requiredHeaders: ["x-forwarded-proto", "x-forwarded-host"],
// Опционально: ограничить доступ определёнными пользователями (пусто = разрешить всем)
allowUsers: ["nick@example.com", "admin@company.org"],
},
},
},
}
Если gateway.bind имеет значение loopback, включите адрес loopback прокси в gateway.trustedProxies (127.0.0.1, ::1 или эквивалентный CIDR loopback).
Справочник по конфигурации
| Поле | Обязательно | Описание |
|---|---|---|
gateway.trustedProxies | Да | Массив доверенных IP-адресов прокси. Запросы с других IP-адресов отклоняются. |
gateway.auth.mode | Да | Должно быть "trusted-proxy" |
gateway.auth.trustedProxy.userHeader | Да | Имя заголовка, содержащего идентификатор аутентифицированного пользователя |
gateway.auth.trustedProxy.requiredHeaders | Нет | Дополнительные заголовки, которые должны присутствовать для доверия запросу |
gateway.auth.trustedProxy.allowUsers | Нет | Список разрешённых идентификаторов пользователей. Пусто означает разрешить всем аутентифицированным пользователям. |
Терминирование TLS и HSTS
Используйте одну точку терминирования TLS и применяйте HSTS там.
Рекомендуемый шаблон: терминирование TLS на прокси
Когда ваш обратный прокси обрабатывает HTTPS для https://control.example.com, установите Strict-Transport-Security на прокси для этого домена.
- Хорошо подходит для развёртываний, обращённых к интернету.
- Держит сертификат и политику усиления безопасности HTTP в одном месте.
- OpenClaw может оставаться на loopback HTTP за прокси.
Пример значения заголовка:
Strict-Transport-Security: max-age=31536000; includeSubDomains
Терминирование TLS на Gateway
Если OpenClaw сам обслуживает HTTPS напрямую (без прокси, терминалирующего TLS), установите:
{
gateway: {
tls: { enabled: true },
http: {
securityHeaders: {
strictTransportSecurity: "max-age=31536000; includeSubDomains",
},
},
},
}
strictTransportSecurity принимает строковое значение заголовка или false для явного отключения.
Рекомендации по внедрению
- Начните с короткого max age (например,
max-age=300) для проверки трафика. - Увеличьте до долгосрочных значений (например,
max-age=31536000) только после высокой уверенности. - Добавляйте
includeSubDomainsтолько если каждый поддомен готов к HTTPS. - Используйте preload только если вы намеренно соответствуете требованиям preload для всего набора ваших доменов.
- Локальная разработка только на loopback не получает выгоды от HSTS.
Примеры настройки прокси
Pomerium
Pomerium передаёт идентификатор в x-pomerium-claim-email (или других claim-заголовках) и JWT в x-pomerium-jwt-assertion.
{
gateway: {
bind: "lan",
trustedProxies: ["10.0.0.1"], // IP-адрес Pomerium
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: nick@example.com
pass_identity_headers: true
Caddy с OAuth
Caddy с плагином caddy-security может аутентифицировать пользователей и передавать заголовки с идентификатором.
{
gateway: {
bind: "lan",
trustedProxies: ["127.0.0.1"], // IP-адрес Caddy (если на том же хосте)
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.
{
gateway: {
bind: "lan",
trustedProxies: ["10.0.0.1"], // IP-адрес nginx/oauth2-proxy
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"], // IP-адрес контейнера Traefik
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-forwarded-user",
},
},
},
}
Контрольный список безопасности
Перед включением аутентификации trusted-proxy убедитесь:
- Прокси — единственный путь: Порт Gateway защищён брандмауэром от всего, кроме вашего прокси
- trustedProxies минимален: Только реальные IP-адреса вашего прокси, а не целые подсети
- Прокси удаляет заголовки: Ваш прокси перезаписывает (а не добавляет) заголовки
x-forwarded-*от клиентов - Терминирование TLS: Ваш прокси обрабатывает TLS; пользователи подключаются по HTTPS
- allowUsers задан (рекомендуется): Ограничьте доступ известными пользователями, а не разрешайте всем аутентифицированным
Проверка безопасности
openclaw security audit отметит аутентификацию trusted-proxy как критическую (critical) проблему. Это сделано намеренно — это напоминание о том, что вы делегируете безопасность вашей настройке прокси. Проверка контролирует:
- Отсутствующую конфигурацию
trustedProxies - Отсутствующую конфигурацию
userHeader - Пустой
allowUsers(разрешает любого аутентифицированного пользователя)
Устранение неполадок
”trusted_proxy_untrusted_source”
Запрос пришёл не с IP-адреса из gateway.trustedProxies. Проверьте:
- Правильный ли IP-адрес прокси? (IP-адреса контейнеров Docker могут меняться)
- Есть ли балансировщик нагрузки перед вашим прокси?
- Используйте
docker inspectилиkubectl get pods -o wide, чтобы найти реальные IP-адреса
”trusted_proxy_user_missing”
Заголовок пользователя был пуст или отсутствовал. Проверьте:
- Настроен ли ваш прокси на передачу заголовков с идентификатором?
- Правильное ли имя заголовка? (регистр не важен, но написание имеет значение)
- Пользователь действительно аутентифицирован на прокси?
“trustedproxy_missing_header*”
Обязательный заголовок отсутствовал. Проверьте:
- Конфигурацию вашего прокси на наличие этих конкретных заголовков
- Удаляются ли заголовки где-то в цепочке
”trusted_proxy_user_not_allowed”
Пользователь аутентифицирован, но не входит в allowUsers. Либо добавьте его, либо удалите список разрешений.
WebSocket всё ещё не работает
Убедитесь, что ваш прокси:
- Поддерживает обновление до WebSocket (
Upgrade: websocket,Connection: upgrade) - Передаёт заголовки с идентификатором на запросы обновления WebSocket (а не только на HTTP)
- Не имеет отдельного пути аутентификации для соединений WebSocket
Миграция с токенной аутентификации
Если вы переходите с токенной аутентификации на trusted-proxy:
- Настройте ваш прокси на аутентификацию пользователей и передачу заголовков
- Протестируйте настройку прокси независимо (curl с заголовками)
- Обновите конфигурацию OpenClaw на аутентификацию trusted-proxy
- Перезапустите Gateway
- Протестируйте соединения WebSocket из Control UI
- Запустите
openclaw security auditи просмотрите результаты
Связанные темы
- Безопасность — полное руководство по безопасности
- Конфигурация — справочник по конфигурации
- Удалённый доступ — другие модели удалённого доступа
- Tailscale — более простая альтернатива для доступа только внутри tailnet