הרשאות גישה עודפות: היכן נשברות מדיניות IAM של S3
הרשאות שניתנו למשימה «לזמן מוגבל» כמעט ואינן נשללות לעולם. לחשבון שירות מוסיפים s3:GetObject על כל ה-bucket, כדי לייצא דוח באופן חד-פעמי: הדוח יוצא, המשימה נסגרת — אך הכלל נשאר במדיניות. כעבור כמה מהדורות יש עשרות רשומות «זמניות» כאלה, ואיש כבר לא זוכר מה כל אחת מהן משרתת.
ניטור רגיל לא יתפוס זאת: הוא מסתכל על קודי תגובה, זמן תגובה וזמינות, ואילו גישה עודפת אינה מייצרת שגיאות או קפיצות. הבקשות תקינות, התגובות מוצלחות, הגרפים ישרים — אין התראות, אף שהנתונים כבר מזמן נקראים על ידי מי שאינם מיועדים לו. גישה ציבורית לאובייקטים מסוכנת בדיוק בכך: ה-storage פועל כשורה, אך הדליפה כבר התרחשה.
הכול נשבר בשלושה מקומות אופייניים. תו wildcard ב-Resource או ב-Action — המדיניות נראית צרה לפי שמה, אך מכסה את כל ה-bucket. היעדר Condition לפי מקור הבקשה: הכלל אינו קשור לרשת או לתפקיד ספציפי. ו-ACL ברמה של אובייקט בודד, שמרחיב גישה בניגוד למדיניות ה-bucket, אם לא מוצב איסור מפורש בשום מקום.
אין לטפל בכך בניקוי חד-פעמי, אלא במשטר מתמשך: עקרון ההרשאה המינימלית בתוספת ביקורת גישה תקופתית ל-storage — הצלבת ההרשאות שניתנו עם אלו שבשימוש בפועל לפי לוגי הפניות. אנו מפרטים כיצד לבנות זאת כך ש«זמני» יפסיק להפוך לקבוע.
מה מפסיק להישבר לאחר מדיניות גישה מחמירה
איסור מפורש במדיניות ה-bucket גובר על כל הרשאה, ולכן תחילה סוגרים את כל המעגל, והגישה ניתנת נקודתית. המדיניות על ה-bucket אחראית למה שמותר לעשות עם האובייקטים: לפי prefix, מאילו רשתות, ורק בערוץ מאובטח. כללי IAM אחראים למי זה נגיש. כל עוד הרמות מעורבבות, ההרשאות תלויות על החשבון ולא על התפקיד.
| סוג הכשל | כיצד נוצר | מה קרה לאחר המדיניות |
|---|---|---|
| גישה נשארת לאחר פיטורים | הרשאות על חשבון אישי | התפקיד הוסר מהקבוצה — הגישה נסגרה |
| נתונים דולפים מהמעגל הסגור | דגל גישה ציבורית על האובייקט | גישה ציבורית נאסרה ברמת ה-bucket |
| קריאת prefixes של אחרים | מדיניות רחבה אחת לכולם | הגישה ניתנה לפי prefix ותפקיד |
מתן הגישה הופך לפעולה של דקות: תפקיד עם סט ההרשאות הנדרש מתואר כקוד ב-Terraform, ונותר רק להקצות אותו לעובד. שלילת הרשאות בעת פיטורים — הסרה אחת מהקבוצה, ונסגרים גם מפתחות ארוכי-טווח וגם טוקנים זמניים. החלפת תפקיד של עובד בתוך הצוות מפסיקה לדרוש בקשה חדשה: ההרשאות נבנות מחדש בעת ההעברה.
חלק הנתונים במעגל הסגור גדל לא בזכות בדיקות ידניות, אלא מפני שגישה ציבורית נאסרה על ה-bucket עצמו ולא ניתן לעקוף אותה בדגל מקרי. נעלמים לחלוטין: קריאת prefixes של אחרים, גישה לאחר פיטורים, ואובייקט בגישה פתוחה עקב שגיאה בסקריפט.
דרכי הפרדת גישה: השוואת אפשרויות
הפרדת גישה ב-object storage נפתרת בארבע רמות — ממדיניות IAM של הספק ועד בדיקה עצמאית לפני הנפקת קישור. הבחירה תלויה במי שמבקש את האובייקט: שירות פנימי, שותף חיצוני או הדפדפן של משתמש הקצה.
אף רמה אינה פותרת את המשימה לחלוטין. כללי הספק אינם מכירים את הלוגיקה העסקית שלכם, ובדיקה עצמאית אינה מגנה מפני עקיפה דרך כתובת ישירה. לכן משלבים בין הרמות: בבסיס יסוד נוקשה, ומעליו חריגים נקודתיים.
| אפשרות | מתי מתאימה | מגבלות |
|---|---|---|
| כללי הספק (IAM) | חשבונות שירות בתוך הפלטפורמה, גישה לקריאה או כתיבה בשלמותה | אין הקשר של האפליקציה, ההרשאות ניתנות בקבוצות רחבות |
| כללים ברמת ה-bucket | שיתוף ציבורי או עם שותפים, סט תנאים אחד לכל ה-container | הגרנולריות עד לאובייקט בודד מוגבלת, הבידוד מושג על ידי פיצול buckets |
| כללים ברמת האובייקט וקישורים זמניים לקבצים | הנפקת קובץ למשתמש ספציפי לזמן קצר, בלי חשיפת מפתחות | לא ניתן לשלול את הקישור לפני תום תקופתו: בעת דליפה הוא עובד אצל כל אחד |
| שכבת הרשאה עצמאית לפני הנפקת הקישור | תפקידים, בעלים, שוכרים, ביקורת של כל פנייה | שירות נוסף במסלול הקריטי — נדרש מרווח בעמידות לתקלות |
כיצד לבחור רמה
אם הכלל מתואר בתנאי אחד, החזיקו אותו בצד הספק. אם ההחלטה תלויה בנתונים במסד הנתונים שלכם — הוציאו את הבדיקה לשכבה עצמאית, והפכו את הקישור הזמני לקצר-מועד.
סדר ההטמעה: ממיפוי ועד מסירה
מתחילים בעובדות ולא בתבנית: המיפוי מראה מי באמת פונה ל-storage — שירותים, אנליטיקה, קבלנים חיצוניים. בלי המפה הזו, סכמת התפקידים נבנית באקראי, והחלפת המדיניות הופכת לחיפוש אחר הגישה שנכשלה לפי הלוגים.
- מיפוי הרשאות גישה. מייצאים את ה-bucket policy הפעילות, תפקידי IAM, ACL ציבוריים וקישורים פעילים לאובייקטים, ומצליבים עם לוגי הפניות. בפלט — מפה של «מי, לאיזה bucket, אילו פעולות» ורשימת הרשאות מיותרות.
- סכמת תפקידים. מתכננים תפקידים לפי פונקציות — קריאת אנליטיקה, כתיבה מהשירות, החלפה עם קבלן לפי prefix נפרד — ולא לפי אנשים ספציפיים. לכל תפקיד סט פעולות מינימלי ותנאי יישום.
- הגדרת מדיניות. הגבלה לפי prefixes, תנאי על מקור הבקשה, הצפנה מחייבת, איסור גישה ציבורית. איסור מפורש גובר על הרשאות שניתנו במקרה.
- בדיקה על עותק של הנתונים. מעגל בדיקה על עותק אנונימי: מריצים קריאה, כתיבה, מחיקה ויצירת קישורים. בנפרד — בדיקות שליליות: הגישה סגורה היכן שצריכה להיות סגורה.
- מעבר ללא השבתה. מדיניות ישנות וחדשות פועלות במקביל, ומחליפים לפי שירותים עם חלון תצפית לפי לוגי הכשלים. כל שלב ניתן לחזור בו על ידי החזרת הגרסה הקודמת של התצורה.
- נוהל. קובעים מי מנפיק גישה, לכמה זמן, כיצד מתבצעת סקירה ומה לעשות בעת פיטורים או החלפת קבלן. הכללים נשמרים ב-repository, והשינויים — דרך בדיקה.
- מסירה. תיעוד, סכמות תפקידים, תצורות ב-repository וניטור כשלי גישה — כדי שהצוות ימשיך לעבוד באופן עצמאי.
מה נשאר בידיכם: תצורות ונהלים
אנו מוסרים לא ארכיון של הגדרות, אלא מעגל גישה פעיל, שהצוות שלכם יוכל לקרוא ולשנות בלעדינו. תצורות של מדיניות IAM ו-bucket policies נמצאות ב-repository לצד קוד התשתית: השינוי עובר בדיקה ונשאר בהיסטוריה — רואים מי ומתי הרחיב את ההרשאות.
- מטריצת גישה — טבלה «סובייקט → משאב → פעולה → תנאי»: ממנה רואים מדוע לשירות או לעובד מסוים יש הרשאה ל-prefix הנדרש של ה-bucket, והיכן גבול סמכותו.
- סכמת תפקידים — אילו תפקידים קיימים, במה הם שונים, אילו ניתנים לאנשים דרך פדרציה ואילו — לשירותים; בנפרד מסומנים תפקידים עם הרשאה לשנות את המדיניות עצמה.
- תצורות פעילות — קבצי מדיניות מגורסאים עם שמות בעלי משמעות והערות במקום ייצוא מהקונסולה.
- נוהל הנפקת הרשאות — סדר: בקשה, אישור על ידי בעל הנתונים, תוקף, שלילה אוטומטית; לתפקידים קבועים — סקירה תקופתית.
- תיעוד גישה — שמות buckets, נקודות כניסה, סדר רוטציה של אישורי גישה ושגיאות אופייניות בפנייה.
- תיאור האינטגרציות — אילו מערכות פונות ל-storage, עם אילו הרשאות ומה יקרה להן בעת החלפת מדיניות.
- נוהל בדיקה — סט הפניות שאמור לעבור, וסט שאמור לקבל סירוב.
בפלט נשארת מערכת ניתנת לניהול, ולא הגדרה חד-פעמית: גישה לקבלן חדש ניתנת לפי נוהל, ובבירור תקרית יש יומן שינויים ונקודת חזרה ברורה.
מקרה בוחן: כיצד סגרו גישה ציבורית ל-object storage
מה היה לפני השינויים
את הביקורת התחילו במיפוי: עברו על כל ה-buckets בכל החשבונות והצליבו bucket policy, ACL והגדרות חסימת גישה ציבורית. התוצאה — 17% מה-buckets החזירו אובייקטים באופן אנונימי: חלק נפתחו לצורך השקה מהירה ולא נסגרו, וחלק — כשניתנו לקבלנים קישורים «לזמן מוגבל».
צרה נפרדת — ירושה: עריכת המדיניות של bucket אחד פתחה בשקט שכנים, וב-storage תואם S3 MinIO הדבר נתפס רק בהצלכה ידנית.
התהליכים הוסיפו משלהם. ההרשאות ניתנו דרך טיקטים: 2-3 ימים מהבקשה ועד גישה פעילה, והשלילה בעת פיטורים נמשכה עד שבוע — המפתחות כל אותו הזמן נשארו פעילים. התמיכה קיבלה כמה עשרות פניות בחודש רק בנושא גישות, ומחציתן — «תנו לי את אותו הדבר שיש לקולגה».
מה שינו ומה קיבלו
את הפומביות סגרו בשתי רמות: בחשבון הפעילו חסימת מדיניות ציבורית, ולשירותים עם קהל חיצוני אמיתי השאירו תנאים נקודתיים — רשימת מקורות מפורשת ותוקף קצר לקישורים. ההרשאות הועברו לתפקידים עם מאפיינים: הגישה נקבעת לפי תגים של המשתמש ושל ה-bucket, ולא על ידי מנייה ידנית. צוות חדש מקבל את הסט הנדרש אוטומטית, ובהחלפת תפקיד ההרשאות הישנות מוסרות יחד עם התג.
את ההנפקה הפכו לשירות עצמי דרך קטלוג תפקידים. המדדים לאחר מכן: שיעור ה-buckets הנגישים אנונימית — אפס, ביקורת הרשאות מלאה אורכת הרצה אחת של סקריפט במקום שבוע של הצלבה ידנית, והפניות לתמיכה בנושא גישות הצטמצמו פי חמישה.
במה נבדלות מדיניות IAM של S3 מכללי ה-bucket
ל-object storage, לדוגמה Amazon S3, שתי רמות גישה בלתי תלויות. מדיניות IAM מוצמדת לסובייקט — משתמש, תפקיד, חשבון שירות — ואחראית למה שסובייקט זה רשאי לעשות: אילו פעולות ועל אילו משאבים.
כלל ה-bucket מוצמד ל-bucket עצמו, מכיל ציון של הסובייקט ומתאר את הצד ההפוך — מי מבחוץ פונה לנתונים, כולל חשבונות אחרים.
בעת חפיפה, המודלים מצטברים לפי ההיגיון: מותר אם מותר לפחות במקום אחד, אסור אם אסור ולו במקום אחד. ההרשאות מתאחדות, ולאיסור מפורש יש עדיפות עליונה: Deny אחד במדיניות IAM או בכלל ה-bucket גובר על כל מספר של Allow, כולל אלו שניתנו דרך קבוצה. זהו בדיוק תעדוף האיסור — מחסום שלא ניתן לעקוף על ידי הוספת הרשאה חדשה.
מכאן ההפרדה המעשית. בתוך חשבון אחד די בתפקידי IAM: צוותים ושירותים פנימיים מקבלים גישה דרך תפקיד, ולא דרך מפתחות סטטיים. כלל ה-bucket נדרש היכן שהפנייה מגיעה מבחוץ — חשבון שותף, שירות חיצוני, הגשת תוכן סטטי. בסכמה משולבת, המגבלות ברמת הארגון משמשות גבול עליון שאיש מהמודלים לא ירחיב.
מגדירים מהאיסורים: תחילה סוגרים גישה ציבורית וייצוא ללא הצפנת הערוץ, ואחר כך מוסיפים הרשאות לפי prefixes ותפקידים. בירור הסירוב מתנהל באותו סדר — IAM, כלל ה-bucket, מגבלות הארגון; לרוב חוסם את הגישה לא Allow חסר, אלא Deny מפורש באחת השכבות.
ספקות טכניים בנוגע להפרדת גישה
ספקות בנוגע להפרדת גישה נוגעים בדרך כלל לא למדיניות עצמה, אלא לאופן שבו היא תסתדר עם אינטגרציות שכבר פועלות ומה יקרה בעת שגיאה בכללים. להלן חמש שאלות טכניות שנשאלות לרוב לפני ההתחלה.
האם מדיניות IAM חדשה תשבור אינטגרציות פעילות?
תחילה מתעדים את הפניות הנוכחיות ובונים מפה: מי פונה לאילו prefixes. לאחר מכן מנפיקים הרשאות מפורשות ומפעילים איסור כברירת מחדל — שירות שלא נכנס למפה נופל בבדיקה, ולא בפרודקשן.
האם ניתן להנפיק גישה לאובייקטים בודדים ולא לכל ה-storage?
כן: המדיניות מתארת גם prefixes וגם מפתחות ספציפיים. להנפקה נקודתית מתירים אובייקט אחד, ולחיתוכים (selections) — prefix עם תנאי לפי שם. הקבלן מקבל בדיוק את הקבצים הנדרשים.
כיצד לתת גישה לקבלנים חיצוניים מבלי לחלק מפתח משותף?
לחיצוניים מנפיקים משתמש או תפקיד נפרד עם הגבלה לפי תוקף וטווח כתובות. הגישה נשללת בעריכה אחת, וההיסטוריה של הפניות נשארת בלוגים.
כיצד לוודא שהכללים פועלים בדיוק כמתוכנן?
לאחר היישום מריצים תרחישים: מפתחות שירות, מפתחות קבלן, בקשה אנונימית, בקשה ל-prefix שכן. את התגובה הצפויה — אישור או סירוב — מתעדים, כדי לתפוס רגרסיה בשינוי הבא.
מה יקרה לנתונים אם כלל ישלול הרשאות נדרשות?
הנתונים לא ייפגעו: משתנה רק התגובה לבקשה. החזרה לאחור — החזרת הגרסה הקודמת של המדיניות, עניין של דקות, ללא ייצוא והעלאה מחדש של אובייקטים.
נדון במשימה: הפרדת גישה ל-storage
הערכת העבודה בנושא גישה ל-storage מבוססת לא על תיאור כללי, אלא על מצב המדיניות בפועל. כל עוד לא רואים מי ובאיזה תפקיד קורא את הנתונים היום, כל לוח זמנים יהיה ניחוש — לכן אנו מבקשים לשלוח מספר ארטיפקטים, ועל פיהם אנו בונים תוכנית:
- ייצוא של הכללים הפעילים: bucket policies, מדיניות IAM של תפקידים ומשתמשים, וכן ACL אם הם עדיין בשימוש;
- מפה של ה-storages: ה-buckets, ייעודם, אילו מערכי נתונים וכמה רגישים מונחים בהם;
- רשימת השירותים והאפליקציות בציון התפקידים שדרכם הם פונים ל-storage, כולל אינטגרציות חיצוניות;
- דרישות להפרדה: למי ולאיזה prefix נדרשת גישה, היכן חשובות הגבלות לפי רשת, זמן או מקור הבקשה;
- הגדרות הלוגינג של הפניות: לאן נכתבים אירועי הגישה וכמה זמן הם נשמרים;
- מגבלות מצדכם: חלונות תחזוקה, נוהל אישור עריכות, מי מאשר שינויים בפרודקשן.
בתגובה נחזור עם תוכנית הטמעה: סכמת ירושת הגישות, חלוקה לפי תפקידים למשימות אמתיות של השירותים, טיוטות מדיניות מוכנות לצד תצורת השירות, וסדר פריסה עם נקודות חזרה.
הצעד הראשון אורך מעט ומניב תוצאה מיד:
- מיפוי: מאחדים את כל הכללים לטבלה אחת «מי — מה — מאיפה».
- תיעוד גישות עודפות ומקומות שבהם ההרשאות רחבות מהנדרש.
- הגדרת לוגינג וסביבת בדיקה שבה נבדקות עריכות בלי סיכון לפרודקשן.
- מסירת תוכנית ההטמעה ותיאום סדר הפריסה.
תארו את המשימה וצרפו את מה שיש בהישג יד — נחזור עם הערכה ותוכנית.







