The Private Vault: Building "Zero Trust Intelligence" with AlloyDB Row-Level Security

1- نظرة عامة

في خضمّ التسرّع لإنشاء تطبيقات الذكاء الاصطناعي التوليدي، غالبًا ما ننسى العنصر الأكثر أهمية، وهو الأمان.

لنفترض أنّك تريد إنشاء روبوت دردشة خاص بالموارد البشرية. يجب أن يجيب عن أسئلة مثل "ما هو راتبي؟" أو "كيف يؤدي فريقي؟"

  • إذا طلبت أليس (موظفة عادية) ذلك، يجب أن ترى بياناتها فقط.
  • إذا طلب بوب (مدير) ذلك، من المفترض أن تظهر له بيانات فريقه.

المشكلة

تحاول معظم بنى RAG (التوليد المعزّز بالاسترجاع) التعامل مع هذه المشكلة في طبقة التطبيق. تتم فلترة الأجزاء بعد استرجاعها، أو يتم الاعتماد على النموذج اللغوي الكبير في "التصرف" بشكل صحيح. هذا المنتج هشّ. في حال تعذُّر منطق التطبيق، يحدث تسريب للبيانات.

الحلّ

فرض الأمان على طبقة قاعدة البيانات باستخدام ميزة أمان على مستوى الصف (RLS) في PostgreSQL ضمن AlloyDB، نضمن أنّ قاعدة البيانات ترفض فعليًا عرض البيانات التي ليس لدى المستخدم إذن بالاطّلاع عليها، بغض النظر عن طلب الذكاء الاصطناعي.

في هذا الدليل، سننشئ "الخزنة الخاصة"، وهي مساعد آمن للموارد البشرية يغيّر إجاباته بشكل ديناميكي استنادًا إلى المستخدم الذي سجّل الدخول.

1e095ac5fe069bb6.png

بنية التطبيق

لن ننشئ منطق أذونات معقّدًا في Python. نحن نستخدم محرك قاعدة البيانات نفسه.

  1. الواجهة: تطبيق بسيط من Streamlit يحاكي عملية تسجيل الدخول.
  2. العقل: AlloyDB AI (متوافق مع PostgreSQL)
  3. آلية العمل: نضبط متغيّر جلسة (app.active_user) في بداية كل معاملة. تتحقّق سياسات قاعدة البيانات تلقائيًا من جدول user_roles (يعمل كموفّر الهوية) لفلترة الصفوف.

ما ستنشئه

تطبيق آمن لمساعد الموارد البشرية بدلاً من الاعتماد على منطق التطبيق لفلترة البيانات الحسّاسة، ستنفّذ ميزة "أمان على مستوى الصف" (RLS) مباشرةً في محرّك قاعدة بيانات AlloyDB. يضمن ذلك أنّه حتى إذا "هلوس" نموذج الذكاء الاصطناعي أو حاول الوصول إلى بيانات غير مصرَّح بها، سيرفض قاعدة البيانات فعليًا عرضها.

أهداف الدورة التعليمية

ستتعرّف على:

  • كيفية تصميم مخطط لأمان على مستوى الصف (فصل البيانات عن الهوية)
  • كيفية كتابة سياسات PostgreSQL (CREATE POLICY)
  • كيفية تجاوز الإعفاء "مالك الجدول" باستخدام FORCE ROW LEVEL SECURITY
  • كيفية إنشاء تطبيق Python ينفّذ "تبديل السياق" للمستخدمين

المتطلبات

  • متصفّح، مثل Chrome أو Firefox
  • مشروع Google Cloud تم تفعيل الفوترة فيه
  • الوصول إلى Cloud Shell أو إلى وحدة طرفية مثبَّت عليها gcloud وpsql

2. قبل البدء

إنشاء مشروع

  1. في Google Cloud Console، ضمن صفحة اختيار المشروع، اختَر أو أنشِئ مشروعًا على Google Cloud.
  2. تأكَّد من تفعيل الفوترة لمشروعك على Cloud. تعرَّف على كيفية التحقّق من تفعيل الفوترة في مشروع.
  1. ستستخدم Cloud Shell، وهي بيئة سطر أوامر تعمل في Google Cloud. انقر على "تفعيل Cloud Shell" في أعلى "وحدة تحكّم Google Cloud".

صورة زر تفعيل Cloud Shell

  1. بعد الاتصال بـ Cloud Shell، يمكنك التأكّد من أنّك قد أثبتّ هويتك وأنّ المشروع مضبوط على معرّف مشروعك باستخدام الأمر التالي:
