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 (عند تعيينها)، يُخوَّل الطلب.

  • الإعداد

    json5
    {  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.read
    • x-openclaw-scopes: operator.read,operator.write
    • x-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 خلف الوكيل.

    مثال لقيمة الترويسة:

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

    إنهاء TLS عند Gateway

    إذا كان OpenClaw نفسه يقدّم HTTPS مباشرةً (دون وكيل ينهي TLS)، فعيّن:

    json5
    {  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.

    json5
    {  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:

    yaml
    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 مع Plugin ‏caddy-security مصادقة المستخدمين وتمرير ترويسات الهوية.

    json5
    {  gateway: {    bind: "lan",    trustedProxies: ["10.0.0.1"], // عنوان IP لوكيل Caddy/sidecar    auth: {      mode: "trusted-proxy",      trustedProxy: {        userHeader: "x-forwarded-user",      },    },  },}

    مقتطف من Caddyfile:

    caddy
    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.

    json5
    {  gateway: {    bind: "lan",    trustedProxies: ["10.0.0.1"], // عنوان IP لـ nginx/oauth2-proxy    auth: {      mode: "trusted-proxy",      trustedProxy: {        userHeader: "x-auth-request-email",      },    },  },}

    مقتطف من إعداد nginx:

    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 مع المصادقة المُمرَّرة
    json5
    {  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 وراجع النتائج.

  • ذات صلة

    Was this useful?
    On this page

    On this page