1. סקירה כללית
במהלך הפיתוח של אפליקציות מבוססות-AI גנרטיבי, אנחנו שוכחים לעיתים קרובות את הרכיב הקריטי ביותר: בטיחות.
נניח שאתם רוצים ליצור צ'אט בוט למשאבי אנוש. אתם רוצים שהיא תענה על שאלות כמו "מה השכר שלי?" או "מה הביצועים של הצוות שלי?"
- אם אליס (עובדת רגילה) מבקשת, היא צריכה לראות רק את הנתונים שלה.
- אם Bob (מנהל) מבקש, הוא צריך לראות את הנתונים של הצוות שלו.
הבעיה
רוב הארכיטקטורות של RAG (יצירה משופרת באמצעות אחזור) מנסות לטפל בבעיה הזו בשכבת האפליקציה. הם מסננים את המקטעים אחרי שהם מאחזרים אותם, או שהם מסתמכים על כך שמודל ה-LLM יפעל בצורה תקינה. זה שברירי. אם הלוגיקה של האפליקציה נכשלת, מתרחשת דליפת נתונים.
הפתרון
העברת האבטחה אל שכבת מסד הנתונים. באמצעות אבטחה ברמת השורה (RLS) ב-PostgreSQL ב-AlloyDB, אנחנו מוודאים שמסד הנתונים מסרב באופן פיזי להחזיר נתונים שהמשתמש לא מורשה לראות – לא משנה מה ה-AI מבקש.
במדריך הזה ניצור את הכספת הפרטית: עוזרת מאובטחת למשאבי אנוש שמשנה את התשובות שלה באופן דינמי על סמך המשתמש שמחובר.

הארכיטקטורה
אנחנו לא בונים לוגיקת הרשאות מורכבת ב-Python. אנחנו משתמשים במנוע מסד הנתונים עצמו.
- הממשק: אפליקציית Streamlit פשוטה שמדמה התחברות.
- המוח: AlloyDB AI (תואם ל-PostgreSQL).
- המנגנון: אנחנו מגדירים משתנה סשן (
app.active_user) בתחילת כל עסקה. מדיניות מסד הנתונים בודקת באופן אוטומטי טבלתuser_roles(שמשמשת כספק הזהויות שלנו) כדי לסנן את השורות.
מה תפַתחו
אפליקציה מאובטחת של עוזר משאבי אנוש. במקום להסתמך על לוגיקה של אפליקציה כדי לסנן נתונים רגישים, אתם יכולים להטמיע אבטחה ברמת השורה (RLS) ישירות במנוע מסד הנתונים של AlloyDB. כך אפשר לוודא שגם אם מודל ה-AI שלכם ינסה לגשת לנתונים לא מורשים, מסד הנתונים יסרב להחזיר אותם.
מה תלמדו
תלמדו:
- איך מעצבים סכמה ל-RLS (הפרדה בין נתונים לבין זהות).
- איך כותבים מדיניות PostgreSQL (
CREATE POLICY). - איך לעקוף את ההחרגה 'בעלים של הטבלה' באמצעות
FORCE ROW LEVEL SECURITY. - איך ליצור אפליקציית Python שמבצעת 'החלפת הקשר' עבור משתמשים.
דרישות
2. לפני שמתחילים
יצירת פרויקט
- ב-Google Cloud Console, בדף לבחירת הפרויקט, בוחרים או יוצרים פרויקט ב-Google Cloud.
- מוודאים שהחיוב מופעל בפרויקט ב-Cloud. כך בודקים אם החיוב מופעל בפרויקט.
- תשתמשו ב-Cloud Shell, סביבת שורת פקודה שפועלת ב-Google Cloud. לוחצים על 'הפעלת Cloud Shell' בחלק העליון של מסוף Google Cloud.