gcloud auth list
  1. نفِّذ الأمر التالي في Cloud Shell للتأكّد من أنّ أمر gcloud يعرف مشروعك.
gcloud config list project
  1. إذا لم يتم ضبط مشروعك، استخدِم الأمر التالي لضبطه:
gcloud config set project <YOUR_PROJECT_ID>
  1. فعِّل واجهات برمجة التطبيقات المطلوبة: اتّبِع الرابط وفعِّل واجهات برمجة التطبيقات.

يمكنك بدلاً من ذلك استخدام أمر gcloud لهذا الغرض. راجِع المستندات لمعرفة أوامر gcloud وطريقة استخدامها.

gcloud services enable \
  alloydb.googleapis.com \
  compute.googleapis.com \
  cloudresourcemanager.googleapis.com \
  servicenetworking.googleapis.com \
  aiplatform.googleapis.com

المشاكل المحتملة وتحديد المشاكل وحلّها

متلازمة "المشروع الوهمي"

نفّذت الأمر gcloud config set project، ولكنّك في الواقع تنظر إلى مشروع مختلف في واجهة مستخدم "وحدة التحكّم". تحقَّق من رقم تعريف المشروع في القائمة المنسدلة أعلى يمين الصفحة.

حاجز الفوترة

لقد فعّلت المشروع، ولكن نسيت حساب الفوترة. ‫AlloyDB هو محرّك عالي الأداء، ولن يبدأ إذا كان "خزان الوقود" (الفوترة) فارغًا.

تأخُّر انتشار واجهة برمجة التطبيقات

نقرت على "تفعيل واجهات برمجة التطبيقات"، ولكن سطر الأوامر لا يزال يعرض Service Not Enabled. انتظِر لمدة 60 ثانية. تحتاج السحابة الإلكترونية إلى بعض الوقت لتنشيط الخلايا العصبية.

Quota Quags

إذا كنت تستخدم حسابًا تجريبيًا جديدًا تمامًا، قد تبلغ حصة إقليمية لمثيلات AlloyDB. إذا تعذّر تنفيذ us-central1، جرِّب us-east1.

3- إعداد قاعدة البيانات

في هذا التمرين العملي، سنستخدم AlloyDB كقاعدة بيانات لبيانات الاختبار. تستخدم المجموعات للاحتفاظ بجميع الموارد، مثل قواعد البيانات والسجلات. تحتوي كل مجموعة على مثيل أساسي يوفّر نقطة وصول إلى البيانات. ستحتوي الجداول على البيانات الفعلية.

لننشئ مجموعة ومثيل وجدول AlloyDB سيتم تحميل مجموعة البيانات الاختبارية فيها.

  1. انقر على الزر أو انسخ الرابط أدناه إلى المتصفّح الذي سجّلت فيه الدخول إلى حساب مستخدم Google Cloud Console.

  1. بعد إكمال هذه الخطوة، سيتم استنساخ المستودع إلى محرّر Cloud Shell المحلي، وستتمكّن من تنفيذ الأمر أدناه من مجلد المشروع (من المهم التأكّد من أنّك في دليل المشروع):
sh run.sh
  1. استخدِم الآن واجهة المستخدم (من خلال النقر على الرابط في الوحدة الطرفية أو النقر على الرابط "معاينة على الويب" في الوحدة الطرفية).
  2. أدخِل تفاصيل معرّف المشروع واسمَي المجموعة والآلة الافتراضية لبدء الاستخدام.
  3. يمكنك تناول القهوة بينما يتم عرض السجلات، ويمكنك الاطّلاع على كيفية تنفيذ ذلك في الخلفية هنا. قد يستغرق ذلك حوالي 10 إلى 15 دقيقة.

المشاكل المحتملة وتحديد المشاكل وحلّها

مشكلة "الصبر"

مجموعات قواعد البيانات هي بنية أساسية ثقيلة. إذا أعَدت تحميل الصفحة أو أغلقت جلسة Cloud Shell لأنّها "تبدو عالقة"، قد ينتهي بك الأمر إلى إنشاء آلة افتراضية "وهمية" تم توفيرها جزئيًا ولا يمكن حذفها بدون تدخّل يدوي.

عدم تطابق المنطقة

إذا فعّلت واجهات برمجة التطبيقات في us-central1 وحاولت توفير المجموعة في asia-south1، قد تواجه مشاكل في الحصة أو تأخيرات في أذونات حساب الخدمة. يجب الالتزام بمنطقة واحدة طوال فترة التدريب العملي.

مجموعات الزومبي

إذا سبق لك استخدام الاسم نفسه لمجموعة ولم تحذفها، قد تشير البرمجة النصية إلى أنّ اسم المجموعة مستخدَم من قبل. يجب أن تكون أسماء المجموعات فريدة ضمن المشروع.

