הגדרה מהירה של SCA: Trivy filesystem mode ב-CI/CD

תלויות פגיעות מגיעות לריליז בלי לשים לב וצפות רק אצל הלקוח. אנחנו מגדירים Trivy filesystem mode כפתרון מלא: הבדיקה משתלבת בצינור הבנייה ומפסיקה גרסאות בעייתיות לפני שהן ממשיכות הלאה. טיפול בתקלות מפסיק להיות אירוע חירום, וחלקן של הבניות עם תלויות פגיעות יורד פי כמה.

היכולות שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1359
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    776
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח לוגו חברת AIDER
    פיתוח לוגו חברת AIDER
    1022
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113

Trivy filesystem mode: היכן נשברת בדיקת התלויות

בדיקת תלויות בעת בנייה נשברת לעתים קרובות לא בגלל הפגיעות עצמה, אלא בגלל אופן החיפוש שלה. סריקת הרכב התלויות תולים אחרי בניית image, כמשימה נפרדת וללא חסימה — pipeline הבנייה של פגיעויות נשאר ירוק פורמלית, ואל release יוצאת חבילה עם בעיה ידועה.

גם האפשרות ההפוכה גרועה: סריקה מלאה של image על כל commit מוסיפה דקות לכל בנייה, ואת השלב מכבים כדי לא לחכות.

Trivy filesystem mode מבטל את שתי הקיצוניות: הוא קורא manifests וקובצי lock ישירות מהעותק העבודה — package-lock.json, go.mod יחד עם go.sum, pom.xml, requirements.txt או poetry.lock — ללא image בנוי, גישה ל-registry והרשאות ל-daemon של קונטיינרים.

מספיק קובץ הרצה אחד ומטמון מקומי של בסיס הנתונים של פגיעויות, שמתעדכן בשלב נפרד ומשמש שוב בין הרצות, כולל בסביבה סגורה.

זה נשבר במאגרים מרובי-מודולים. ב-monorepo יש עשרות מודולים עם קובצי lock משלהם, חלק מהחבילות מגיעות באופן טרנזיטיבי דרך manifest אב, וחלק הן כלי פיתוח ובדיקות. בלי רשימת יעדים מפורשת וכללי החרגה, הסריקה או מרעישה על תלויות לא נתמכות, או מפספסת בשקט מודול שעץ התלויות לא הגיע אליו. התוצאה צפויה: הצוות מתרגל להתעלם מסטטוס אדום.

נבחן איך סוגרים את זה — איך להגדיר יעדי סריקה, ספי חומרה והתנהגות ביציאה, כך שהשלב יישאר מהיר ובאמת יעצור את הבנייה.

מה משתנה לאחר שילוב הבדיקה בבנייה

שילוב בדיקת תלויות בבנייה נותן שינויים מדידים, לא תחושת שקט. להלן צ'קליסט שלפיו אנו משווים את התוצאה בקבלה: כל סעיף נמדד לפי לוגים של ה-pipeline ודוחות הסורק, לא לפי מילים.

  • זמן בנייה — Trivy במצב filesystem מנתח manifests ועץ תלויות בלי להריץ קונטיינרים, ולכן התוספת לזמן הכולל היא עשרות שניות, לא דקות.
  • שיעור הפגיעויות שנתפסות — הבדיקה מתבצעת בכל commit, הממצא נרשם לפני הפריסה; בדוח רואים פילוח לפי רמות חומרה ומגמה בין releases.
  • סוג כשל שנעלם — מהפריסות נעלמות נפילות בגלל גרסאות ספריות לא תואמות או מבוטלות: אותן חוסמת הבנייה, לא התורן בלילה.
  • עלות השבתה — נמדדת בשעות אי-זמינות ובמספר החזרות ידניות; כשהבעיה נתפסת לפני הפריסה, אין צורך בשחזור כלל.
  • קריאות הדוח — אנו מגבילים את הפלט לממצאים חדשים ביחס לקו הבסיס, ולכן לדוח נכנס רק מה שהופיע בשינוי הנוכחי.
  • יכולת שחזור — אותה בדיקה מהנדס מריץ מקומית לפני commit, והתוצאה זהה לזו שה-pipeline רואה.

בנפרד אנו מגדירים ספים: לחסום את הבנייה ברמות קריטיות ולהתריע בשאר. בלי זה, רעש בדוח מביא במהירות לכך שמתחילים לעקוף את הבדיקה, והיא מפסיקה לתפוס משהו.

מצבי סריקה: מערכת קבצים, image, registry