- אחרי שמתחברים ל-Cloud Shell, אפשר לבדוק שכבר בוצע אימות ושהפרויקט מוגדר למזהה הפרויקט שלכם באמצעות הפקודה הבאה:
gcloud auth list
- מריצים את הפקודה הבאה ב-Cloud Shell כדי לוודא שפקודת gcloud מכירה את הפרויקט.
gcloud config list project
- אם הפרויקט לא מוגדר, משתמשים בפקודה הבאה כדי להגדיר אותו:
gcloud config set project <YOUR_PROJECT_ID>
- מפעילים את ממשקי ה-API הנדרשים: לוחצים על הקישור ומפעילים את ממשקי ה-API.
אפשר גם להשתמש בפקודת gcloud. אפשר לעיין במאמרי העזרה בנושא פקודות gcloud ושימוש בהן.
gcloud services enable \
alloydb.googleapis.com \
compute.googleapis.com \
cloudresourcemanager.googleapis.com \
servicenetworking.googleapis.com \
aiplatform.googleapis.com
נקודות חשובות ופתרון בעיות
תסמונת 'פרויקט הרפאים' | הפעלת את הפקודה |
מחסום בחיוב | הפעלתם את הפרויקט, אבל שכחתם להוסיף חשבון לחיוב. AlloyDB הוא מנוע עם ביצועים גבוהים, והוא לא יופעל אם 'מיכל הדלק' (החיוב) ריק. |
השהיה של הפצת API | לחצת על 'הפעלת ממשקי API', אבל בשורת הפקודה עדיין מופיעה ההודעה |
מכסה | אם אתם משתמשים בחשבון ניסיון חדש לגמרי, יכול להיות שתגיעו למכסה אזורית של מופעי AlloyDB. אם הפעולה |
3. הגדרת מסד נתונים
בשיעור ה-Lab הזה נשתמש ב-AlloyDB כבסיס הנתונים של נתוני הבדיקה. הוא משתמש באשכולות כדי להכיל את כל המשאבים, כמו מסדי נתונים ויומנים. לכל אשכול יש מופע ראשי שמספק נקודת גישה לנתונים. הטבלאות יכילו את הנתונים בפועל.
ניצור אשכול, מכונה וטבלה של AlloyDB שבהם ייטען מערך הנתונים של הבדיקה.
- לוחצים על הלחצן או מעתיקים את הקישור שלמטה לדפדפן שבו המשתמש מחובר למסוף Google Cloud.
- אחרי שהשלב הזה יסתיים, המאגר ישוכפל לעורך המקומי של Cloud Shell ותוכלו להריץ את הפקודה שלמטה מתוך תיקיית הפרויקט (חשוב לוודא שאתם בספריית הפרויקט):
sh run.sh
- עכשיו משתמשים בממשק המשתמש (לוחצים על הקישור במסוף או על הקישור 'תצוגה מקדימה באינטרנט' במסוף).
- כדי להתחיל, מזינים את הפרטים של מזהה הפרויקט, האשכול ושמות המופעים.
- אתם יכולים ללכת לשתות קפה בזמן שהיומנים מתגללים, וכאן תוכלו לקרוא איך זה קורה מאחורי הקלעים. התהליך יימשך כ-10 עד 15 דקות.
נקודות חשובות ופתרון בעיות
הבעיה של 'סבלנות' | אשכולות של מסדי נתונים הם תשתית כבדה. אם תרעננו את הדף או תסיימו את הסשן ב-Cloud Shell כי נראה שהוא נתקע, יכול להיות שתקבלו מופע 'רפאים' שהוקצה באופן חלקי ואי אפשר למחוק אותו בלי התערבות ידנית. |
חוסר התאמה באזור | אם הפעלתם את ממשקי ה-API ב- |
Zombie Clusters | אם השתמשתם בעבר באותו שם לאשכול ולא מחקתם אותו, יכול להיות שהסקריפט יציין שהשם של האשכול כבר קיים. שמות האשכולות חייבים להיות ייחודיים בפרויקט. |
פסק זמן ב-Cloud Shell | אם הפסקת הקפה שלכם נמשכת 30 דקות, יכול להיות ש-Cloud Shell יעבור למצב שינה וינתק את התהליך |
4. הקצאת הרשאות לסכימה
בשלב הזה נסביר על:

אלה הפעולות המפורטות שצריך לבצע:
אחרי שמפעילים את האשכול ואת המופע של AlloyDB, עוברים אל עורך ה-SQL של AlloyDB Studio כדי להפעיל את תוספי ה-AI ולספק את הסכימה.

יכול להיות שתצטרכו לחכות עד שהמופע שלכם יסיים את תהליך היצירה. אחרי שזה קורה, נכנסים ל-AlloyDB באמצעות פרטי הכניסה שיצרתם כשנוצר האשכול. משתמשים בנתונים הבאים כדי לבצע אימות ל-PostgreSQL:
- שם משתמש : "
postgres" - מסד נתונים : "
postgres" - סיסמה:
alloydb(או כל סיסמה אחרת שהגדרתם בזמן היצירה)
אחרי שתעברו בהצלחה את תהליך האימות ב-AlloyDB Studio, תוכלו להזין פקודות SQL בכלי העריכה. אפשר להוסיף כמה חלונות של Editor באמצעות סימן הפלוס משמאל לחלון האחרון.