انتهاء مهلة Cloud Shell

إذا استغرقت استراحة القهوة 30 دقيقة، قد يتم تشغيل وضع السكون في Cloud Shell وفصل عملية sh run.sh. يجب إبقاء علامة التبويب نشطة.

4. توفير المخطط

في هذه الخطوة، سنتناول ما يلي:

d05d7d2706c689dc.png

في ما يلي الإجراءات المفصّلة التي يجب اتّباعها:

بعد تشغيل مجموعة AlloyDB ومثيلها، انتقِل إلى أداة تعديل SQL في AlloyDB Studio لتفعيل إضافات الذكاء الاصطناعي وتوفير المخطّط.

1e3ac974b18a8113.png

قد تحتاج إلى الانتظار إلى أن يكتمل إنشاء مثيلك. بعد ذلك، سجِّل الدخول إلى AlloyDB باستخدام بيانات الاعتماد التي أنشأتها عند إنشاء المجموعة. استخدِم البيانات التالية للمصادقة على PostgreSQL:

  • اسم المستخدم : "postgres"
  • قاعدة البيانات : "postgres"
  • كلمة المرور : "alloydb" (أو أي كلمة مرور تم ضبطها عند إنشاء الحساب)

بعد إكمال عملية المصادقة بنجاح في AlloyDB Studio، يتم إدخال أوامر SQL في "المحرّر". يمكنك إضافة نوافذ "المحرّر" متعددة باستخدام علامة الجمع على يسار النافذة الأخيرة.

28cb9a8b6aa0789f.png

ستُدخل أوامر AlloyDB في نوافذ المحرّر، باستخدام الخيارات "تشغيل" و"تنسيق" و"محو" حسب الحاجة.

إنشاء جدول

نحتاج إلى جدولَين: أحدهما للبيانات الحسّاسة (الموظفون) والآخر لقواعد تحديد الهوية (user_roles). ويُعدّ فصلها أمرًا بالغ الأهمية لتجنُّب أخطاء "التكرار اللانهائي" في السياسات.

يمكنك إنشاء جدول باستخدام عبارة DDL أدناه في AlloyDB Studio:

-- 1. Create User Roles (The Identity Provider)
CREATE TABLE user_roles (
    username TEXT PRIMARY KEY,
    role TEXT -- 'employee', 'manager', 'admin'
);

INSERT INTO user_roles (username, role) VALUES
('Alice', 'employee'),
('Bob', 'manager'),
('Charlie', 'employee');

-- 2. Create the Data Table
CREATE TABLE employees (
    id SERIAL PRIMARY KEY,
    name TEXT,
    salary INTEGER,
    performance_review TEXT
);

INSERT INTO employees (name, salary, performance_review) VALUES
('Alice', 80000, 'Alice meets expectations but needs to improve punctuality.'),
('Bob', 120000, 'Bob is a strong leader. Team morale is high.'),
('Charlie', 85000, 'Charlie exceeds expectations. Ready for promotion.');

المشاكل المحتملة وتحديد المشاكل وحلّها

تم رصد تكرار لا نهائي أثناء تحديد الأدوار داخل جدول الموظفين

سبب التعذُّر: إذا كانت سياستك تنص على "التحقّق من جدول الموظفين لمعرفة ما إذا كنت مديرًا"، يجب أن يستعلم الجدول عن قاعدة البيانات للتحقّق من السياسة، ما يؤدي إلى تفعيل السياسة مرة أخرى.النتيجة: تم رصد تكرار لا نهائي.الحلّ: احتفظ دائمًا بجدول بحث منفصل (user_roles) أو استخدِم مستخدمي قاعدة البيانات الفعليين للأدوار.

تحقَّق من البيانات:

SELECT count(*) FROM employees;
-- Output: 3

5- تفعيل الأمان وفرضه

الآن، سنفعّل الدروع. سننشئ أيضًا "مستخدم تطبيق" عامًا سيستخدمه رمز Python للاتصال.

نفِّذ عبارة SQL أدناه من "محرّر طلبات البحث" في AlloyDB:

-- 1. Activate RLS
ALTER TABLE employees ENABLE ROW LEVEL SECURITY;


-- 2. CRITICAL: Force RLS for Table Owners
ALTER TABLE employees FORCE ROW LEVEL SECURITY;


-- 3. Create the Application User
DO
$do$
BEGIN
   IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'app_user') THEN
      CREATE ROLE app_user LOGIN PASSWORD 'password';
   END IF;
END
$do$;