נקודת הבדיקה קובעת מה הסורק בכלל מסוגל לראות. Trivy במצב filesystem קורא manifests וקובצי lock ישירות בספריית העבודה: זו האפשרות המהירה ביותר, שניות להרצה, מתאימה ל-pre-commit ולשלבים מוקדמים של הבנייה.

בדיקת image מוכן נותנת תמונה מלאה — שכבות, ספריות מערכת, חבילות שהותקנו מעל בסיס הבסיס. registry מרוחק של images בודק את מה שכבר פורסם ועובד בסביבה.

נקודת בדיקה מתי מתאימה מגבלות
מערכת קבצים פיתוח, pre-commit, בדיקת manifests לפני בנייה לא רואה חבילות משכבת הבסיס וספריות מערכת
image מוכן שער לפני פרסום, בדיקה של מה שבאמת יעלה דורש ארטיפקט בנוי ו-daemon מקומי, הרצה ארוכה יותר
registry מרוחק ביקורת של tags שפורסמו, סקירה תקופתית בלי בנייה מחדש אין גישה לשכבות מקומיות, יש תלות בזמינות ה-registry

מצבי הסריקה לא מחליפים זה את זה אלא משלימים: מערכת קבצים תופסת את הבעיה בכניסה, image מוכן — לפני פרסום, registry — אחרי. פער בין התוצאות הוא נורמלי, כי חלק מהתלויות מגיעות משכבת הבסיס ואינן נראות בקבצי הפרויקט.

מגבלה משותפת — עדכניות בסיס הנתונים של הפגיעויות. בלי עדכון סדיר של האינדקס, כל מצב נותן תמונה לא מהימנה, וכדאי לנעול את מטמון הבסיס לפי גרסה, אחרת הרצות בין בניות אינן ברות השוואה.

בחירת נקודה היא בחירת מקום השער: במקום שבו כשל עולה בזול יותר, שם שמים את הבדיקה.

שלבי הטמעת בדיקת הרכב התלויות

סדר העבודה נבנה כך שבדיקת הרכב התלויות תשתלב מעל ה-pipeline הקיים, לא במקומו. תחילה מתעדים את המצב הנוכחי, אחר כך מפעילים סריקה במצב דוח, ורק לאחר הרצת הרצה עושים את הבדיקה לחסומה — כך הבנייה לא תיעצר ביום הראשון, והצוות מספיק לטפל בהערות שנצברו.

  1. ביקורת pipeline. בודקים איך נבנים הארטיפקטים, היכן נמצאים ה-manifests וקובצי התלויות, אילו שלבים כבר קיימים ועל איזה מהם הבדיקה תשתלב בלי לשנות את הבנייה.
  2. סכימת בדיקות. קובעים כיסוי — עצי repositories ו-images בנויים — ואת נקודת ההרצה של Trivy filesystem mode: לפני הבנייה, כדי לא לבזבז זמן על commit בעייתי מראש.
  3. הגדרת ספי חסימה. מפרידים ממצאים לפי רמות: מה עוצר את הבנייה, מה עובר לדוח, מה נכנס לרשימת הסיכונים המאושרים עם סיבה ואחראי.
  4. הרצת הרצה במצב דוח. ההרצות הראשונות לא חוסמות, אלא אוספות סטטיסטיקה: כמה התראות, אילו חוזרות, היכן שגויות. לפיה מכיילים את הספים.
  5. מעבר למצב חוסם. מפעילים עצירה לפי רמות קריטיות ומנסחים הודעה למפתח כך שיהיה ברור מה בדיוק לעדכן או להחליף.
  6. העברת ההגדרות לצוות. מוסרים את הכללים, סכימת ההרצה, סדר עדכון רשימת ההחרגות ונקודת הפנייה בעת התראה — מכאן ה-pipeline עובד בלעדינו.

מה נשאר ב-repository לאחר ההטמעה

לאחר ההטמעה נשאר ב-repository לא סט פקודות חד-פעמיות, אלא ערכת ארטיפקטים. Trivy במצב סריקת מערכת קבצים מופעל מקובץ קונפיגורציה, ולכן התוצאה משוחזרת באופן זהה גם במכונה מקומית וגם ב-pipeline.

  • קונפיגורציית בדיקה — קובץ אחיד בשורש: יעדי סריקה, רמות חומרה, פורמטי דוחות, התנהגות הבנייה בעת ממצא.
  • כללי סינון התראות — רשימת החרגות, שבה מול כל אחת מצוינת ההצדקה: מדוע הפגיעות אינה רלוונטית לפרופיל השימוש של השירות.
  • מדיניות גישה — מי רשאי לערוך החרגות ולאשר חדשות, איך מנוהל היסטוריית השינויים ומי מבצע review.
  • נוהל עדכון בסיס הנתונים — תדירות הסנכרון, התנהגות הבנייה כשמקור אינו זמין, האחראי על העדכון.
  • תיעוד הבדיקות — פרק ב-README: איך להריץ בדיקה מקומית, מה משמעות בנייה שנפלה, היכן לראות את הדוח.
  • מטריצת חומרה — אילו רמות חוסמות את הבנייה, אילו עוברות לדוח ונכנסות לתוכנית העבודה.
  • תבנית לשירותים חדשים — סט קבצים בסיסי, כדי ש-repository חדש יתחיל עם בדיקות ולא ישיג את האחרים בדיעבד.

