يمكن لـ ClickHouse مصادقة المستخدمين باستخدام JSON Web Tokens (JWTs). وعلى عكس موفّرات المصادقة الخارجية الأخرى مثل LDAP أو Kerberos، فإن المصادقة عبر JWT لا تتحقق من هوية المستخدمين الموجودين مسبقًا. وبدلًا من ذلك، تُنشئ مستخدمين مؤقتين ديناميكيًا من المطالبات المضمّنة في كل رمز مميز. ولا يوجد هؤلاء المستخدمون إلا في الذاكرة، ويحصلون على صلاحيات وصول مشتقة من مطالبات الـ رمز المميز، وتتم إزالتهم تلقائيًا بعد انتهاء صلاحية الـ رمز المميز.
وهذا يجعل المصادقة عبر JWT مختلفة جذريًا عن الطرق المعتمدة على password أو الشهادات: فلا توجد عبارة CREATE USER ... IDENTIFIED WITH jwt، وأي محاولة لذلك تؤدي إلى ظهور استثناء. ويُدار مستخدمو JWT بالكامل وفقًا لدورة حياة الـ رمز المميز.
يعمل تدفق المصادقة على النحو التالي:
- يقدّم عميل رمز JWT موقّعًا عبر إحدى آليات النقل المدعومة (ترويسة HTTP
Authorization: Bearer، أو البروتوكول الأصلي عبر TCP، أو الحقل jwt في gRPC).
- يتحقق ClickHouse من توقيع الرمز المميز.
- يُتحقق من المطالبات المطلوبة (
exp, iat, iss, sub, aud).
- يُنشأ مستخدم مؤقت في الذاكرة مع صلاحيات وصول مشتقة من مطالبات الرمز المميز
clickhouse:grants وclickhouse:roles، ومتقاطعة مع حدّ الصلاحيات.
- عند انتهاء صلاحية الرمز المميز، تزيل مهمة جمع البيانات المهملة في الخلفية هذا المستخدم.
يجب أن يحتوي كل JWT يُقدَّم إلى ClickHouse على المطالبات التالية:
| المطالبة | الوصف |
|---|
alg | خوارزمية التوقيع (مطالبة في الترويسة). القيم المدعومة: HS256 وRS256 وES256. |
exp | وقت انتهاء الصلاحية. يحدّد valid_until للمستخدم المؤقت. |
iat | وقت الإصدار. يُستخدم لمنع إعادة استخدام الرموز المميزة الأقدم للهوية نفسها. |
iss | الجهة المُصدِرة. يُطابَق مع الجهة المُصدِرة المتوقعة لدى المزوّد. |
sub | المعرّف. يصبح جزءًا من اسم المستخدم المُنشأ. |
aud | الجمهور المستهدف. يُطابَق مع الجمهور المستهدف المتوقع لدى المزوّد. |
تكون مطالبة kid في الترويسة (معرّف المفتاح) مطلوبة أيضًا عند استخدام تحليل المفاتيح المستند إلى JWKS.
يدعم وضع JWKS مفاتيح RSA فقطفي حين أن موفّري المفاتيح الثابتة يقبلون أيًا من HS256 أو RS256 أو ES256، فإن الموفّرين المستندين إلى JWKS لا يقبلون إلا JWKs التي تكون فيها قيمة kty هي RSA (أي الرموز المميزة الموقّعة باستخدام RS256). ولا يمكن التحقق من الرموز المميزة الموقّعة بمفاتيح HMAC (HS256) أو EC (ES256) باستخدام endpoint لـ JWKS، لذلك سيتم رفضها.
| المطالبة | الوصف |
|---|
nbf | وقت “ليس قبل”. هذه المطالبة ليست مطلوبة، ولكن إذا كانت موجودة، فسيتم رفض الرموز المميزة قبل هذا الوقت. |
jti | محجوزة. تُقبل في الرموز المميزة، ولكن لا يُتحقق منها أو تُستخدم حاليًا. |
| المطالبة | الاسم الافتراضي | الوصف |
|---|
| الامتيازات | clickhouse:grants | مصفوفة JSON تضم مقاطع من عبارة SQL GRANT، مثل ["SELECT ON db.*", "INSERT ON db.table1"]. ويُفسَّر كل عنصر على أنه متن عبارة GRANT. |
| الأدوار | clickhouse:roles | مصفوفة JSON لأسماء الأدوار المراد إسنادها، مثل ["analyst", "reader"]. |
| يمكن إعادة تعيين أسماء المطالبات الافتراضية إلى أسماء مطالبات مخصّصة إذا كان موفّر الهوية لديك يستخدم اصطلاحات تسمية مختلفة. | | |
مثال على رأس الرمز المميز وحمولته
{
"alg": "RS256",
"kid": "my-key-id"
}
{
"iss": "https://idp.example.com",
"sub": "jane.doe",
"aud": "my-clickhouse-cluster",
"exp": 1719504000,
"iat": 1719500400,
"clickhouse:grants": ["SELECT ON analytics.*", "INSERT ON analytics.events"],
"clickhouse:roles": ["analyst"]
}
يختلف مستخدمو JWT عن مستخدمي ClickHouse العاديين في عدة نواحٍ مهمة.
يتلقى كل مستخدم JWT معرّف UUID حتميًا يُحتسب من مطالبات iss وsub وaud. ويظل هذا المعرّف ثابتًا عبر عمليات تسجيل الدخول. لذا فإن المستخدم الذي يسجّل الدخول عدة مرات باستخدام رموز مميزة مختلفة (ولكن مع issuer وsubject وaudience نفسها) يحصل دائمًا على معرّف UUID نفسه.
أما اسم المستخدم فهو غير ثابت. ويُنشأ على النحو التالي:
JWT::<issuer>::<audience>::<subject>::<claims_hash>
يتغيّر الجزء <claims_hash> كلما تغيّرت المطالبات clickhouse:roles أو clickhouse:grants. وهذا يعني أن الرموز المميّزة ذات مجموعات الأدوار أو الامتيازات المختلفة تُنتِج أسماء مستخدمين مختلفة حتى للهوية نفسها.
تُحتسب صلاحيات الوصول الفعلية على النحو التالي:
effective_rights = permission_limit ∩ (token_grants ∪ token_roles)
حيث إن permission_limit هي مجموعة حقوق الوصول التي يمتلكها دور مرجعي أو مستخدم مُعدّ ليكون الحد الأعلى. وأي حقوق يطلبها الرمز المميز وتتجاوز هذا الحد تُسقَط بصمت.
يتتبّع ClickHouse مطالبة iat (وقت الإصدار) لأحدث رمز مميز تمت مصادقته لكل هوية مستقرة. وإذا قُدِّم رمز مميز بقيمة iat تساوي القيمة المخزنة أو تسبقها، يعيد الخادم استخدام المستخدم المؤقت الحالي من دون إعادة تقييم المطالبات. ويمنع ذلك الرموز المميزة الأقدم من تقليص أذونات المستخدم.
دورة الحياة وجمع البيانات المهملة
يتم إنشاء المستخدمين المؤقتين عند مصادقة الرمز المميز لأول مرة، ثم تُزيلهم مهمة جمع البيانات المهملة في الخلفية بعد انقضاء valid_until (المشتق من exp). ويتم التحكم في الفاصل الزمني لـ GC بواسطة المعلَمة gc_interval (الافتراضي: 5 دقائق).
بين مرات تشغيل GC، قد يظل المستخدمون منتهو الصلاحية ظاهرين في system.users، لكن لن يعودوا قادرين على المصادقة.
تعيينات صلاحيات الوصول الدائمة
نظرًا لأن معرّف UUID ثابت، يمكنك إسناد ملفات تعريف الإعدادات، والحصص، وسياسات الصفوف، وسياسات إخفاء الأعمدة إلى مستخدم JWT باستخدام عبارات SQL. وتظل هذه التعيينات محفوظة في مخزن التحكم في الوصول (على القرص أو في ZooKeeper)، وتبقى سارية بعد انتهاء صلاحية الرمز المميز وإعادة المصادقة.
استخدم اسم المستخدم الحالي للإشارة إلى المستخدم:
ALTER SETTINGS PROFILE my_profile ADD TO 'JWT::ClickHouse::my-service-id::jane.doe::<claims-hash>';
يمكن العثور على اسم المستخدم ومعرّف UUID لهوية معيّنة في العمودين name وid في system.users ما دام المستخدم نشطًا.
لاحظ أن ALTER USER لا يعمل مباشرةً مع مستخدمي JWT، لأنهم للقراءة فقط. لإسناد ملفات تعريف الإعدادات أو الحصص أو السياسات، استخدم عبارات ALTER SETTINGS PROFILE أو ALTER QUOTA أو ALTER ROW POLICY كما هو موضح أعلاه.
الاختلافات عن المستخدمين العاديين
| الميزة | مستخدمو JWT | المستخدمون العاديون |
|---|
| الإنشاء | تلقائي من مطالبات الرمز | عبارة CREATE USER |
| التخزين | في الذاكرة فقط (مؤقت) | القرص أو ZooKeeper أو ملف الإعدادات |
CREATE USER ... IDENTIFIED WITH jwt | غير مدعوم (يؤدي إلى استثناء) | جميع أنواع المصادقة الأخرى مدعومة |
ALTER USER / DROP USER | غير مدعوم | مدعوم |
| النسخ الاحتياطي والاستعادة | غير مشمولين | مشمولان |
| اسم المستخدم | يُنشأ تلقائيًا، وغير ثابت | يختاره المسؤول، وثابت |
| معرّف UUID | يُشتق حتميًا من iss+sub+aud | عشوائي عند الإنشاء |
| مدة الصلاحية | مقيّدة بـ exp الخاص بالرمز | حتى يُحذف صراحةً |
| صلاحيات الوصول | مشتقة من مطالبات الرمز، ومقيّدة بحدّ الصلاحيات | تُمنح صراحةً عبر GRANT |
| قيود المضيف | تهيئة الشبكة الخاصة بكل موفّر | عبارة HOST لكل مستخدم |
| ملفات تعريف الإعدادات | يمكن إسنادها بواسطة معرّف UUID (بشكل دائم) | قابلة للتهيئة مباشرةً |
| الحصص وسياسات الصفوف | يمكن إسنادها بواسطة معرّف UUID (بشكل دائم) | قابلة للتهيئة مباشرةً |
| الأدوار الافتراضية | غير قابلة للتهيئة | قابلة للتهيئة |
طرق العرض SQL SECURITY DEFINER
عندما ينشئ مستخدم JWT مؤقت طريقة عرض باستخدام SQL SECURITY DEFINER، ينشئ الخادم تلقائيًا نسخة ظل دائمة من هذا المستخدم لتكون مُعرِّف طريقة العرض. ويتميّز هذا المستخدم الظل بما يلي:
- يحمل الاسم
<original_jwt_username>:definer
- لديه
NO_AUTHENTICATION (ولا يمكن استخدامه لتسجيل الدخول)
- يحتفظ بحقوق الوصول نفسها التي كانت لدى مستخدم JWT الأصلي وقت إنشاء طريقة العرض
وهذا يضمن استمرار طريقة العرض في العمل بعد انتهاء صلاحية رمز المستخدم المؤقت وإزالة المستخدم الأصلي عبر جمع المهملات.
استخدم الخيار --jwt مع clickhouse-client للمصادقة باستخدام رمز مميز تم الحصول عليه مسبقًا:
clickhouse-client --host your-instance.clickhouse.cloud --secure --jwt '<your_jwt_token>'
الخيار --jwt لا يمكن استخدامه مع --user. عند تحديد --jwt، يُشتق اسم المستخدم من الرمز المميّز.
أرسل الرمز المميز كـ Bearer token في ترويسة Authorization:
curl -H 'Authorization: Bearer <your_jwt_token>' \
'https://your-instance.clickhouse.cloud:8443/?query=SELECT+currentUser()'
أرسل دائمًا رموز JWT عبر HTTPS. إن رمز Bearer المُرسَل عبر HTTP غير المشفّر يكون مكشوفًا لأي شخص على مسار الشبكة، ويُعدّ ذلك بمثابة تسريب لبيانات الاعتماد.
تسجيل الدخول باستخدام رمز جهاز OAuth2
يدعم clickhouse-client مسار رمز جهاز OAuth2 التفاعلي عبر الخيار --login. بالنسبة إلى نقاط النهاية في ClickHouse Cloud، يُجري العميل تلقائيًا عملية تبادل الرموز المميزة للحصول على JWT خاص بـ ClickHouse. تُحدَّث الرموز المميزة تلقائيًا أثناء الجلسة. وعند الحصول على رمز مميز جديد، يعيد العميل الاتصال تلقائيًا.
clickhouse-client --host your-instance.clickhouse.cloud --login
مُصادِق JWT المضمّن في ClickHouse Cloud
تأتي كل خدمة في ClickHouse Cloud مع مُصادِق JWT مُعرَّف مسبقًا يُستخدم في SQL Console ومع تدفّق --login في clickhouse-client. يُضبط هذا المُصادِق على النحو التالي:
| المَعلمة | القيمة |
|---|
iss (issuer) | ClickHouse |
aud (audience) | معرّف UUID الخاص بالخدمة (ويظهر في عنوان URL لوحدة تحكم Cloud) |
sub (subject) | عنوان البريد الإلكتروني لحسابك في ClickHouse Cloud |
يحتوي المُصادِق المضمّن على حدٍّ للصلاحيات مضبوط على الدور default_role والمستخدم default. وهذا يعني أن الصلاحيات الفعلية لأي مستخدم JWT تُقاطع مع الصلاحيات الممنوحة لهذين الكيانين، لذا لا يمكن لأي رمز JWT مطلقًا رفع الامتيازات إلى ما يتجاوز المسموح به لكل من default_role وdefault.
لا تحتاج إلى تهيئة أي شيء لاستخدام هذا المُصادِق. إذ يُوفَّر تلقائيًا عند إنشاء الخدمة.
عندما يُعاد توجيه الاستعلام إلى сегмент أو نسخة متماثلة أخرى، يُضمَّن رمز JWT في بروتوكول الاتصال بين الخوادم. وتُعيد العقدة البعيدة المصادقة على الرمز بشكل مستقل، وتُنشئ مستخدمًا مؤقتًا خاصًا بها.
- لم تُمنح صلاحيات الوصول: قد يفتقر الدور أو المستخدم المشار إليه إلى الامتيازات المطلوبة. تأكد من أن الأدوار المشار إليها في
clickhouse:roles موجودة وتتضمن الامتيازات المناسبة.
- رُفض الرمز المميز: تحقّق من أن
iss وaud وخوارزمية التوقيع في الرمز المميز لديك تطابق ما يتوقعه موفّر JWT. إذا كان JWKS مستخدمًا، فتأكد من أن kid الخاص بالرمز المميز يطابق مفتاحًا في مجموعة مفاتيح الموفّر.
- يختفي المستخدم بين الاستعلامات: يُزال المستخدمون المؤقتون بعد انتهاء صلاحية الرمز المميز. استخدم عميلًا يدعم تحديث الرمز المميز (مثل وضع
--login) للجلسات طويلة الأمد.
- يفشل
CREATE USER ... IDENTIFIED WITH jwt: هذا متوقع. لا يمكن إنشاء مستخدمي JWT عبر DDL، إذ تُدار بالكامل من خلال دورة حياة الرمز المميز.