-- 4. Grant Access
GRANT SELECT ON employees TO app_user;
GRANT SELECT ON user_roles TO app_user;

المشاكل المحتملة وتحديد المشاكل وحلّها

الاختبار بصفتك مستخدمًا فائقًا (postgres) والاطّلاع على جميع البيانات

سبب تعذُّر ذلك: لا تنطبق سياسة أمان على مستوى الصف تلقائيًا على مالك الجدول أو المستخدمين المميّزين. تتجاوز هذه الأذونات جميع السياسات.تحديد المشاكل وحلّها: إذا بدت سياساتك "معطّلة" (تسمح بكل شيء)، تحقّق مما إذا كنت مسجّلاً الدخول بصفتك postgres.الحلّ: يضمن الأمر FORCE ROW LEVEL SECURITY أن يخضع حتى المالك للقواعد. هذا أمر ضروري للاختبار.

6. إنشاء سياسات الوصول

سنحدّد قاعدتَين باستخدام "متغيّر جلسة" (app.active_user) سنضبطه من رمز تطبيقنا لاحقًا.

نفِّذ عبارة SQL أدناه من "محرّر طلبات البحث" في AlloyDB:

-- Policy 1: Self-View
-- Users can see rows where their name matches the session variable
CREATE POLICY "view_own_data" ON employees
FOR SELECT
USING (name = current_setting('app.active_user', true));

-- Policy 2: Manager-View
-- Managers can see ALL rows.
CREATE POLICY "manager_view_all" ON employees
FOR SELECT
USING (
    EXISTS (
        SELECT 1 FROM user_roles
        WHERE username = current_setting('app.active_user', true)
        AND role = 'manager'
    )
);

المشاكل المحتملة وتحديد المشاكل وحلّها

استخدام current_user بدلاً من app.active_user

المشكلة: Current_user هي كلمة رئيسية محجوزة في SQL تعرض دور قاعدة البيانات (مثل app_user). نحتاج إلى مستخدم التطبيق (مثل أليس).الحلّ: استخدِم دائمًا مساحة اسم مخصّصة، مثل app.variable_name.

عدم تضمين المَعلمة true في current_setting

المشكلة: إذا لم يتم ضبط المتغيّر، يتعطّل طلب البحث بسبب حدوث خطأ.الحل: تعرض الدالة current_setting('...', true) القيمة NULL بدلاً من التعطّل، ما يؤدي بأمان إلى عدم عرض أي صفوف.

7. إنشاء تطبيق "Chameleon"

سنستخدم Python وStreamlit لمحاكاة منطق التطبيق.

296a980887b5c700.png

افتح "وحدة Cloud Shell الطرفية" في "وضع المحرّر"، وانتقِل إلى المجلد الجذر أو الدليل الذي تريد إنشاء هذا التطبيق فيه. أنشئ مجلدًا جديدًا.

1. تثبيت التبعيات:

نفِّذ الأمر التالي في "وحدة Cloud Shell الطرفية" من داخل دليل مشروعك الجديد:

pip install streamlit psycopg2-binary

2. أنشئ ملف app.py:

أنشئ ملفًا جديدًا باسم app.py وانسخ المحتوى من ملف المستودع.

import streamlit as st
import psycopg2

# CONFIGURATION (Replace with your IP)
DB_HOST = "10.x.x.x"
DB_NAME = "postgres"
DB_USER = "postgres"
DB_PASS = "alloydb"

def get_db_connection():
    return psycopg2.connect(
        host=DB_HOST, database=DB_NAME, user=DB_USER, password=DB_PASS
    )

def query_database(user_name):
    conn = get_db_connection()
    try:
        with conn.cursor() as cur:
            # THE SECURITY HANDSHAKE
            # We tell the database: "For this transaction, I am acting as..."
            cur.execute(f"SET app.active_user = '{user_name}';")
            
            # THE BLIND QUERY
            # We ask for EVERYTHING. The database silently filters it.
            cur.execute("SELECT name, role, salary, performance_review FROM employees;")
            return cur.fetchall()
    finally:
        conn.close()

# UI
st.title("🛡️ The Private Vault")
user = st.sidebar.radio("Act as User:", ["Alice", "Bob", "Charlie", "Eve"])

if st.button("Access Data"):
    results = query_database(user)
    if not results:
        st.error("🚫 Access Denied.")
    else:
        st.success(f"Viewing data as {user}")
        for row in results:
            st.write(row)

3. شغِّل التطبيق:

نفِّذ الأمر التالي في "وحدة Cloud Shell الطرفية" من داخل دليل مشروعك الجديد:

