Multi-Tenant Agent Isolation — הפרדת הרשאות בין לקוחות באותה מערכת סוכנים
מאת צוות מדיה דיל · 12.08.2026 · AI Security · 5 דק׳
כשכמה לקוחות חולקים תשתית Agent אחת, כל שכבה משותפת - Cache, מאגר וקטורי, אישורים - היא נקודת דליפה פוטנציאלית. מדריך לבידוד אמיתי בין דיירים.
סטארטאפ SaaS שבנה Agent שירות לקוחות משותף לכל הלקוחות שלו - כדי לחסוך בעלות תפעול נפרד לכל דייר (Tenant) - גילה בבדיקה פנימית שנציג של לקוח A קיבל, בתשובה לשאלה תמימה, קטע טקסט שמזכיר בבירור פרטים מחוזה של לקוח B. אף אחד לא "פרץ" כלום. הבעיה הייתה במטמון תשובות משותף שמפתח ה-Cache שלו לא כלל את מזהה הדייר, כך שתשובה שנשלפה עבור לקוח אחד "התאימה" סטטיסטית מספיק כדי להיחשב רלוונטית עבור השאלה של לקוח אחר. זהו הסיכון המרכזי בMulti-Tenant Agent Isolation: כשכמה לקוחות חולקים תשתית Agent אחת מטעמי עלות ותחזוקה, כל שכבה משותפת - Cache, זיכרון, מאגר וקטורי, הקשר שיחה - היא נקודת דליפה פוטנציאלית בין דיירים, גם בלי כל כוונה זדונית.
למה בידוד ברמת Prompt לא מספיק
הגישה הנפוצה והפגיעה ביותר היא לנסות לאכוף בידוד דרך הוראה בפרומפט המערכת: "ענה רק על שאלות של דייר X, אל תשתף מידע מדיירים אחרים". זו הגנה סמלית בלבד, כי היא מסתמכת על ציות המודל להוראה טקסטואלית, בזמן שכל התוכן הרלוונטי - כולל מה שלא אמור להיות נגיש - כבר נמצא איפשהו בשרשרת העיבוד (מאגר וקטורי משותף, זיכרון שיחה, Cache). כל מסלול שמביא נתונים לא-מסוננים לקרבת ה-Context מסוכן, גם אם ההוראה אומרת למודל "להתעלם" מהם - בדיוק כפי שדנו במדריך על Context Exfiltration, שבו מידע שנמצא ב-Context עלול לדלוף גם בלי הזרקה מכוונת. הבידוד האמיתי חייב לקרות לפני שהמידע מגיע ל-Context, לא בתוך ההוראה שמנחה מה לעשות איתו.
בידוד ברמת הנתונים: Row-Level Security ומרחבי שם נפרדים
כל מקור נתונים שה-Agent נוגע בו - מאגר וקטורי ל-RAG, זיכרון שיחה, Cache תשובות, לוגים - צריך לאכוף את מזהה הדייר כחלק בלתי נפרד מהשאילתה עצמה, לא כפילטר שמופעל אחרי השליפה. במסד נתונים רלציוני זה אומר Row-Level Security אמיתי ברמת ה-DB, לא רק בקוד האפליקציה. במאגר וקטורי (Pinecone, Weaviate, pgvector) זה אומר Namespace נפרד לכל דייר, לא שדה metadata שמסונן אחרי החיפוש - כי חיפוש סמנטי שמריץ Top-K על כל המאגר ורק אז מסנן לפי דייר עלול "לבזבז" את כל תוצאות ה-K הטובות ביותר על מסמכים שנחסמים בכל מקרה, וגם חושף את התוכן שלהם לפחות ברמת ניקוד (Score) שיכולה לרמז על תוכן שלא אמור להיות נגיש כלל.
// לא כך - סינון אחרי שליפה
const results = await vectorDB.query(embedding, { topK: 10 });
return results.filter(r => r.tenantId === currentTenant);
// אלא כך - בידוד בשכבת האחסון עצמה
const results = await vectorDB.query(embedding, {
namespace: `tenant-${currentTenant}`,
topK: 10
});
בידוד ברמת האישורים: Credentials שלא חוצים דייר
כשה-Agent פועל בשם דייר מסוים ומשתמש בכלים חיצוניים (שליחת מייל, קריאה ל-API של הדייר עצמו), חובה שכל האישורים (Credentials) שהוא משתמש בהם מוגבלים לאותו דייר בלבד - לא מפתח API משותף שמשרת את כל הדיירים ומזהה אותם רק דרך פרמטר בבקשה. אם מפתח משותף אחד דולף, כל הדיירים נחשפים בבת אחת; אם כל דייר מקבל אישורים מבודדים, דליפה מוגבלת לדייר בודד. זה מתקשר ישירות לעקרון Capability-Based Security: Capability שמונפק צריך להצביע במפורש על משאבי הדייר הספציפי, לא על "המערכת" בכללותה, כדי שגם שגיאת תכנות בקוד ה-Agent לא תוכל לגרום לו לגשת בטעות למשאב של דייר אחר - כי הוא פשוט לא מחזיק שום Capability שמצביע לשם.
בידוד ברמת החישוב: Noisy Neighbor ומכסות
מעבר לדליפת מידע, יש סיכון תפעולי נפרד: דייר אחד שמפעיל את ה-Agent בעומס גבוה חריג (בין אם בכוונה ובין אם בגלל תקלה) עלול לצרוך את כל תקציב ה-Rate Limit או משאבי החישוב המשותפים, ולפגוע בזמינות עבור כל שאר הדיירים - תופעת Noisy Neighbor הקלאסית. הפתרון הוא מכסות (Quotas) נפרדות לכל דייר, נאכפות ברמת התשתית ולא רק ברמת מדיניות - כך שגם אם דייר אחד "משתולל", השפעתו מוגבלת לתקציב שלו בלבד, ולא מדממת לשאר המערכת. תכנון נכון כולל גם ניטור נפרד לכל דייר, כדי לזהות התנהגות חריגה לפני שהיא הופכת לבעיית זמינות רחבה.
הבחירה הארכיטקטונית: תשתית משותפת מול מבודדת לחלוטין
הפתרון הכי בטוח - Sandbox נפרד לגמרי לכל דייר, ללא שום שכבה משותפת - הוא גם הכי יקר ומורכב לתפעול, ולרוב לא מוצדק כלכלית מתחת להיקף מסוים. הפתרון המעשי הנפוץ הוא מודל היברידי: תשתית חישוב משותפת (אותו קוד Agent, אותה תשתית הרצה), אך עם בידוד קפדני בכל שכבת נתונים ואישורים כפי שתואר למעלה. הקריטריון להחלטה מתי לעבור לבידוד מלא הוא רגישות הנתונים של הדיירים - לקוחות Enterprise עם דרישות רגולטוריות (בריאות, פיננסים) לרוב מצדיקים בידוד פיזי מלא, ואילו לקוחות SMB עם נתונים פחות רגישים יכולים לחיות בנוחות במודל המשותף-אך-מבודד-לוגית, ובלבד שהבידוד הלוגי אכן קשיח ולא רק תיאורטי.
בדיקה מעשית: תרגיל חדירה בין דיירים
הדרך היחידה לדעת בוודאות אם הבידוד הלוגי אכן אטום היא לנסות לפרוץ אותו בכוונה, לא לסמוך על עיצוב שנראה נכון על הנייר. תרגיל פשוט ויעיל: יוצרים שני חשבונות דייר בדיקה עם נתונים מזוהים וייחודיים בכל אחד (מסמך עם מחרוזת ייחודית, שם לקוח בדוי מובחן), ואז מריצים סדרת שאילתות מדייר A שמנוסחות כך שינסו לחלץ מידע שקשור לדייר B - ניסוחים ישירים ("מה יש לך על לקוח כזה") וניסוחים עקיפים (שאלות כלליות שעלולות לגרור תוצאה רלוונטית מהמאגר המשותף בטעות). כל תוצאה שמכילה שריד כלשהו מנתוני דייר B היא כשל בידוד שדורש תיקון מיידי, לא "מקרה קצה נדיר" - כי אם זה קרה בבדיקה יזומה, זה יקרה במוקדם או במאוחר גם בפעילות אמיתית. תרגיל כזה משתלב היטב עם מתודולוגיית Red Teaming הכללית, אך ראוי להריץ אותו כתרחיש ייעודי, לא רק כחלק כללי מבדיקת אבטחה רחבה יותר, ובאופן קבוע כחלק ממחזור הרצה תקופתי - לא כבדיקה חד-פעמית שמבוצעת רק לפני השקת המערכת.
תגיות: Multi-Tenant Isolation · tenant data leakage · RAG namespace · row-level security · SaaS agent architecture · noisy neighbor