ערכה כזו שורדת החלפת מהנדסים והעברת פרויקט: הבדיקות מוקמות לפי התיעוד, לא לפי הזיכרון של עמית. בנפרד מקפידים שרשימת ההחרגות לא תתפח — בוחנים אותה מחדש לפי לוח זמנים ומסירים כללים שאיבדו את הבסיס.

מקרה בוחן: שיעור הבניות עם תלויות פגיעות ירד

הפרויקט — פלטפורמה של כמה עשרות שירותים עם pipeline בנייה משותף. בדיקת התלויות כאן נעשתה אחרי בניית ה-image: התוצאה הגיעה כעבור 10–12 דקות, כבר אחרי פרסום הארטיפקט, ונתפסה כמידע לעיון בלבד. שיעור הבניות בענף הראשי עם תלויות פגיעות ברמה גבוהה עמד על כ-27%.

מה עשינו

העברנו את הבדיקה לתחילת ה-pipeline והעברנו אותה ל-Trivy במצב סריקת מערכת קבצים. ההרצה עוברת על עץ קוד המקור — manifests וקובצי נעילת תלויות — לפני בניית ה-image, ולכן אינה ממתינה לארטיפקט מוכן ואינה דורשת גישה ל-registry.

בסיס הנתונים של הפגיעויות נשמר במטמון בין הרצות, הספים וההחרגות מוגדרים בקובץ קונפיגורציה, והדוח מופק בפורמט שמערכת בקרת הגרסאות מציגה כהערות ישירות ב-merge request. רק פגיעות קריטית עם תיקון זמין חוסמת — השאר עובר לתור המשימות.

תוצאה

לאחר המעבר, בדיקת שירות אחד אורכת כ-40 שניות במקום 12 דקות, והמפתח רואה את התוצאה בדקה הראשונה. שיעור הבניות עם תלויות פגיעות ירד מ-27% ל-4%, ושמונה מתוך עשרה תיקונים נכנסים לאותו merge request שבו נמצאה הפגיעות.

אימתנו את האפקט לפי יומני הבנייה והשוואת דוחות לפני ואחרי: חישבנו את שיעור הבניות הפגיעות לפי שבועות, לא לפי releases בודדים, כדי לשלול תוצאה חד-פעמית.

במה Trivy שונה מבדיקה בצד ה-registry?

בדיקה בצד ה-registry עובדת עם image שכבר נבנה — שכבות, בסיס חבילות, תוכן מערכת הקבצים. נקודת הכניסה אחת והיא האחרונה: מתאימה כמחסום סופי לפני פריסה, אבל האות מגיע אחרי הבנייה ופרסום ה-tag, כשההקשר של המשימה אצל המפתח כבר אבד.

Trivy במצב filesystem סורק את ספריית העבודה לפני הבנייה: קובצי lock ו-manifests של תלויות, Dockerfile, manifests של Kubernetes, קונפיגורציות וסודות שנכנסו ל-commit בטעות.

כיסוי הבדיקה עובר מהארטיפקט למקור — רואים את מה שרק עוד ייכנס ל-image, והבעיה נסגרת במיזוג הענף, לא אחרי הפרסום.

גם מחיר הטעות שונה. עבור registry, פגם שנמצא הוא image קיים שצריך לבנות מחדש, להוציא מחדש ולפרוס מחדש בסביבה. עבור מצב filesystem — תיקון שורה אחת ובדיקה שנפלה באותה משימה שבה רצים הבדיקות וה-linters; אין צורך בחזרה אחורה, כי ארטיפקט גרוע לא נוצר.

בדיקה בצד ה-registry לא מתבטלת: היא רואה בנייה אמיתית, כולל שכבות בסיס, ומכסה images שנבנו לא ב-pipeline שלנו. בנוסף היא בודקת מחדש ארטיפקטים שכבר נמצאים ב-registry, כשבבסיס הנתונים מופיעה פגיעות חדשה — ייתכן שאין כבר קוד מקור ל-tag ישן.