מזינים פקודות ל-AlloyDB בחלונות של כלי העריכה, ומשתמשים באפשרויות Run (הפעלה), Format (עיצוב) ו-Clear (ניקוי) לפי הצורך.
צור טבלה
צריך שתי טבלאות: אחת לנתונים הרגישים (עובדים) ואחת לכללי הזהות (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. הפעלה ואכיפה של אבטחה
עכשיו מפעילים את המגנים. בנוסף, ניצור משתמש כללי בשם App User (משתמש באפליקציה) שהקוד שלנו ב-Python ישתמש בו כדי להתחבר.
מריצים את הצהרת ה-SQL הבאה מ-AlloyDB Query Editor:
-- 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 (משתמש על) וצפייה בכל הנתונים. | למה הבדיקה נכשלת: כברירת מחדל, RLS לא חל על בעלי הטבלה או על משתמשי-על. הם עוקפים את כל כללי המדיניות.פתרון בעיות: אם נראה שכללי המדיניות שלכם 'מקולקלים' (מאפשרים הכול), בדקו אם אתם מחוברים בתור |
6. יצירת מדיניות הגישה
נגדיר שני כללים באמצעות משתנה סשן (app.active_user) שנגדיר מקוד האפליקציה שלנו בהמשך.
מריצים את הצהרת ה-SQL הבאה מ-AlloyDB Query Editor:
-- 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). אנחנו צריכים את המשתמש באפליקציה (למשל, Alice).Fix: Always use a custom namespace like app.variable_name. |
שוכחים את הפרמטר | בעיה: אם המשתנה לא מוגדר, השאילתה קורסת עם שגיאה.פתרון: הפונקציה current_setting('...', true) מחזירה NULL במקום לקרוס, וכך מתקבלות 0 שורות בצורה בטוחה. |
7. יצירת אפליקציית Chameleon
נשתמש ב-Python וב-Streamlit כדי לדמות את הלוגיקה של האפליקציה.

פותחים את Cloud Shell Terminal במצב עריכה, ועוברים לתיקיית הבסיס או לספרייה שבה רוצים ליצור את האפליקציה. יוצרים תיקייה חדשה.
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 בטרמינל. |
8. אימות של אפס אמון
כדאי לנסות את האפליקציה כדי לוודא שההטמעה של מודל אפס אמון בוצעה:
בוחרים באפשרות Alice: היא אמורה לראות שורה אחת (של עצמה).

בוחרים באפשרות 'Bob': הוא אמור לראות 3 שורות (כולם).

למה זה חשוב לסוכני AI
תארו לעצמכם שמקשרים את המודל למסד הנתונים הזה. אם משתמש יבקש מהמודל: "תסכם את כל ביקורות הביצועים", המודל ייצור את הפקודה SELECT performance_review FROM employees.
- בלי RLS: המודל מאחזר את הביקורות הפרטיות של כולם ומעביר אותן לאליס.
- עם RLS: המודל מריץ בדיוק את אותה שאילתה, אבל מסד הנתונים מחזיר רק את הביקורת של אליס.
זהו AI עם מודל אבטחה של אפס אמון. אתם לא סומכים על המודל שיסנן את הנתונים, ואתם מכריחים את מסד הנתונים להסתיר אותם.
העברה לסביבת הייצור
הארכיטקטורה שמוצגת כאן מתאימה לסביבת ייצור, אבל ההטמעה הספציפית פשוטה יותר כדי להקל על הלמידה. כדי לפרוס את התוסף בצורה מאובטחת בסביבת Enterprise אמיתית, צריך להטמיע את השיפורים הבאים:
- אימות אמיתי: מחליפים את התפריט הנפתח 'החלפת זהות' בספק זהויות חזק כמו Google Identity Platform, Okta או Auth0. האפליקציה צריכה לאמת את הטוקן של המשתמש ולחלץ את הזהות שלו בצורה מאובטחת לפני הגדרת משתנה הסשן של מסד הנתונים, כדי לוודא שהמשתמשים לא יוכלו לזייף את הזהות שלהם.
- בטיחות של מאגר חיבורים: כשמשתמשים במאגרי חיבורים, לפעמים משתני סשן נשמרים בין בקשות שונות של משתמשים אם לא מטפלים בהם בצורה נכונה. מוודאים שהאפליקציה מאפסת את משתנה הסשן (לדוגמה, RESET app.active_user) או מנקה את מצב החיבור כשמחזירים חיבור למאגר כדי למנוע דליפת נתונים בין משתמשים.
- ניהול סודות: קידוד קשיח של פרטי הכניסה למסד נתונים הוא סיכון אבטחה. כדי לאחסן ולאחזר את הסיסמאות למסד הנתונים ואת מחרוזות החיבור בצורה מאובטחת בזמן הריצה, מומלץ להשתמש בשירות ייעודי לניהול סודות כמו Google Secret Manager.
9. הסרת המשאבים
אחרי שמסיימים את ה-Lab הזה, חשוב למחוק את אשכול AlloyDB ואת המכונה.
הוא צריך לנקות את האשכול יחד עם המכונות שלו.
10. מזל טוב
מזל טוב! העברתם בהצלחה את האבטחה לשכבת הנתונים. גם אם בקוד Python יש באג שמנסה לבצע print(all_salaries), מסד הנתונים לא יחזיר לעינת כלום.
השלבים הבאים
- אתם יכולים לנסות את זה עם קבוצת נתונים משלכם.
- כדאי לעיין במסמכי התיעוד של AlloyDB AI.
- באתר Code Vipassana אפשר למצוא סדנאות נוספות.