Gateway
مصادقة الوكيل الموثوق
متى يُستخدم
- تشغّل OpenClaw خلف وكيل مدرك للهوية (Pomerium، أو Caddy + OAuth، أو nginx + oauth2-proxy، أو Traefik + مصادقة مُمرّرة).
- يتولى وكيلك جميع عمليات المصادقة ويمرر هوية المستخدم عبر الترويسات.
- تعمل في بيئة Kubernetes أو حاويات يكون فيها الوكيل هو المسار الوحيد إلى Gateway.
- تواجه أخطاء WebSocket من نوع
1008 unauthorizedلأن المتصفحات لا تستطيع تمرير الرموز المميزة في حمولات WS.
متى يجب عدم استخدامه
- لا يصادق وكيلك المستخدمين (بل يعمل فقط كنقطة إنهاء TLS أو موازن حمل).
- يوجد أي مسار إلى Gateway يتجاوز الوكيل (ثغرات في جدار الحماية أو وصول عبر الشبكة الداخلية).
- لست متأكدًا مما إذا كان وكيلك يزيل الترويسات المُمرّرة أو يستبدلها بشكل صحيح.
- لا تحتاج إلا إلى وصول شخصي لمستخدم واحد (فكّر في استخدام Tailscale Serve + local loopback بدلًا من ذلك).
آلية العمل
يصادق الوكيل المستخدم
يصادق الوكيل العكسي المستخدمين (OAuth أو OIDC أو SAML، وما إلى ذلك).
يضيف الوكيل ترويسة هوية
يضيف الوكيل ترويسة تحتوي على هوية المستخدم المصادَق عليه (مثل x-forwarded-user: nick@example.com).
يتحقق Gateway من المصدر الموثوق
يتحقق OpenClaw من أن الطلب أتى من عنوان IP لوكيل موثوق (gateway.trustedProxies) وأنه ليس عنوان local loopback الخاص بـ Gateway أو عنوان واجهته المحلية.
يستخرج Gateway الهوية
يقرأ OpenClaw الترويسات المطلوبة، ثم يقرأ هوية المستخدم من الترويسة المُعدّة.
التخويل
إذا اجتازت جميع عمليات التحقق، واجتاز المستخدم allowUsers (عند تعيينها)، يُخوَّل الطلب.
الإعداد
{ gateway: { // Trusted-proxy auth expects the proxy's source IP to be non-loopback 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) allowUsers: ["nick@example.com", "admin@company.org"], // Optional: allow a same-host loopback proxy after explicit opt-in allowLoopback: false, }, }, },}مرجع الإعداد
gateway.trustedProxiesstring[]requiredمصفوفة بعناوين IP للوكلاء (أو نطاقات CIDR) المطلوب الوثوق بها. تُرفض الطلبات الواردة من عناوين IP أخرى.
gateway.auth.modestringrequiredيجب أن تكون "trusted-proxy".
gateway.auth.trustedProxy.userHeaderstringrequiredاسم الترويسة التي تحتوي على هوية المستخدم المصادَق عليه.
gateway.auth.trustedProxy.requiredHeadersstring[]ترويسات إضافية يجب أن تكون موجودة لكي يُعد الطلب موثوقًا.
gateway.auth.trustedProxy.allowUsersstring[]قائمة سماح بهويات المستخدمين. تعني القيمة الفارغة السماح لجميع المستخدمين المصادَق عليهم.
gateway.auth.trustedProxy.allowLoopbackbooleandefault: falseدعم اختياري للوكلاء العكسيين العاملين عبر local loopback على المضيف نفسه.
سلوك إقران واجهة التحكم
عندما يكون gateway.auth.mode = "trusted-proxy" نشطًا ويجتاز الطلب عمليات تحقق الوكيل الموثوق، يمكن لجلسات WebSocket الخاصة بواجهة التحكم الاتصال دون هوية إقران الجهاز.
الآثار المتعلقة بالنطاق:
- تتصل جلسات WebSocket الخاصة بواجهة التحكم التي لا ترتبط بجهاز، لكنها لا تتلقى افتراضيًا أي نطاقات للمشغّل. يمسح OpenClaw قائمة النطاقات المطلوبة إلى
[]لكي لا تتمكن جلسة غير مرتبطة بجهاز أو رمز مميز مقترن ومعتمد من التصريح بأذوناتها ذاتيًا. - إذا فشلت الأساليب برسالة
missing scopeبعد نجاح اتصال WebSocket، فاستخدم HTTPS لكي يتمكن المتصفح من إنشاء هوية الجهاز وإكمال الإقران. راجع استخدام HTTP غير الآمن لواجهة التحكم. - للاستخدام الطارئ فقط: يحافظ
gateway.controlUi.dangerouslyDisableDeviceAuth=trueعلى النطاقات المطلوبة حتى دون هوية جهاز. يمثل هذا خفضًا أمنيًا شديدًا؛ تراجع عنه بسرعة. راجع استخدام HTTP غير الآمن لواجهة التحكم.
تقييد النطاقات عبر الوكيل العكسي: إذا أرسل وكيلك x-openclaw-scopes في طلب ترقية WebSocket الخاص بواجهة التحكم، يقيّد OpenClaw نطاقات الجلسة إلى تقاطع النطاقات المطلوبة مع النطاقات المعلنة. لا تمنح هذه الترويسة نطاقات؛ بل تضيّق فقط ما يمكن للجلسة الاحتفاظ به.
الآثار:
- لم يعد الإقران هو البوابة الأساسية للوصول إلى واجهة التحكم في هذا الوضع.
- تصبح سياسة المصادقة في وكيلك العكسي و
allowUsersآلية التحكم الفعلية في الوصول. - أبقِ حركة المرور الواردة إلى Gateway مقصورة على عناوين IP للوكلاء الموثوقين فقط (
gateway.trustedProxies+ جدار الحماية).
عملاء WebSocket المخصصون ليسوا جلسات لواجهة التحكم. لا يمنح gateway.controlUi.dangerouslyDisableDeviceAuth نطاقات لعملاء عشوائيين يستخدمون client.mode: "backend" أو يتخذون شكل عملاء CLI. يجب أن تستخدم الأتمتة المخصصة هوية الجهاز والإقران، أو مسار مساعد الواجهة الخلفية المحلي المباشر المحجوز client.id: "gateway-client"، أو Plugin استدعاء HTTP RPC الإداري عندما تكون واجهة طلب/استجابة HTTP أنسب.
ترويسة نطاقات المشغّل
مصادقة الوكيل الموثوق هي وضع HTTP يحمل الهوية، لذلك يمكن للمتصلين اختياريًا إعلان نطاقات المشغّل باستخدام x-openclaw-scopes في طلبات HTTP API.
ملاحظة: تحدد مصافحة بروتوكول Gateway وربط هوية الجهاز نطاقات WebSocket. في طلبات ترقية WebSocket الخاصة بواجهة التحكم، لا تمثل x-openclaw-scopes سوى حد أقصى لنطاقات الجلسة المتفاوض عليها، وليست منحة. راجع سلوك إقران واجهة التحكم.
أمثلة:
x-openclaw-scopes: operator.readx-openclaw-scopes: operator.read,operator.writex-openclaw-scopes: operator.admin,operator.write
السلوك:
- عندما تكون الترويسة موجودة، يحترم OpenClaw مجموعة النطاقات المعلنة.
- عندما تكون الترويسة موجودة لكنها فارغة، يعلن الطلب عدم وجود أي نطاقات للمشغّل.
- عندما تكون الترويسة غائبة، ترجع واجهات HTTP API العادية الحاملة للهوية إلى مجموعة نطاقات المشغّل الافتراضية القياسية (
operator.adminوoperator.readوoperator.writeوoperator.approvalsوoperator.pairingوoperator.talk.secrets). - تكون مسارات HTTP الخاصة بالـ Plugin والمصادَق عليها عبر Gateway أضيق افتراضيًا: عند غياب
x-openclaw-scopes، يرجع نطاق وقت التشغيل الخاص بها إلىoperator.writeفقط. - يجب أن تجتاز طلبات HTTP الصادرة من المتصفح
gateway.controlUi.allowedOrigins(أو وضع الرجوع المتعمد إلى ترويسة Host) حتى بعد نجاح مصادقة الوكيل الموثوق.
قاعدة عملية: أرسل x-openclaw-scopes صراحةً عندما تريد أن يكون طلب الوكيل الموثوق أضيق من الإعدادات الافتراضية، أو عندما يحتاج مسار Plugin مصادَق عليه عبر Gateway إلى صلاحية أقوى من نطاق الكتابة.
إنهاء TLS وHSTS
استخدم نقطة واحدة لإنهاء TLS وطبّق HSTS فيها.
إنهاء TLS عند الوكيل (موصى به)
عندما يتولى الوكيل العكسي HTTPS للنطاق https://control.example.com، عيّن Strict-Transport-Security في الوكيل لذلك النطاق.
- مناسب لعمليات النشر المواجهة للإنترنت.
- يحافظ على سياسة الشهادات وتقوية HTTP في مكان واحد.
- يمكن أن يظل OpenClaw على HTTP عبر local loopback خلف الوكيل.
مثال لقيمة الترويسة:
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=300) أثناء التحقق من حركة المرور. - زِد القيمة إلى مدة طويلة (مثل
max-age=31536000) فقط بعد اكتساب ثقة عالية. - أضف
includeSubDomainsفقط إذا كانت جميع النطاقات الفرعية جاهزة لاستخدام HTTPS. - استخدم التحميل المسبق فقط إذا كنت تستوفي عمدًا متطلباته لمجموعة نطاقاتك الكاملة.
- لا تستفيد بيئة التطوير المحلية التي تقتصر على local loopback من HSTS.
أمثلة على إعداد الوكيل
Pomerium
يمرر Pomerium الهوية في x-pomerium-claim-email (أو ترويسات مطالبات أخرى) وJWT في 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"], }, }, },}مقتطف من إعداد Pomerium:
routes: - from: https://openclaw.example.com to: http://openclaw-gateway:18789 policy: - allow: or: - email: is: nick@example.com pass_identity_headers: trueCaddy مع OAuth
يستطيع Caddy مع Plugin caddy-security مصادقة المستخدمين وتمرير ترويسات الهوية.
{ gateway: { bind: "lan", trustedProxies: ["10.0.0.1"], // عنوان IP لوكيل Caddy/sidecar 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 مع المصادقة المُمرَّرة
{ gateway: { bind: "lan", trustedProxies: ["172.17.0.1"], // عنوان IP لحاوية Traefik auth: { mode: "trusted-proxy", trustedProxy: { userHeader: "x-forwarded-user", }, }, },}إعداد الرموز المميّزة المختلط
يرفض بدء تشغيل Gateway مصادقة الوكيل الموثوق إذا كان رمز مميّز مشترك مُعدًّا أيضًا (gateway.auth.token أو OPENCLAW_GATEWAY_TOKEN). الخياران متنافيان، لأن الرمز المميّز المشترك سيسمح للمتصلين من المضيف نفسه بالمصادقة عبر مسار مختلف تمامًا عن الهوية التي تحقق منها الوكيل، والتي صُمم هذا الوضع لفرضها.
إذا فشل بدء التشغيل برسالة خطأ مثل gateway auth mode is trusted-proxy, but a shared token is also configured:
- أزل الرمز المميّز المشترك عند استخدام وضع الوكيل الموثوق، أو
- غيّر
gateway.auth.modeإلى"token"إذا كنت تقصد استخدام المصادقة المستندة إلى رمز مميّز.
تظل ترويسات هوية الوكيل الموثوق عبر local loopback تفشل بشكل مغلق: لا تتم مصادقة المتصلين من المضيف نفسه ضمنيًا كمستخدمي الوكيل. ويمكن لمتصلِي OpenClaw الداخليين الذين يتجاوزون الوكيل المصادقة باستخدام gateway.auth.password / OPENCLAW_GATEWAY_PASSWORD بدلًا من ذلك. يظل الرجوع إلى الرمز المميّز غير مدعوم عمدًا في وضع الوكيل الموثوق.
قائمة التحقق الأمنية
قبل تمكين مصادقة الوكيل الموثوق، تحقق مما يلي:
- [ ] الوكيل هو المسار الوحيد: منفذ Gateway محمي بجدار ناري من كل شيء باستثناء وكيلك.
- [ ]
trustedProxiesفي حدها الأدنى: عناوين IP الفعلية لوكيلك فقط، وليس شبكات فرعية كاملة. - [ ] مصدر وكيل local loopback مقصود: تفشل مصادقة الوكيل الموثوق بشكل مغلق للطلبات ذات مصدر local loopback ما لم يُمكّن
gateway.auth.trustedProxy.allowLoopbackصراحةً لوكيل على المضيف نفسه. - [ ] الوكيل يزيل الترويسات: يستبدل وكيلك ترويسات
x-forwarded-*الواردة من العملاء، ولا يلحقها. - [ ] إنهاء TLS: يتولى وكيلك TLS؛ ويتصل المستخدمون عبر HTTPS.
- [ ]
allowedOriginsمحددة صراحةً: تستخدم واجهة التحكم غير المتصلة عبر local loopback قيمة صريحة لـgateway.controlUi.allowedOrigins. - [ ]
allowUsersمضبوطة (موصى به): اقصر الوصول على المستخدمين المعروفين بدلًا من السماح لأي مستخدم تمت مصادقته. - [ ] لا يوجد إعداد مختلط للرمز المميّز: لا تضبط كلًا من
gateway.auth.tokenوgateway.auth.mode: "trusted-proxy". - [ ] الرجوع المحلي إلى كلمة المرور خاص: إذا أعددت
gateway.auth.passwordللمتصلين الداخليين المباشرين، فأبقِ منفذ Gateway محميًا بجدار ناري بحيث لا يتمكن العملاء البعيدون غير المارين بالوكيل من الوصول إليه مباشرةً.
التدقيق الأمني
يُبلغ openclaw security audit عن مصادقة الوكيل الموثوق كنتيجة ذات خطورة حرجة. هذا مقصود؛ فهو تذكير بأنك تفوض الأمان إلى إعداد وكيلك.
يتحقق التدقيق مما يلي:
- التحذير/التذكير الحرج الأساسي
gateway.trusted_proxy_auth. - غياب إعداد
trustedProxies. - غياب إعداد
userHeader. - كون
allowUsersفارغة (ما يسمح لأي مستخدم تمت مصادقته). - تمكين
allowLoopbackلمصادر الوكيل الموجودة على المضيف نفسه.
تنطبق أيضًا نتائج منفصلة غير خاصة بالوكيل الموثوق كلما كانت واجهة التحكم مكشوفة: استخدام حرف بدل أو غياب gateway.controlUi.allowedOrigins، والرجوع إلى أصل ترويسة Host.
استكشاف الأخطاء وإصلاحها
trusted_proxy_untrusted_source
لم يأتِ الطلب من عنوان IP موجود في gateway.trustedProxies. تحقق مما يلي:
- هل عنوان IP الخاص بالوكيل صحيح؟ (قد تتغير عناوين IP لحاويات Docker.)
- هل يوجد موازن تحميل أمام وكيلك؟
- استخدم
docker inspectأوkubectl get pods -o wideللعثور على عناوين IP الفعلية.
trusted_proxy_loopback_source
رفض OpenClaw طلب وكيل موثوق مصدره local loopback.
تحقق مما يلي:
- هل يتصل الوكيل من
127.0.0.1/::1؟ - هل تحاول استخدام مصادقة الوكيل الموثوق مع وكيل عكسي عبر local loopback على المضيف نفسه؟
الإصلاح:
- فضّل المصادقة بالرمز المميّز/كلمة المرور للعملاء الداخليين على المضيف نفسه الذين لا يمرون عبر الوكيل، أو
- وجّه الاتصال عبر عنوان وكيل موثوق ليس عنوان local loopback، واحتفظ بعنوان IP هذا في
gateway.trustedProxies، أو - بالنسبة إلى وكيل عكسي مقصود على المضيف نفسه، اضبط
gateway.auth.trustedProxy.allowLoopback = true، واحتفظ بعنوان local loopback فيgateway.trustedProxies، وتأكد من أن الوكيل يزيل ترويسات الهوية أو يستبدلها.
trusted_proxy_local_interface_source / trusted_proxy_local_interface_check_failed
تطابق عنوان IP لمصدر الطلب مع أحد عناوين واجهات الشبكة غير التابعة لـ local loopback في مضيف Gateway نفسه (وليس الوكيل)، وذلك للحماية من حركة المرور المنتحلة من المضيف نفسه على شبكات tailnet أو شبكات جسر Docker. وتعني ..._check_failed أن اكتشاف الواجهات نفسه واجه خطأ، لذا يفشل OpenClaw بشكل مغلق.
تحقق مما يلي:
- هل ترسل عملية على مضيف Gateway نفسه ترويسات الهوية مباشرةً متجاوزةً الوكيل؟
- هل يعمل الوكيل في مساحة أسماء الشبكة نفسها التي يعمل فيها Gateway، بعنوان IP يظهر أيضًا كواجهة محلية؟
الإصلاح: وجّه حركة مرور الوكيل عبر عنوان غير مرتبط محليًا أيضًا بمضيف Gateway، أو استخدم allowLoopback فقط لإعداد وكيل حقيقي على المضيف نفسه.
trusted_proxy_user_missing
كانت ترويسة المستخدم فارغة أو مفقودة. تحقق مما يلي:
- هل وكيلك مُعد لتمرير ترويسات الهوية؟
- هل اسم الترويسة صحيح؟ (غير حساس لحالة الأحرف، لكن التهجئة مهمة)
- هل تمت مصادقة المستخدم فعليًا لدى الوكيل؟
trusted_proxy_missing_header_*
لم تكن إحدى الترويسات المطلوبة موجودة. تحقق مما يلي:
- إعداد وكيلك لتلك الترويسات المحددة.
- ما إذا كانت الترويسات تُزال في مكان ما ضمن السلسلة.
trusted_proxy_user_not_allowed
تمت مصادقة المستخدم لكنه غير موجود في allowUsers. إما أن تضفه أو تزيل قائمة السماح.
trusted_proxy_no_proxies_configured / trusted_proxy_config_missing
قيمة gateway.auth.mode هي "trusted-proxy" لكن gateway.trustedProxies فارغة، أو أن gateway.auth.trustedProxy نفسها مفقودة. يُرفض كل طلب حتى يتم ضبطهما معًا.
trusted_proxy_origin_not_allowed
نجحت مصادقة الوكيل الموثوق، لكن ترويسة المتصفح Origin لم تجتز عمليات تحقق واجهة التحكم من الأصل.
تحقق مما يلي:
- تتضمن
gateway.controlUi.allowedOriginsأصل المتصفح المطابق تمامًا. - لا تعتمد على أصول حرف البدل إلا إذا كنت تريد عمدًا سلوك السماح للجميع.
- إذا كنت تستخدم عمدًا وضع الرجوع إلى ترويسة Host، فاضبط
gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=trueعن قصد.
ينجح الاتصال لكن الأساليب تُبلغ عن نطاق مفقود
يتصل WebSocket، لكن chat.history أو sessions.list أو
models.list يفشل مع missing scope: operator.read.
الأسباب الشائعة:
- جلسة واجهة تحكم بلا جهاز: يمكن لمصادقة الوكيل الموثوق السماح باتصال WebSocket من دون هوية جهاز، لكن OpenClaw يمسح النطاقات في الجلسات التي بلا جهاز حسب التصميم.
- عميل خلفي مخصص: يقتصر
gateway.controlUi.dangerouslyDisableDeviceAuthعلى واجهة التحكم، ولا يمنح نطاقات لعملاء WebSocket عشوائيين للواجهة الخلفية أو المشابهين لـ CLI. - قيمة
x-openclaw-scopesضيقة أكثر من اللازم: إذا حقن وكيلك هذه الترويسة في طلب ترقية WebSocket الخاص بواجهة التحكم، فتُحدَّد نطاقات الجلسة بتلك المجموعة. وتؤدي قيمة الترويسة الفارغة إلى عدم وجود نطاقات.
الإصلاح:
- بالنسبة إلى واجهة التحكم، استخدم HTTPS كي يتمكن المتصفح من إنشاء هوية الجهاز وإكمال الاقتران.
- بالنسبة إلى الأتمتة المخصصة، استخدم هوية الجهاز/الاقتران، أو مسار مساعد الواجهة الخلفية المباشر المحلي المحجوز
gateway-client، أو استدعاء RPC الإداري عبر HTTP. - استخدم
gateway.controlUi.dangerouslyDisableDeviceAuth: trueفقط كمسار طوارئ مؤقت لواجهة التحكم.
ما يزال WebSocket يفشل
تأكد من أن وكيلك:
- يدعم ترقيات WebSocket (
Upgrade: websocket، وConnection: upgrade). - يمرر ترويسات الهوية في طلبات ترقية WebSocket (وليس HTTP فقط).
- لا يملك مسار مصادقة منفصلًا لاتصالات WebSocket.
الترحيل من مصادقة الرمز المميّز
إعداد الوكيل
أعد وكيلك لمصادقة المستخدمين وتمرير الترويسات.
اختبار الوكيل بشكل مستقل
اختبر إعداد الوكيل بشكل مستقل (استخدم curl مع الترويسات).
تحديث إعداد OpenClaw
حدّث إعداد OpenClaw باستخدام مصادقة الوكيل الموثوق.
إعادة تشغيل Gateway
أعد تشغيل Gateway.
اختبار WebSocket
اختبر اتصالات WebSocket من واجهة التحكم.
التدقيق
شغّل openclaw security audit وراجع النتائج.
ذات صلة
- الإعداد — مرجع الإعدادات
- نطاقات المشغّل — الأدوار والنطاقات وعمليات تحقق الموافقة
- الوصول عن بُعد — أنماط أخرى للوصول عن بُعد
- الأمان — دليل الأمان الكامل
- Tailscale — بديل أبسط للوصول المقصور على tailnet