streamlit run app.py --server.port 8080 --server.enableCORS false

المشاكل المحتملة وتحديد المشاكل وحلّها

تجميع الاتصالات

المخاطرة: إذا كنت تستخدم مجموعة اتصالات، قد يستمر متغير الجلسة SET app.active_user في الاتصال وقد "يتسرّب" إلى المستخدم التالي الذي يحصل على هذا الاتصال.الحل:في مرحلة الإنتاج، استخدِم دائمًا RESET app.active_user أو DISCARD ALL عند إعادة اتصال إلى المجموعة.

شاشة فارغة في Cloud Shell

الحلّ: استخدِم الزر "معاينة الويب" على المنفذ 8080. لا تنقر على رابط localhost في نافذة Terminal.

8. التحقّق من صحة نهج الثقة المعدومة

جرِّب التطبيق للتأكّد من تنفيذ "نهج الثقة المعدومة":

اختَر "أليس": من المفترض أن يظهر لها صف واحد (اسمها).

b3b7e374fa66ac87.png

اختَر "بوب": من المفترض أن يرى 3 صفوف (الجميع).

fdc65cb1acdee8a4.png

أهمية ذلك بالنسبة إلى "وكلاء الذكاء الاصطناعي"

لنفترض أنّك ربطت نموذجك بقاعدة البيانات هذه. إذا طلب مستخدم من النموذج: "لخِّص جميع مراجعات الأداء"، سينشئ النموذج SELECT performance_review FROM employees.

  1. بدون أمان على مستوى الصف: يستردّ نموذجك المراجعات الخاصة بكل مستخدم ويُفصح عنها لأليس.
  2. باستخدام أمان على مستوى الصف: ينفّذ نموذجك طلب البحث نفسه بالضبط، ولكن لا تعرض قاعدة البيانات سوى مراجعة "أليس".

هذا هو الذكاء الاصطناعي المستند إلى "نهج الثقة المعدومة". لا تثق في النموذج لفلترة البيانات، بل تفرض على قاعدة البيانات إخفاءها.

نقل هذا التطبيق إلى مرحلة الإنتاج

إنّ البنية الموضّحة هنا مناسبة للاستخدام في مرحلة الإنتاج، ولكن تم تبسيط التنفيذ المحدّد لأغراض تعليمية. لنشر هذا التطبيق بشكل آمن في بيئة مؤسسة واقعية، عليك تنفيذ التحسينات التالية:

  1. المصادقة الحقيقية: استبدِل القائمة المنسدلة "مبدّل الهوية" بموفّر هوية (IDP) قوي، مثل Google Identity Platform أو Okta أو Auth0. يجب أن يتحقّق تطبيقك من رمز المستخدم المميز وأن يستخرج هويته بشكل آمن قبل ضبط متغيّر جلسة قاعدة البيانات، ما يضمن عدم انتحال المستخدمين لهويتهم.
  2. أمان تجميع الاتصالات: عند استخدام ميزة تجميع الاتصالات، يمكن أن تبقى متغيرات الجلسة أحيانًا في طلبات المستخدمين المختلفة إذا لم تتم معالجتها بشكل صحيح. تأكَّد من أنّ تطبيقك يعيد ضبط متغيّر الجلسة (مثلاً، إعادة ضبط app.active_user) أو محو حالة الاتصال عند إعادة اتصال إلى مجموعة الاتصالات لمنع تسرُّب البيانات بين المستخدمين
  3. إدارة الأسرار: تشكّل كتابة بيانات اعتماد قاعدة البيانات بشكل ثابت خطرًا أمنيًا. استخدِم خدمة مخصّصة لإدارة الأسرار، مثل Google Secret Manager، لتخزين كلمات مرور قواعد البيانات وسلاسل الاتصال واستردادها بأمان في وقت التشغيل.

9- تَنظيم

بعد الانتهاء من هذا المختبر، لا تنسَ حذف مجموعة AlloyDB ونسختها.

يجب أن يؤدي ذلك إلى تنظيف المجموعة بالإضافة إلى مثيلاتها.

10. تهانينا

تهانينا! لقد نجحت في تعزيز الأمان على مستوى طبقة البيانات. حتى إذا كان رمز Python يتضمّن خطأً حاول تنفيذ print(all_salaries)، لن تعرض قاعدة البيانات أي نتائج لأليس.

الخطوات التالية

  • جرِّب ذلك باستخدام مجموعة البيانات الخاصة بك.
  • اطّلِع على مستندات AlloyDB AI.
  • يمكنك الاطّلاع على الموقع الإلكتروني Code Vipassana لمعرفة المزيد من ورش العمل.