לסיכום: נקודות הבדיקה לא מחליפות זו את זו, אלא מחלקות תפקידים. מצב filesystem נותן כשל מוקדם ומשוב תוך דקות באותה הרצה שבה רצים הבדיקות, וה-registry נשאר המחסום האחרון לפני המסירה.

ספקות טכניים נפוצים בנוגע לבדיקת תלויות

הספקות של מהנדסים לגבי בדיקת תלויות מצטמצמים לארבעה נושאים: כמה התראות שווא יהיה צריך למיין ידנית, האם הניתוח עובד בסביבה סגורה, עד כמה הוא מאט את הבנייה ואיך מתעדכן בסיס הנתונים של הפגיעויות בלי שאילות חיצוניות.

להלן תשובות קצרות ברמת הקונפיגורציה. מדובר במצב trivy filesystem mode: הוא קורא manifests וקובצי נעילה ישירות מהעותק העבודה, בלי לדרוש image בנוי.

האם נטבע בהתראות שווא?

כל עוד המסננים לא הוגדרו — כן. אנו חוסמים ענפי תלויות שאינם בשימוש, מגבילים את הכלל לרמת חומרה ומנהלים קובץ החרגות, שבו לכל שורה יש מחבר ותאריך בחינה מחדש. אחרי זה נשארות ל-release בודדות של ממצאים, וכל אחת דורשת החלטה אמיתית.

האם זה עובד בסביבה סגורה?

כן. בסיס הנתונים של הפגיעויות נפרס ב-registry פנימי של ארטיפקטים, העדכון מתבצע לפי לוח זמנים, והניתוח עצמו לא פונה לרשת חיצונית. במקום שבו גישה חיצונית מותרת, הבסיס נמשך ישירות; בסביבה סגורה בודקים את שלמות המראה לפני ההרצה, אחרת תמונת מצב מיושנת מפספסת ממצאים בשקט.

עד כמה הניתוח מאט את הבנייה?

מורגש רק בלי מטמון. את השלב שמים אחרי התקנת התלויות, מריצים על קובצי נעילה שהשתנו, ושומרים את הבסיס מקומית ליד סוכן הבנייה. ב-release טיפוסי התוספת נמדדת בשניות; הדוח עובר כארטיפקט נפרד ולא חוסם את הבנייה עד שלא הוגדרו ספים.

נדון במשימה: מה לשלוח להערכת ה-pipeline

כדי לחזור עם הערכה ותוכנית עבודה, אנחנו צריכים נתוני פתיחה על ה-pipeline שלכם — בלעדיהם חישוב לוחות הזמנים הופך לניחושים. להלן רשימה של מה שאנחנו בדרך כלל מבררים בשיחה הראשונה; חלק מהסעיפים לעתים קרובות כבר נמצאים בהישג יד.

  • קישור ל-repository ולקובץ תיאור הבנייה (GitLab CI, GitHub Actions, Jenkinsfile) — ממנו רואים באיזה שלב הבדיקות רצות כעת והיכן ישתלב שלב הסריקה.
  • שפות ומנהלי תלויות: go.mod, package-lock.json, requirements.txt, pom.xml, composer.lock — מהם תלוי אילו מנתחים יפעיל Trivy filesystem mode וכמה זמן יארך המעבר.
  • דרישות לדוחות: צריך SARIF לפאנל המובנה, JSON לניתוח בסקריפטים או טבלה בארטיפקטים של הבנייה.
  • מדיניות פגיעויות: אילו רמות חומרה עוצרות את הבנייה ואילו רק נרשמות בלוג; האם יש החרגות וקובץ .trivyignore.
  • מגבלות סביבה: סביבה סגורה בלי פניות חיצוניות, registry images משלכם, proxy, מטמון מקומי של בסיסי פגיעויות.
  • נוהל טיפול בממצאים: מי אחראי על התיקון, תוך כמה זמן נסגרים קריטיים, איך מבוצעת חזרה אחורה במקרה של התראת שווא.
  • יעדים מספריים: כמה זמן נמשכת הבנייה כעת ואיזה מרווח זמן לשלב הסריקה אסור לנו לחרוג ממנו.

שלחו את נתוני הפתיחה האלה — נדון במשימה ונחזור עם הערכה ותוכנית עבודה: שלבים, מה משנים ב-pipeline, איך בודקים את התוצאה. אם אין איזה מהנתונים, נעזור למצוא היכן להשיג אותם.