משינה אויסלערן – או בקיצור: Machine Learning

Machine Learning הוא תחום שאמנם קיים בערך משנות ה-60, אך שהתפתח בעיקר ב 10-15 השנים האחרונות.

מנקודת מבט אחת, Machine Learning (בקיצור: ML) הוא כלי שמאפשר לפתור בעיות תוכנה, שלא ניתן לפתור בדרך הרגילה – קרי: בעזרת משפטי if ולולאות for.
ארתור סמואל, החלוץ בתחום תיאר זאת כ "give computers the ability to learn without being explicitly programmed".

כמובן שיש בשכבות הנמוכות של פתרונות ה ML הרבה משפטי if ולולאות for, אך ML מספק שיטה מתמטית/סטטיסטית המאפשרת לחשוב בפרדיגמה שונה של "תכנות" על הבעיות האלה.

מפתחים "רגילים" שלא מכירים את התחום נוטים להגיב ל ML בעיקר באחת מ-2 צורות:

  • התלהבות ושקיקה ללמוד את הנושא, מתוך אמונה ש"זה הדבר הבא שישנה את עולם התוכנה, והעולם בכלל"
  • זלזול והתייחסות לקהילת ה ML כ "קבוצה של אנשים מתנשאים ומרוכזים בעצמם, שהשפעתם שולית".
האמת – היא כנראה איפשהו באמצע.
בפוסט הבא אנסה לתת סקירה לא משוחדת של עולם ה Machine Learning, ומשמעויותיו.

היכרות בסיסית עם ML

לא כל בעיה ניתן לפתור בעזרת ML – להיפך. הבעיות העיקריות שניתן לפתור בעזרת ML מחולקות לקטגוריות הבאות:

  • Regression – חיזוי של ערך, על בסיס נתונים. למשל: שערוך ערך של דירה על סמך הנתונים שלה (שטח, גיל, וכו') או הערכה מה יהיה סכום העסקאות של לקוח בחודש הקרוב – על סמך עסקאות עבר, גיל, ומדדים של הרגלי קנייה.
  • Classification – סיווג של entities למספר סגור של קבוצות מוגדרות, למשל: שביעות רצון של לקוח (3 ערכים אפשריים: נאמן, רגיל, נוטה לעזוב), האם עסקה היא לגיטימית או הונאה (2 ערכים אפשריים), וכו'.
  • Clustering – גיבוש קבוצות של פריטים מסוימים. למשל: ברוסיה יש 10,500 ערים – צור קבוצות של ערים דומות (ע"פ סדרה של נתונים על הערים, קרי: מספר תושבים, הכנסה ממוצעת, שטח, שנות קיום, וכו').
  • Recommender Systems – חיזוי פריטים דומים שמישהו עשוי להתעניין בהם, למשל: אם אהבת דיסק של כנסיית השכל – אולי תאהב את הדיסק החדש של שלמה ארצי (לא!!!!!!)
    • Collaborative Filtering – "מי שאהב X אהב גם Y" – המלצת תוכן או מוצר למשתמש, ע"פ סיווג של משתמשים "דומים", ותיאור הפריטים שקבוצת ה"משתמשים הדומים" נוטה לאהוב.
מקור: https://dataaspirant.com

את עולם ה ML מחלקים בדרך ל-2 קטגוריות:

Supervised Learning

כאשר יש לנו מאגר של נתונים ותשובות (= target value), שהושגו בצורה כזו או אחרת (מדידה, עבודה של מומחים, וכו') – ואנו רוצים שהמחשב ינסה לחקות את התשובות.

דוגמה קלאסית: שערוך ערך של דירה. גם אם יש לנו נתונים של אלפי דירות ומחיר מכירה של כל אחד מהן (אתר מדלן?!) – זו תהיה משימה כמעט בלתי אפשרית לכתוב קוד בעזרת if ו for שיבצע שיערוך של מחיר דירה, ובצורה טובה.

בעזרת ML אנו יכולים לפעול באופן הבא:

  • להשתמש ב Domain Knowledge (בקיצור DK) על מנת למצוא, או לפחות לנחש את ה features (תכונות) שמסבירות את מחיר הדירה. מיקום, ושטח במ"ר הם features חזקים מאוד, קומה וגיל הבנין הם features בינוניים וצבע הקירות או גודל המטבח יחסית לגודל חדר האמבטיה – הם features זניחים או אפילו מטעים.
  • בשלב הבא אנו נבחר אלגוריתם למידה (מתוך מבחר אלגוריתמים בתחום) ונפעיל אותו על 80% מהנתונים שלנו (למשל).
  • האלגוריתם ירכיב מודל חיזוי, ע"פ כל מיני שיטות מתמטיות / סטטיסטיות – שניתן להריץ: לשלוח לו פרטים של דירה – ולקבל תשובה = מחיר משוערך.
  • נשתמש ב 20% הנתונים הנותרים שלא השתמשנו בהם ללמידה – לצורך ביקורת: עד כמה טוב המודל שנוצר? מה התפלגות התשובות שלו?
  • כך אפשר לחזור כמה מחזורים עד שאנו מוצאים אלגוריתם ו tuning שמספקים תוצאות שאנו מרוצים מהן.
  • שלב זה יש לנו תוכנה שיכולה לשערך בדיוק כזה או אחר (בשאיפה: דיוק דיי טוב) את העלות הצפויה של דירה ע"פ נתונים גולמיים.
  • כמובן שניתן לשפר את המודל עם הכנסה של Domain Knowledge נוסף: למשל אנו יכולים להעריך שיש הבדל בהתנהגות בין המרכז לפריפריה. אולי הרכבה של 2 מודלים שונים: אחד למרכז ואחד לפריפריה – תשיג תוצאה טובה יותר.
    • יש עוד כלים רבים לשיפור מודל החיזוי – מדובר בד"כ בתהליך איטרטיבי ומשמעותי של שיפורים.
Unsupervised Learning

זוהי קטגוריה מעט שונה של ML בה יש לנו סט של נתונים, אך ללא תשובות (target value) – מהם אנו מנסים להפיק תובנות.
למשל: אנו מנסים לסווג מאמרים לקבוצות הגיוניות, מבלי שיש דוגמה לסיווג שכזה.

ניתן להשתמש ב features כמו אורך המאמר, מספר המלים שחוזר פעמים רבות יותר בכל מאמר, או המצאות / אי המצאות של מילות מפתח.

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

שתי הקטגוריות של ML, "למידה מפוקחת" ו"למידה לא מפוקחת" – מייצרות מודלים שאינם מושלמים:
בבעיות Binary Classification (כאשר התשובה היא X או Y) הצלחות של 80% ואפילו 70% נחשבות להצלחה.
להזכיר: בכזו בעיה נקודת האפס היא 50% – השקולה להטלת מטבע, או התפלגות ידועה אחרת (קרי: ההסתברות האפריורית של האירוע).

אחוזי ההצלחה וכיצד מודדים אותם – תלויים כמובן בבעיה. לפעמים ניתן להשקיע זמן רב בניסיונות ליצור מודל חיזוי של ML – ופשוט לא-להצליח / להצליח ברמה לא-מספקת לצורך העסקי.
"55% אחוז חיזוי במקום בו 50% הוא ההתפלגות הידועה" – עשויה להיות לצרכים מסוימים כישלון צורב, ולצרכים אחרים – תועלת שראוי להשתמש בה.

המוטיב המרכזי לשימוש ב ML הוא לפתור בעיות שאין לנו פתרון טוב יותר עבורן:

אם אנו רוצים לסווג את המאמרים בדוגמה הנ"ל לכמה קבוצות על פי אורך המאמר (משהו שקל מאוד לתוכנה אמפירית לעשות) – אין טעם להשתמש ב ML – פשוט כותבים קוד שיעשה זאת. זה יותר קצר, מהיר, ומדויק.

מצד שני, טכניקות של ML מסוגלות לפתור בעיות שלא היה ניתן לפתור בצורה אחרת: מזיהוי כתב יד, המלצות תוכן ("אנשים שקנו X גם קנו Y"), זיהוי פריצות אבטחה, או נהיגה של רכב אוטונומי. את כל הבעיות הללו – אתם מוזמנים לנסות ולפתור בעזרת קוד אימפרטיבי 🙂

תהליך העבודה (Workflow) של ML

תהליך העבודה של ML, הוא מעט יותר מורכב ממה שתיארתי. מכיוון שעיקר העבודה על ML היא התהליך ולא כתיבת קוד – אפרט מעט יותר על התהליך.
אני אתמקד בתהליך שמתאים ל Supervised Learning, כמו בעיית רגרסיה (ניבוי ערך של נכס נדל"ן).

השלבים בתהליך הם:

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

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

מי יכול לדעת ששישה חודשי עבודה על ניסיונות המלצה שונים הולכים לרדת לטמיון?
דרוש כאן בעיקר Domain Knowledge עמוק ואיכותי ו/או מתודולוגיה שתזהה כישלון בשלב מוקדם.

השגת הנתונים (Obtaining Data)
יש להשיג נתונים "מוצלחים", ולא סתם נתונים "באיזור הבעיה".
זה אומר הרבה פעמים להתחיל לאסוף נתונים שלא נאספו בעבר, ולהבין המשמעות המדויקת של כל נתון. לכמות הנתונים יש גם חשיבות גדולה: אלגוריתמים רבים יהיו מוצלחים הרבה יותר – כאשר יש להם יותר נתונים ללמוד מהם.

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

שלב זה בעיה משולבת של Domain Knowledge, תכנות, והבנה ארגונית טובה – ברוב הפעמים לא תוכלו להשיג את הנתונים לבד.

".More data beats clever algorithms, but better data beats more data" — פיטר נורוויג (המחבר-שותף של הספר הנודע "AI: A Modern Approach" ומנהל מחקר בגוגל).

קרצוף הנתונים (Scrubbing Data)
גם ברגע שיש נתונים "נכונים "- לרוב יהיו להם בעיות איכות (Data Quality):

  • להשלים ערכים חסרים (או להסיר אותם, אם תיקון לא אפשרי). באג בפרודקשיין עשוי לגרור לאחוז כזה או אחר של נתונים שגויים או חסרים – לאורך תקופה.
  • לתקן אי התאמות. למשל שמי הופיע פעם בספריית הוידאו גם כ "ליאור בר און" וגם כ "ליאור בר-און" – הייתי מיוצג כשני אנשים, למרות שאני אדם אחד – מה שיגרום להטיה בניתוח הנתונים.
    • יש טכניקות שונות (חלקן מבוססות ML) בכדי להתאים ולזהות שבעצם מדובר באותו האדם (בסבירות כזו או אחרת)
  • נורמליזציה של הנתונים, למשל: כל התאריכים באותו ה format כך שניתן יהיה לעשות השוואות. המרה של מיילים לקילומטרים, סדר נתונים כזה לסדר אחר, וכו'. ישנו כלל של ML שטוען: "הנתונים שתקבלו תמיד יהיו בפורמט הלא-נכון"
שלב השגת הנתונים + "הקרצוף" נחשבים בד"כ לכ 50-80% מכלל העבודה ב ML Workflow – החלק הארי.
שלב זה דורש יכולות תכנות, קצת הבנה סטטיסטית (עבור תיקונים וקירובים), ומעט Domain Knowledge – על מנת להבין את הנתונים טוב יותר.
כמעט תמיד ניתן להשקיע עוד עבודה בכדי לשפר עוד יותר את איכות הנתונים – וחשוב לדעת גם מתי "לעצור".
בחירת האלגוריתם
ישנם עשרות אלגוריתמים של ML, וכמה שרלוונטיים לכל סוג של בעיה. עליכם להבין את הנתונים ואת האלגוריתם – על מנת (לנסות ו)להתאים את האלגוריתם הטוב ביותר.
למשל: בעיה של Binary Classification ניתן לפתור בעזרת Naive Bayes (מודל סטטיסטי שלא דורש כמויות גדולות של נתונים ורץ מהר), בעזרת Logistic Regression (המבצע רגרסיה בין features ע"פ משקולות נתונות), או עץ החלטה (שמנסה לשערך הסתברות של כל feature בנפרד – ואז לסכם את סך ההסתברויות).

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

שלב זה הוא Pure Machine Learning Knowledge

בתרשים זה ניתן לראות כיצד בחירה של אלגוריתם משפיעה על אחוז הטעות של האלגוריתם. תמיד קיים tradeoff בין טעות מסוג I וטעות מסוג II, אבל ניתן לראות שאלגוריתם ה Random Forest עליון במקרה זה על האלגוריתמים האחרים. מקור: wise.io

אימון המודל

זהו השלב בו מזרימים את הנתונים לאלגוריתם, ובד"כ בונים תהליך אוטומטי שיעשה זאת.
נרצה לנסות אימון של המערכת עם קבוצות שונות של features וכך לבדוק אילו features הם מוצלחים יותר לפתרון הבעיה. זהו סוג של fine tuning של האלגוריתם, למשל: האם כדאי לשלוח median או average? אולי כדאי average כאשר מנקים מעט נקודות קיצון?
כיצד ניתן לצמצם את כמות ה features (קרי: סוגי הנתונים)? לרוב – פחות features יובילו לכמות קטנה יותר של טעויות.

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

שלב זה דורש הבנה סטטיסטית, מעט תכנות, ויכולות תפעול.
בחינת המודל
בשלב זה אנו מריצים את קבוצת הביקורת (או טכניקה אחרת שבחרנו) על מנת לבחון את הצלחת המודל.
זהו שלב בעיקר מדעי / סטטיסטי – בו אנו מנסים להעריך עד כמה המודל מוצלח.
השלב הבא הוא לא GA (כלומר: General Availability).
בד"כ יהיו השגות חדשות על איכות הנתונים / סוג הנתונים הנדרש / התאמת האלגוריתם וכו'.
מכאן חוזרים לכמה איטרציות נוספות של שיפורים – עד שמגיעים לרמה הרצויה.
כמה איטרציות? תלוי כמה טוב צריך להיות המודל, כמה זמן יש לכם, ועד כמה אתם מעריכים שזמן נוסף ישפר את המודל.בסופו של דבר, יש מודל חיזוי מספיק טוב – שניתן לחבר למערכות ה Production ולהתחיל להשתמש בו.

סיכום

עברנו בצורה זריזה על העולם של ה Machine Learning, וניסינו להפריך את הפנטזיה של "קוד שכותב את עצמו, בזמן שהמתכנת שותה קפה או משחק בפינג-פונג".ML היא סוג של שיטה מדעית לחיזוי על סמך מציאת דפוסים (Patterns) בנתוני עבר. יש בה הרבה יותר מן האומנות (הרבה בחירות לא מדויקות וניחושים מושכלים, הרבה fine-tuning) – מאשר תחומים קלאסיים של כתיבת תוכנה.

עם ההישגים הרבים של ML – קשה להתווכח. מצד שני: אין פה תחום ש"יחליף את כתיבת התוכנה הקלאסית". אם כבר, אזי עולם התוכנה מצליח להתרחב לתחומים ופתרון בעיות שלא היו נגישות לו בעבר.

התחום הזה הוא לא פשוט בכלל: זה לא כמו ללמוד עוד שפת תכנות או עוד Framework.
ספקי ענן כאלו אחרים יספרו לכם שיש להם "Machine Learning as a Service" ושהיום הכל יותר פשוט: לא צריך דוקטורט, אלא רק חשבון ב – ואפשר להתחיל להריץ ML.
זה נכון – התהליך הופך לנגיש יותר ויותר מבחינת התפעול, אך אין עדיין (למיטב ידיעתי) – התקדמות משמעותית בניסיון לייתר את המומחיות בתחום.

שיהיה בהצלחה!

לינקים רלוונטיים:

איך ללמוד ML בשנה: מאפס – לעבודה מעשית

הקורס של גוגל ל Deep Learning – ה "Docker" של עולם ה ML… – גם קורס זה בחינם.מי שמסיים בהצלחה אחד מהקורסים הנ"ל – מוזמן לבוא ולכתוב פוסט אורח בנושא 🙂

https://charlesmartin14.wordpress.com – בלוג שמנסה להסביר לעומק קונספטים שונים ב ML

על DevOps וה DevOps toolkit

יש כמה הבדלים מהותיים בין פיתוח תוכנה של המתכנת הבודד ("לבד בבית") לקבוצה גדולה יותר של אנשים שמפתחת את הפרויקט ביחד. המעבר לקבוצת פיתוח מכתיב צרכים של תיאום וסנכרון, ובסיס הקוד הגדול והמורכב יותר (שהוא פועל יוצא של יותר ידיים עובדות) – דורש תהליכים של "ניהול תצורה", Deployment, וניהול הקוד ב Production.   בכדי להתמודד עם האתגרים הללו, קבוצות הפיתוח השתמשו בשני כלי-עוצמה ניהוליים: התמחויות ואחריות, וכך נוצרו התפקידים הבאים:

  • מפתחים אחראים לכתוב קוד
  • איש ה UX אחראי לעצב את חווית השימוש
  • ה DBA מתמחה ב Database Systems
  • ה QA בודק את המערכת
  • איש ה Operations אחראי להתקין את התוכנה ולנטר אותה
  • וכו'…

באופן טבעי, הושתת ניגוד-אינטרסים מובנה בין חלק מבעלי התפקידים:
  • איש ה UX רוצה להשיג את חווית השימוש הטובה ביותר – והמפתח רוצה לשחרר פיצ'רים מהר.
  • איש ה QA רוצה שלמות במוצר – והמפתח רוצה לשחרר פיצ'רים מהר.
  • איש ה Operations רוצה יציבות – והמפתח רוצה לשחרר פיצ'רים מהר.

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

שינוי #1: הגבולות בין אנשי ה QA והמפתחים החלו להיטשטש

בעקבות צירוף של אנשי ה QA "לצוותי סקראם" והגדרת מטרות משותפות ברמה צוותית – ניגוד-האינטרסים המובנה פחת: ה QA שותפים לזמני ה Delivery והמתפתחים אחראים יותר לאיכות.
מפתחים החלו להיות שותפים פעילים יותר בתהליכי האיכות (בדיקות יחידה, בדיקות אינטגרציה וכו') דבר שהן השפיע על הגישה שלהם לנושא וגם יצר שותפות-גורל גדולה יותר בין ה QA למפתחים.שינוי #2: המעבר לענן ואוטומציה של התפעול

המעבר לענן הסיר מאנשי ה Operations בארגון כמה עיסוקים הרחוקים מאוד מהמפתחים: טיפול בחומרה ורשתות תקשורת – עולם שלם בפני עצמו. את החומרה והרשת מנהלים בצורה אוטומטית בעזרת תוכנה (להלן Virtualization ו Software Defined Networks) וכך התקרב העולם של אנשי ה Operations לעולם המתכנתים – עולם של כתיבת סקריפטים ~= קוד.

בד בבד, התצורות הלוגיות של המערכת (להלן מיקרו-שירותים, ומערכות מבוזרות אחרות) הפכו למורכבות הרבה יותר – לא עוד Cluster בודד של שרתים עם בסיס נתונים שיש לתחזק.

היכולת של ה Operations להתמודד עם אתגרים אלו כקבוצה חיצונית לפיתוח – הפכה מורכבת יותר ויותר. חילופי ההאשמות והמתח בין הקבוצות רק הלך וגבר (להלן blaming culture).שינוי שאנו נמצאים במהלכו כיום נקרא The DevOps Movement – ההכרה שהדרך הטובה ביותר להתמודד עם סביבות המחשוב המורכבות שנוצרו – הוא בשיתוף פעולה אמיתי בין Operations ל Developers.

מקור: ThoughtWorks Radar – מארס 2012

כמובן שארגונים רבים לא מכירים בעומק הרעיונות שמאחורי תנועה זו, ופשוט משנים את ה title של אנשי ה Operations ל "DevOps" – שם פופולארי יותר.

מקור: ThoughtWorks Radar – נוב' 2015

עבודת ה Dev-Ops בארגון

בשלב הזה אני לסקור את העבודה שיש בפני ה Operations וה Dev (וגם קצת IT וגם קצת QA) בארגון. אני יכול להתחיל בהצהרות ברמה גבוהה "לדאוג ליציבות המערכת". הצהרות אלו הן נכונות – הן אם לא תמיד כ"כ מוחשיות. מה כן מוחשי? כלים ותהליכים. אספתי את סוגי הכלים והתהליכים הקיימים בעולם Dev-Ops לכדי רשימה, ואני הולך לפרט לגבי כל קטגוריה בנפרד. אני אציג תמונה (/ "סיפור") מציאותית – אך כמובן לא יחידה: ניתן לתאר את התהליכים הללו בצורות שונות, ולאנשים שונים וארגונים שונים יש תפיסות שונות לגבי גבולות הגזרה בין התהליכים / הכלים / ותחומי-האחריות השונים. אני לוקח כמה הנחות בסט הכלים שאראה:

  • אני מניח שמדובר ב Deployment בענן, ולא ב On-Premises (קרי: אין ניהול של חומרה ורשת פיסיים) – ואני מתמקד ב AWS (עננים אחרים הם דיי דומים בהיבט זה).
  • אני מניח שמדובר באפליקציית ווב.
  • אני מניח ש Docker (או פתרון אחר של Linux Containers) אינו מעורב – אחרת התמונה תשנה במידת-מה.
אם יצאתם זה עתה מהאוניברסיטה, או אי בודד – פוסט זה יכול לספק תמונה לא רעה על תהליכי פיתוח בקבוצות-תוכנה בתעשיה.
אם אתם כבר בתעשיה – אני מקווה שתמונה זו תוכל להשלים "חורים" שאולי חסרים לכם.
המורכבות של Stack מודרני, מול Stack בן עשור. מקור: https://goo.gl/9yCLtp

לרבים מההיבטים שאתאר (למשל: Logging, Version Control, וכו') יש היבטים ברורים מאוד של פיתוח: קביעת conventions לעבודה, למשל –  בד בבד עם היבטים של תפעול (התקנה ותחזוק של השרתים, גיבויים וכו').

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

כלים "פנימיים"

אלו הכלים שלרוב משמשים את הפיתוח. מישהו צריך לנהל ולתפעל אותם. ה"מישהו" הזה, הוא הרבה פעמים צוות ה IT) Operations). בסטארט-אפים קטנים – הרבה פעמים האלמנטים הללו מנוהלים ע"י המתכנתים עצמם.

דוגמאות לכמה כלים בכל קטגוריה

Issue Tracking

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

יש כאן ניגוד אינטרסים קטן: מי שמביט על כלל הפרויקט (מנהל פרויקטים, מנהל פיתוח) מעוניין לאסוף כמה שיותר פרטים על כל משימה – עבור יכולות הניתוח, בעוד מי שעובד עם המערכת (מתכנתים) מעדיף להתעסק עם הכלי כמה שפחות – כי בסוף העיסוק ב Issue Tracking לא מייצר Value ללקוחות.
Jira (ויש מתכנתים האומרים: ״Jifa״) הוא כנראה הכלי הנפוץ ביותר, שמכסה גם היבטים של ניהול פרויקטים ובאגים – אך יש גם כלים אחרים.

Version Control

בסטארט-אפים מקובל בעיקר לעבוד עם Github.com – ולקבל משם שירותים מנוהלים של ניהול קוד.
ארגונים גדולים, יותר מקובל לעבוד עם Git ישירות או עם GitHub Enterprise (או החלופות שלו) – תוכנה שיש להתקין ולנהל לבד, עם היכולת לאבטח בצורה יותר טובה.

מלבד ניהול השרת של ה Version Control, יש עניין של ניהול התוכנה עצמה: ניהול ה Repositories, וההרשאות (האם אתם בודקים כל תקופה שעובדים שעזבו הוסרו מהמערכת?), הכשרה לעובדים (לא כולם מכירים את Git), ופתרון בעיות ("אופס… עשיתי force– למשהו שגוי….").

Build

את הקוד צריך לקמפל (במקרה של Java, Go, #C, וכו') – או שלא (במקרה של רובי, Python, או ג'אווהסקריפט).
לרוב יהיו לנו בדיקות (יחידה, אינטגרציה, ביצועים, אבטחה) אוטומטיות – שירוצו כחלק מתהליך ה Build.
תוצרי הקוד (תמונות, קבצי JavaScript, קבצים בינאריים) לעתים קרובות עוברים עיבוד נוסף: דחיסה / אופטימיזציה – לתמונות, minification / obfuscation ו unification לקבצי ג'אווהסקריפט, או bundling לקבצים בינאריים (למשל: אריזת קבצי jar. כקובץ war. או ear. – בעולם הג'אווה).

את תהליך ה Build לרוב מריצים על כל submit / push של קוד ל Version Control – על מנת לאתר תקלות בשלב מוקדם ככל האפשר. באופן זה העלות לתקן את הבעיות – פחותה.

בטעות, יש כאלו שקוראים לתהליך ה Build בשם "Continuous Integration", ולשרת ה Build – כ "CI Server". זה שימוש שגוי בטרמינולוגיה: Continuous Integration הוא תהליך בו מגבירים את תדירות האינטגרציה בין המפתחים השונים. למשל: כל מפתח מבצע merge של הקוד שלו חזרה ל master / trunk – כל יום!

ו Git Flow? – הוא כבר לא כ"כ באופנה. זו בערך הגישה ההפוכה לגישה של Continuous Integration.
בעולם ה Build יש כלים ברמות שונות: Jenkins או TravisCI הם Build Servers שמנהלים את ה Build Pipeline.
כלים כמו Maven, SBT, Ant, או Gradle (כולם מעולם הג'אווה) – הם כלים להגדרת המיקרו של ה build (וניהול תלויות). דומים יותר ל Make או Rake.
בעולם הג'אווהסקריפט משימות מסוימות מבוצעות עם כלים כמו Grunt, Gulp, או npm – ואת משימת האריזה עם כלים כמו webpack או Browserify.

Artifact Management (בקיצור AM)

תוכנת AM היא כזו שעוזרת לנהל תוצרי תהליך ה-build (למשל: קבצים בינאריים, Gem Files, או Images של VM) בצורה: מסודרת, מאובטחת, Highly Available, ו Durable (כלומר: יש גיבויים).

תהליך ה Build, מרכזי או כזה שנעשה על המחשב של המפתח, ישלוף חלק מהתוצרים ב AM – במקום לייצר אותם מחדש.

AM יכולים לנהל תוצרים פנימיים שנוצרו ע"י הארגון, או Caching לתוצרים חיצוניים כמו ספריות Open Source (בכדי לקצר זמני הורדה שלהם ברשת). הרבה פעמים יהיו בארגון כמה כלי AMs שונים (למשל: תוצרי ג'אווה או רובי, תוצרי AWS, ותוצרי Linux).

Development Environment Management 

אין מה לעשות: בכדי לפתח בצורה יעילה – אנו זקוקים לסביבות שאפשר לנסות עליהן הכל, ואפשר "לחרב" אותן מבלי לחשוש.
הרבה פעמים אנו רוצים בסביבות הללו נתונים (data) מציאותיים, קרי – עותק של חלק מהנתונים מ production, כאשר הם מצומצמים ומנוקים (sanitized) ממידע רגיש (למשל: כתובות אימייל של משתמשים אמיתיים). ההכנה של הסביבות הללו – היא עבודה לא קטנה.

היבט אחר של "סביבת הפיתוח" הוא המחשב האישי של המתכנת (או QA וכו'). כמה זמן לוקח להתקין מחשב חדש ומפורמט – עד שיש סביבת עבודה מלאה? לעתים זה יכול אפילו כמה ימים מלאים של עבודה.
כנראה שהייתם רוצים שיהיה דף וויקי (במינימום), תמיד מעודכן, שמסביר את סדרת התהליכים הידניים שיש לעבור על להתקנה מלאה של הסביבה, ועדיף – שיהיה כלי אוטומטי שמבצע את כל תהליך ההתקנה בלחיצת כפתור (ובזמן סביר).

Collaboration

Collaboration טוב נוצר קודם כל ע"י אנשים – ולא כלים. בכל זאת – הכלים יכולים לעזור.
מישהו צריך להתקין ולנהל את כלי ה Collaboration הללו. את התוכן, באופן טבעי – בדרך כלל ינהלו המתכנתים.

כלל קטן: אם אנשי ה Operations מתחזקים את כלי ה Collaboration אך לא משתמשים בהם – אין לכם תרבות של DevOps בארגון. שקיפות ושיתוף בין פיתוח ו Operations – זה הבסיס.

כלי "Production"

את הכלים הללו לרוב מפעיל צוות שנקרא בארגונים גדולים בשם ״Web Operations״. זו נחשבת התמחות שונה מצווות ה IT Operations.

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

כשעבדתי ב SAP למשל, צוות ה IT Operations ישב איתנו ונקרא "DevOps". הם ניהלו את כל הכלים הפנימיים, הדריכו ותמכו במפתחים וממש עזרו להם. הצוות הזה הכיר Git, Jira, ו Maven – יותר טוב מכולם.
צוות ה Web Operations נקרא "Hosting", ישב בגרמניה והיה מאוד מרוחק מאיתנו – פיסית ומנטלית. אם השתקפה בעיה ב Monitoring – מישהו היה מתקשר, אבל מעבר לזה הקשר ביננו היה חלש, ולא היה הרבה מה לעשות בנידון. זה היה תת-ארגון אחר. לכלי ה Monitoring למשל, לא הייתה לנו גישה. אפילו לא לצפייה. ממש לא DevOps Culture…

דוגמאות לכמה כלים בכל קטגוריה

 Web/HTTP

בקטגוריה זו יש לרוב יהיה שימוש ב 2 או 3 מתוך תתי הקטגוריות הבאות:

  1. HTTP Server – עבור הגשת Static Content ו/או ניהול התעבורה עבור Technology Stack שאינו multi-threaded מטבעו. כלומר: PHP, Ruby, Python. הכלים הנפוצים בקטגוריה זו היא Nginx ו Apache httpd.
  2. Application Server – סביבת ריצה לאפליקציות ווב. בעולם הרובי Applications Servers נפוצים הם Puma, Unicorn, ו Raptor. בעולם הג'אווה הם יכולים להיות Tomcat, Jetty, או Glassfish.
  3. Content Delivery Network (בקיצר CDN) – שהיא יעילה אף יותר מ HTTP Server בהגשת Static Content, אך יש לעתים סיבות להשתמש בשניהם.
כלים אלו משפיעים במידה ניכרת על ה Traffic / התנהגות המערכת. כנראה שתרצו מישהו בארגון שמבין בהם, יידע לקנפג אותם, לנטר אותם, ולאתר תקלות בצורה מהירה – ולא תמיד אלו יהיו המפתחים.

Configuration Management

כלי ניהול תצורה הם סיפור בפני עצמו. הקדשתי להם לאחרונה פוסט בשם כלי ניהול תצורה – מבראשית ועד ימי ה Docker.

Packaging

ה Packaging מטפל באריזת ה VM Image שממנו ניצור instances של מכונות בענן.
אם אתם עובדים בענן כלשהו (אמזון, Azure, או אפילו VMWare) – סביבת הענן תאפשר לכם לייצר Image ממכונה.

כלים כמו boxfuse או packer מאפשרים לכם לייצר מאותה המכונה Images מסוגים שונים (למשל: אחד ל Azure ואחד ל AWS במקביל), וגם ליצור Images קטנים ויעילים יותר (ע"י זיהוי התלויות הנדרשות ובניית "סביבת מערכת הפעלה" מספיקה לצרכים הספציפיים).
Image מוקטן שכזה מתאים ל Immutable Deployments (להלן הפוסט על כלי ניהול תצורה), ומגיע על חשבון החופש להתקין בקלות עוד כלים על המכונה במהלך הדרך.

למרות שאני מציג את ה Packaging כקטגוריה בלתי-תלויה בכלי ניהול תצורה – לרוב משלבים בתהליך ה Packaging כלי ניהול תצורה, שילוב שלרוב הוא מובנה בכלי ה Packaging.

Deployment

"מה הבעיה לעשות Deployment?!" – היא השאלה הראשונה כאשר עוסקים בקטגוריה זו.
"אני פשוט הולך ל UI של אמזון, בוחר image, ומאשר – תוך 2 וחצי דקות השרת למעלה".

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

  • כיצד להתקין שרתים חדשים מבלי לפגוע ב Traffic הקיים? לא Downtime ולא שיהוק.
  • אם אנו עושים זאת בהדרגה, כיצד מתמודדים עם מצב הביניים בו יש כמה שרתים בגרסה n, וכמה שרתים בגרסה n-1 החיים זה לצד זה?
  • מכיוון שמדובר ב cluster, כיצד עושים זאת עם כל הגדרות ה Load Balances, רשת, אבטחה – ומבלי להתבלבל. ה UI הרגיל של אמזון כבר לא כ"כ טוב לבעיה הזו.
  • מה עושים במצב של כשל? מתי מזהים אותו וכיצד – ואיך עושים Rollbacl? (לא נחכה לתיקון קוד עם בעיה חמורה בפרודקשיין, ולא משנה עד כמה המתכנתים שלנו זריזים).

בגדול, יש שתי "אסטרטגיות: עיקריות לביצוע Deployment:

  • Rolling Deployment
    • התהליך (נניח שהשרת שלנו רץ על m nodes):
      • ניקח node אחד ואז:
        • ננתק אותו מה LB
        • נוודא שכל ה requests שבתהליך סיימו להיות מטופלים
        • נתקין את הגרסה החדשה
        • נחבר אותו בחזרה ל LB וננטר אותו לזמן קצר לראות שהכל בסדר.
      • נחזור על כל התהליך הזה עוד כ m-1 פעמים.
    • ל Rolling Deployments יש ייתרון של חסכון במשאבים (צריך עוד שרת אחד, אפילו אם יש לנו 100 nodes), אבל הוא יכול להיות תהליך ארוך – ו rollback הוא קשה וארוך גם כן.
  • Blue/Green Deployment
    • התהליך (נניח שהשרת שלנו רץ על m nodes – "ה cluster הכחול"):
      • ניצור cluster חדש ("ירוק") זהה בחומרה ל cluster המקורי – ונתקין עליו את הגרסה החדשה.
      • ננתב חלק קטן מה traffic ל cluster החדש וננטר לזמן קצר. הכל בסדר? נחליף ברגע אחד את ה cluster הירוק להיות ה cluster הפעיל.
        • ניתוב ה Traffic יכול להיעשות באסטרטגיה של DNS cutover, באמזון – זמינה גם אסטרטגיה בשם swap auto-scaling groups, ויש גם אסטרטגיות אחרות.
      • ה cluster הכחול ימשיך לחיות עוד זמן מה (החיוב באמזון למכונות הוא ע"פ שעה עגולה של שימוש). אם נגלה בעיות בגרסה החדשה נוכל לחזור ל cluster הכחול – ברגע.
    • Blue/Green Deployment דורש יותר משאבים – אך הוא בטוח יותר, ומאפשר Rollback מהיר.
האם אתם רוצים לבצע בשטח את אסטרטגיית ה Deployment בצורה ידנית? קרוב לוודאי שלא, שתעדיפו לעשות את התהליך בעזרת כלי שיצמצם משמעותית את טעויות האנוש ויקצר את התהליך.לרוב ספקי הענן יש כלים משלהם לפעולות Deployment (ובכלל ניהול ה Deployment Pipeline) – אך הכלים החיצוניים עדיין נחשבים טובים יותר.

הערה: Jenkins הוא לא כלי מוצלח לניהול Deployment. נכון: גרסה 2.0 שלו הציגה קונספט של "Pipeline as code", אך קונספט זה ממשיך לעקוב אחר המודל הקיים והסבוך של pipelines של Jenkins והגמישות בו מבוססת על Plugins.

Jenkins הוא סבבה כנראה ל build pipeline, כך בכל הקשור ל deployment – מומלץ להיצמד לכלים ייעודיים.
כדאי להכיר: אלו סט הכלים של HashiCorp – ארגון מוערך מאוד שהוציא כמה כלים מאוד מעניינים (דגש על Vagrant ו Consul) בתחום. חשוב גם להיזהר מהנטייה האישית "לאסוף סריות": לא כל כלי של HashiCorp הוא בהכרח מתאים לכם. בוודאי שלא!
RDBMS Migration
אם אתם זוכרים – בבסיסי נתונים רלציוניים (וגם כמה אחרים), ישנה סכמה מוגדרת מראש של הנתונים. סביר שחלק מהעדכונים של התוכנה יידרשו שינוי סכמה בבסיס הנתונים.להזכיר: בזמן ה Deployments (אם רוצים zero downtime) יהיו שלבים בהם ירוץ קוד חדש וישן זה לצד זה – ושניהם מול בסיס נתונים אחד (זה לא ריאלי בד"כ לרפלק את בסיס הנתונים לצורך deployment. יותר מדי סיכונים והשקעה).

ניתן לבחור ב-2 גישות:
  • קוד תואם לאחר שיתמוך ב-2 הסכמות (השקעה גדולה). את המיגרציה ניתן לעשות לאחר עדכון הקוד (סיכון).
  • סכמה תואמת לאחור – כלומר רק תוספות ולא מחיקות או שינויים (הגישה הנפוצה). את המיגרציה יש לעשות לפני עדכון הקוד, בשלב מוקדם של ה deployment.
עבור migrations יש כלים רבים. חלקים מגיעים כחלק מה Framework (כמו ב !Ruby On Rails, Play, או Django). ישנם כלים כמו Flyway או Liquibase שאינם תלויים בשפת תכנות או Framework ספציפי.ה Migration עצמו הוא סכנה ליציבות המערכת: תקלה בו יכולה להיות בעיה קשה.

סיכון נוסף הוא שינוי של טבלאות גדולות במיוחד (עשרות או מאות מיליוני רשומות?) או פעילות במיוחד (הרבה locking). פעולות migration שכזו עשויה להתארך לאורך שעות – ולפגוע לאורך כל הזמן הזה בביצועי המערכת.

כלים כמו LHM או Table_migrator מצמצמים סיכונים ע"י העתקת הטבלה הצידה, ביצוע ה migration, ואז החלפתה (rename) – קונספט דומה ל Blue/Green Deployment – רק שצריך לנהל delta של השינויים שלא נכנסו לטבלאת העותק בזמן ה migration – ולעדכן אותם מאוחר יותר.

Monitoring

אין דיי לומר על עולם זה, ה Monitoring הוא גם עין ימין וגם עין שמאל שלנו – על סביבת הפרודקשיין.
פעם, כשחדר השרתים היה במשרד היה ניתן לקפוץ אליו – ולשמוע את המאוורים מסתובבים. היום גם את זה אי אפשר ;-).

כלי ה Monitoring הם אלמנט חשוב לתפעול, ולרוב יהיה לנו Monitoring בכמה רמות שונות (מערכת, אפליקציה, Proactive Monitoring, וכו'.) – ייתכן וכל רמה בכלי שונה.

כתבתי כבר בעבר פוסט על New Relic – הכלי האהוב עלי בתחום: על Performance Monitoring ו New Relic.
כתבתי גם פוסט בשם Monitoring: מבוא ל Graphite ושימוש ב Time-Series – המתאר כלים ל custom monitoring (בהיבט של time series).

תת-קטגוריה אחת ששווה להזכיר היא נושא ה Alerting – שליחת אימייל / SMS / או טלפון (עם הודעה קולית) לאנשים הרלוונטיים (ע"פ תורניות), ועל סמך הצטברות מדדים כאלו או אחרים ממערכות ה Monitoring. כלי כזה לדוגמה הוא PagerDuty.

תת-קטגוריה קרובה אחרת היא הנושא של Event Management: בהינתן מדדים כאלו ואחרים – הפעל response שנקבע מראש (ונבדק). למשל: restart ל service, הריגת טרנזקציה מסוימת ב DB, הגדלת מספר השרתים, וכו'.

Logging

לכתוב מהקוד ללוג – זו לרוב פעולה פשוטה למדי: בוחרים ספריית Logging, מסכימים על כמה כללים – וכותבים.

מה קורה עם הלוגים אח"כ?
מה קורה בענן ו/או ובארכיטקטורה של מיקרו-שירותים? אם לא נאסוף את הלוגים הללו למקום מרכזי – הם יעלמו לנו.
אם לא נאנדקס אותם – לא נוכל לחפש בהם בצורה יעילה.
אם לא נמחק אותם (מהמכונות, ומהאינדקסים של ה repository המרכזי) – ייגרם נזק לשרתים או ליכולת שלנו לחפש בהם ביעילות.

הכלים הנפוצים לניהול לוגים הם ה ELK Stack (קיצור של ElasticSearch, LogStash, ו Kibana) או לחלופין Splunk או SumoLogic (שלא כוללים את איסוף הלוגים – LogStash או מוצרים חלופיים).

יש גם תת קטגוריה של Error Tracking – שהם כלים ייחודיים לניתוח תקלות משמעותיות במערכת (מול לוגים – שכוללים את כל המידע וגם info, traces, וכו'). כלים מוכרים בקטגוריה זו הם Airbrake, Sentry, ו Raygun.

יכולות ייחודיות לכלים אלו הם סנכרון עם עדכוני קונפיגורציה / תוכנה – וניתוח ה impacts שלהם מבחינת צפיפות ה errors, חיתוך ע"פ id של משתשמש (שאנחנו סיפקנו) בכדי לנסות ולאתר מדוע שימוש מסוים גורר בעיות – וכו'.

Security

כלי אבטחה הוא עולם בפני עצמו. אני יכול בקלות לזרוק רשימה ארוכה של כלים רלוונטיים:

  • מתחילים עם Firewall – שבדרך כלל ספק הענן יספק.
  • אם המערכת שלכם עובדת על גבי HTTP, קרוב לוודאי Web Application Firewall (בקיצור WAF) – כמו Cloudflare, אינקפסולה, או BigIP (של F5).
  • דרך כלים ל Authentication ו/או Federated Identity Management (בקיצור FIM) כמו PingIdentity, OKTA, או Auth0.
  • כלי Intrusion Detection System (בקיצור: IDS) – כמו Snort, או Trend Micro's Deep Security.
  • כלים ל audit בגישה ל Production כמו ObserveIt או CyberArk.
  • כלי SIEM – כלי לניהול לוגים בהיבט האבטחה, כלים כמו ArcSight, QRadar, או Splunk (שהוא גם "חזק" בעולם ה Security).
  • כלים ל Security Static Code Analysis המחברים לתהליך ה build כגון Checkmarx או Fortify.
  • ועוד…

בארגונים יותר גדולים, כל הנושא של כלי ה Security מופקד ביחיד צוות Operations מיוחד, שמתמחה בנושא.
בארגונים קטנים יותר – זה היה צוות ה Web Operations או אפילו המפתחים.

לכאורה, ניתן לכתוב פוסט מקביל לזה – רק בהיבט האבטחה.

סיכום

עוד פוסט שחששתי שלא יהיה לי מה לכתוב בו – אך התארך מעבר הצפוי 🙂
נושא ה Operations וה Production הוא עולם בלתי נגמר.

תנועת ה DevOps שמשפיעה על כלל התעשיה (שלב א': שינוי ה Title של אנשי ה Operations – אך יש גם את השלבים הבאים) – משנה את העולם.

עוד כוח שמשנה את התמונה הוא טכנולוגיית ה Linux Containers (ובחזיתה: Docker), גישה החותרת ל Fully Immutable Deployment – גישה שעשויה לשנות כמה מהתהליכים ויחסי-הכוחות בעולם זה.
תוצר לוואי של גישת ה Containers היא החתירה ליצירת כלי Infrastructure Management חדשים (כמו Mesos, Tectonic, או Atlas), שלא מבוססים על ספקי הענן  – מה שעלול לגרום לעוד כמה תזוזות.

שיהיה בהצלחה!

לינקים רלוונטיים

DevOps Awesome Links – כמה קישורים מעניינים!

DevOps From the ground up Deep Dive into Blue/Green Deployments on AWS – על אסטרטגיות Deployment.

ההבדל בין Packer ל Vagrant – מאמר + דברים של מיטשל האשימוטו (Hashi)

Cybersecurity Market Review – סוקר הרבה כלי Security במגוון קטגוריות

על כלי ניהול תצורה / Provisioning – מבראשית ועד ימי ה Docker

כאשר מנהלים שרתים בפרודקשיין ומדובר בכמה עשרות שרתים, האופציה לנהל את השרתים בצורה ידנית (להתחבר ב SSH ולבצע שינויים) – הופכת כבר ללא-ריאלית, ואפילו מסוכנת. מסוכנת – כי הסבירות לטעויות אנוש בכזו כמות שרתים היא גבוהה למדי.

ישנם מגוון כלים לניהול תצורה (Configuration Management בקיצור CM), המאפשרים לנהל מספר גדול של שרתים (מאות, אולי אלפים) בצורה אוטומטית ומסודרת. כלים אלו לרוב מספקים את היכולות הבאות:

  • Change Management – ניהול הגדרות ה"מצב הרצוי" בתצורת השרתים, בצורה מסודרת וניתנת לשליטה. למשל: שינוי הגדרות של nginx בשרתים מסוג x או הוספת תיקיה חדשה במערכת הקבצים של שרתים מסוג y.
    • חשוב שיהיה קל להבין ולהגדיר מהם "שרתים מסוג x". לעתים אגב, אלו יכולים להיות שרתים עם מערכות הפעלה שונות, ושמריצים תוכנות שונות.
  • Provisioning – זהו בעצם התהליך של העברת שרת ממצב נתון כלשהו – למצב הרצוי.
    • זה יכול להיות התקנה של שרת מאפס, או בדיקת המצב בשרת קיים – וביצוע השינויים הנדרשים על מנת להגיע למצב הרצוי.
    • לרוב שינוי ההגדרה יכלול ביצוע שינוי בשרתים שכבר "באוויר", וגם הכללת השינוי החדש בשרתים הבאים שיקומו.
    • כאשר מבצעים שינויים, ישנן תקלות (פעולות רצויות שנכשלו) – תקלות שיש לנהל.
  • Orchestration – תיאום הפעולות בין כמה שרתים. למשל:
    • ביצוע שינוי מסוים באותו הזמן על מספר שרתים. אולי כדאי קודם לבצע בדיקה שמאשרת (כמיטב היכולת) שאכן כל השרתים מסוגלים לעבור את השינוי.
    • אם אחוז גבוה מהשרתים לא מצליח לעבור שינוי – אולי כדאי לעצור את השינוי המתגלגל, ולהתחיל פעולה של rollback (חזרה למצב הקודם)?
    • יש שינויים שצריכים להיעשות בצורה מדורגת כלשהי: קודם ביצוע שינוי בשרתי x ורק אח"כ אפשר לבצע את השינוי בשרתי y.

הכל כמובן – בצורה אוטומטית.

בפוסט הבא אני הולך לעבור בקצרה על כלי ה CM הנפוצים בשוק, ולסקור את המעבר שהם עשו ב 20 השנים האחרונות.

"דור ראשון"

CFEngine

את הכלי הזה יכירו בעיקר הוותיקים שבינינו. הוא התחיל לפעול ב93' (כלומר: שנת 1993- למי שלא הבין) והיווה מהפכה תפיסתית בעולם ניהול-השרתים. הוא התחיל כפרויקט קוד פתוח, אך ב 2008 נוספה לו גרסה "מסחרית" עם תמיכה – ומאז הוא משתמש בעיקר תצורות מסובכות של ארגונים גדולים.

CFEngine ממומש בשפת C, והוא ידוע במהירות הגבוהה שלו. מצד שני – הוא דורש ידע מלא בתכנות בשפת C על מנת לתפעל אותו, מה שמגביל מאוד את קהל היעד.

כלי זה, כמו הכלים הבאים אחריו עובדים ע"פ עקרון דומה:

  • שרת מרכזי מחזיק את התצורה הרצויה לסוגי השרתים השונים (ע"פ ארגון של קבוצות או כללים).
  • על כל שרת מותקן Agent שמתשאל מדי פעם את השרת המרכזי, וברגע שהוא מבין שיש לבצע שינוי תצורה (קרי: עדכון תוכנה, שינוי הגדרות, וכו') – הוא מבצע אותו.
    • כששרת מופעל בפעם הראשונה (לפעמים הוא כולל מערכת הפעלה ו Agent בלבד) – הוא יבצע את כל שינויי התצורה לפני שיתחבר ל Load Balancer (קרי: יהיה זמין לשאר ה Landscape).
איך CFEngine עובד. מקור: CFEngine.com

"דור שני"

Puppet

הכלי הבא שהופיע והשאיר חותם הוא Puppet, עם המטפורה המפורסמת של ה "Puppet Master" – השרת המרכזי שלו שהוא כמו "מפעיל בובות". גם Puppet החל בשנת 2005 כ Open Source ורק מאוחר יותר הופיעה גרסה מסחרית (Enterprise).
החידוש המשמעותי של Puppet היה שהוא לא דרש ידע מעמיק בתכנות, אלא כתיבת DSL (כלומר: Domain Specific Language) המבוססת על שפת רובי – דבר שצוות ה Operations של הארגון היה מסוגל לתפעל בצורה מלאה.

קוד Puppet לדוגמה

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

השפה של Puppet (או כלי CM אחרים) היא DSL שמותאמת לצרכים המאוד ספציפיים של ניהול תצורה, ועוזרת לשרת את קריאות הקוד (הקוד הרבה יותר נוח לקריאה מ bash) ולצמצם טעויות אפשריות. עוד ייתרון הוא היכולת להגדיר תצורה שתפעל על מערכות הפעלה שונות (דיסטרוס שונים של לינוקס, או אפילו לינוקס ו"חלונות").

השפה של Puppet מספקת שורה של פרמיטיבים (File, User, Package, Service, וכו') שניתן להרכיב למודולים (הניתנים לשימוש חוזר) או פשוט להוריד מוכנים מ PuppetForge[א]. היכולת לשתף מודולים ברמת הקהילה מסייעת לקיצור זמני-פיתוח והגברת אמינות ניהול התצורה – כל עוד מדובר במודולים איכותיים. יש לציין שלא כולם כאלו, וחשוב מאוד לברור את מקור המודולים בהם אתם משתמשים.

בזכות קלות השימוש – Puppet לקח מ CFEngine את הבכורה.

Chef

לא הרבה מאוחר יותר, בשנת 2008, הופיע כלי חשוב נוסף בשם Chef. גם הוא, אגב, כלל סדרת מטפורות בלתי-נשכחות ("Knife", "Kitchen", "Cookbook", ו "Recipe", וכו'). Chef שיפר כמה מהדברים שהציקו ב Puppet וזכה לפופולריות גדולה בעצמו. גם הוא – מבוסס על שפת רובי.
בשלב הזה Chef ו Puppet החלו בתחרות "ראש בראש", כאשר הם משלימים כל הזמן את הפיצ'רים החדשים אחד של השני. במהלך התחרות הזו נוספו לכל אחד מהם יכולות וכלים, מה שגרם להם בעצם להפוך מכלים פשוטים יחסית – לכלים מורכבים לשימוש, הדורשים מהמשתמשים למידה משמעותית.

בגדול, Chef נחשב יותר "ידידותי למפתח" (כזה שרגיל לכתוב בדיקות יחידה, ו/או לעבוד בכלי פיתוח)  בעוד Puppet מעט יותר ידידותי לאיש ה Operations (שאינו מתכנת).
יש אומרים ש Puppet נוח יותר לניהול תחנות עבודה של משתמשים, וש Chef – נוח יותר לניהול חוות שרתים (אולי בגלל ה output המפורט שלו שמסייע לאתר הבעיה – כאשר יש תקלות). בסופו של דבר, שני הכלים קרובים זה לזה ביכולות, ובבגרות. ל Puppet יש קהילה גדולה יותר, וב Chef מורכב יותר להתמקצע.

לא לזכותם של הכלים הללו ניתן לומר שהם כיום מורכבים למדי לשימוש, עבור רוב המשימות הנפוצות, וה Learning Curve שלהם הוא תלול ממה שארגונים רבים היו רוצים.

עוד נקודה מעניינת היא ששלושת הכלים שהזכרתי עד רגע זה (Chef, Puppet, ו CFEngine) תוכננו ונבנו בתקופה בה התפיסה הייתה לעדכן שרתים קיימים, ולאורך זמן.

אני אסביר: כאשר יש לכם שרתים פיסיים ("ברזלים"), התקנה מלאה של שרת עשויה לקחת עשרות דקות – ואפילו מספר שעות. לבצע את ההליך הזה אפילו פעם אחת בחודש – זו בעיה רצינית.
כלים כמו הכלים הנ"ל התמקצעו בנושא של עדכון הדרגתי של שרתים, מה שגם נקרא Convergence, קרי: א. בדוק באיזה מצב השרת, ב. עדכן את תצורת השרת, רק במה שצריך – לתצורה הרצויה (deltas). עדכונים כאלו יכלו להיות כל כמה ימים.

גישת ה Convergence אפשרה לבצע עדכונים תכופים בתצורת השרתים, מבלי לגזול זמן רב / לשלם ב downtime.
המחיר של גישה זו היא שניהול deltas לאורך זמן הוא מסוכן ולא יציב – ודברים יכולים (ואכן) נוטים להשתבש. למשל: מפתח התחבר ב SSH לשרת ושינה הרשאה של איזו תיקיה. עדכון נכשל והשאיר אחריו מצב בלתי רצוי שאינו מתוקן ע"י הגדרות התצורה של הכלי, וכו'.
הפתרון היה להחזיר שרת ל "baseline" – ברגע שדברים מסתבכים. לשלם את המחיר ההתקנה מחדש – בכדי לחזור למצב של סדר ושליטה.
הבעיה: בזמן שחלף עד שהבנו שהשרת הוא בתצורה בעייתית – התצורה הבעייתית יוצרת "רעש", ועוד רעש בפרודקשיין!

התפיסה השלטת היום היא תפיסה של Immutable Servers (או "כמעט Immutable Servers"), כאשר כל שינוי תצורה (או: כמעט כל שינוי תצורה) – משמעו ליצור Image חדש, נקי ומסודר של שרת, ולעדכן את המכונות הרצויות.
היכולת הזו מתאפשרת בעקבות טכנולוגיות הוירטואליזציה והענן שהפכו לנפוצות כ"כ, ומתקדמות צעד אחד נוסף קדימה בעקבות טכנולוגיה כמו Containers.

כלומר: כל פעם שאנו רוצים לבצע שינוי בשרתים (נניח להוסיף לשרת agent של logstash) – ניצור Image חדש ונקי, ונריץ את כלי שלבי ה provisioning מאפס עד לקבלת שרת בתצורה הרצויה (כולל השלב החדש של התקנת ה logstash agent). כעת נייצר מהשרת הזה Image ואת ה Image הזה – נתקין על המכונות הפיסיות בפרודקשיין.

גישת ה Immutable Server נחשבת אמינה ופשוטה יותר לשליטה – ולכן עדיפה. החיסרון: שינויים קטנים עדיין דורשים בנייה של Image – תהליך שיכול לארוך זמן רב (עשרות דקות עד שעות).
אם כל השינוי הנדרש בשרת הוא העתקה של קובץ בודד, שינוי הרשאות על תיקיה, או שינוי הגדרה – רבים מאיתנו יעדיפו שיהיה על השרת גם כלי CM בעזרתו יוכלו לבצע את השינוי בזריזות. הזריזות הזו חשובה מאוד כאשר יש להגיב לתקלות בפרודקשיין. במקביל, ניתן לבצע את השינוי בצורה מסודרת על ה Image ו"ליישר קו" ב deployment הבא.
גישה זו, היא גישת ה "כמעט Immutable Servers" – המשלבת בעצם בין שתי הגישות.

שינוי הגישה מניהול תצורה בעזרת deltas שמתמשכים למשך חודשים, לצורה של "Immutable Servers" או "כמעט Immutable Servers" (לא ידוע לי על מונח מוסכם) פתח הזדמנות לכלים פשוטים משמעותית, שלא צריכים להתמודד עם המורכבות הרבה של ניהול deltas בתצורת השרת – להצטרף לזירה.

אפשר לציין ש Chef ו Puppet הם עדיין הכלים הנפוצים. הם שולטים בזירת ה CM כבר זמן רב, והשפיעו עליה ועל עולם התוכנה רבות.

"דור שלישי"



Ansible

בשנת 2012, הופיעו כלי CM חדש בשם Ansible ששינה הרבה מצורת העבודה של Chef ו Puppet:

  • ניהול העדכונים: במקום שיהיה שרת מרכזי (או כמה לצרכי HA ו Scale) אליו כל ה Agent פונים ב pull, הגישה היא לבצע push: אתם פונים לשרתים השונים ואומרים להם לבצע את השינוי.
    • יתרונות: הסרת שרת הקונפיגורציה מה landscape. הבדיקות של תצורות חדשות נעשות ב cycles קצרים יותר, ב push העדכונים מגיעים לשרתים מהר יותר. קל לשימוש בסביבת פיתוח, בה ניתן לפתוח laptop ולעדכן שרת – בלי להתקין ולתחזק "שרת מרכזי".
    • חסרונות: כאשר מדובר ב scale גדול (מאות ואלפי שרתים) – עדכון השרתים ב push ייקח יותר זמן. אם בדיוק עלה שרת חדש לפני שיש image מעודכן – הוא עשוי לפספס את העדכון.
  • שפת התכנות: במקום DSL ומיומנויות של semi-תכנות, ההגדרה של התצורה נעשית בעזרת קובץ yaml פשוט.
    • יתרונות: הרבה פחות "קוד" לכתוב. זמן למידה קצר בהרבה של הכלי. אין צורך ברקע בתכנות בכלל על מנת ליצור הגדרות תצורה.
    • במקום שפת תכנות שיוצרת הפשטה מעל כל סוג של מערכת הפעלה, שכבת ההפשטה היא רזה. יש מודול לפקודות apt (נניח אובונטו) ומודול לפקודות yum (נניח Red Hat). ההפשטה הרזה לא מאפשרת "לכתוב סקריפט אחד שמתאים לכל מערכת הפעלה", אך מפשטת מאוד את הלמידה (כי אתם יודעים כיצד apt או yum עובדים, ומקלה להבין מה קורה בפועל.
    • חסרונות: פחות גמישות: בעיות CM מורכבות יידרשו כתיבת סקריפט מיוחד (בעיקר: שימוש ב Jinja2 – שפת templates בה ניתן לכתוב מעט קוד פייטון או להפעיל קוד bash).
    • הערה: Ansible הושפעה מפייטון (השפה בה היא כתובה) בגישת ה "Batteries included". המודולים הטובים שנכתבו / אושרו ע"י Ansible הם חלק מהכלי, ולא צריך להוריד אותם מ repository מרכזי כמו Chef או Puppet.
  • אין Agnets: אין צורך להתקין Agent (להלן Chef-Client או Puppet-Agent): על גבי השרתים. Ansible משתמש ב SSH סטנדרטי (ליתר דיוק: OpenSSH) בכדי לגשת לשרתים ולבצע בהם שינויים. עבור Windows – משתמשים ב PowerShell remoting.
    • יתרונות: אין צורך בהתקנה, עדכון, וניטור של Agents על גבי השרתים. רק צריך שרת עם SSH ו Python 2.5.
    • חסרונות: SSH הוא אטי יותר (פחות מתאים לעדכון אלפי שרתים),
Salt (מבית SaltSlack)
מעט לפני Ansible הופיעה ספרייה בשם Salt.

בכמה מובנים, Slat דומה למדי ל Ansible: הגדרות התצורה מוגדרות ב Yaml ולא בשפת תכנות, והוא פשוט בסדר גודל מ Chef או Puppet.
Salt ו Ansible שניהם כתובים בפייטון (Chef וגם Puppet כתובים בשפת רובי).

בכל זאת, הגישה של Salt להעברת העדכונים לשרתים – היא דיי דומה לזו של Chef ו Puppet.

המוטיבציה המוצהרת ליצירת Slat הייתה עדכון תצורה מהיר של קנה מידה גדול של שרתים. נראה שיצירת סביבת עבודה פשוטה יותר מ Chef/Puppet הייתה מהלך טבעי, אך משני – בתכנון של Salt.

  • השרת (הקרוי Slat Master) מבצע עדכונים ב push לתור של ZeroMQ. על השרתים מותקנים Minions (סוג של agents) שמאזינים לעדכונים על ה Queue ומבצעים מייד את העדכון. זו גישה משולבת בין ה Push של Ansible וה Pull של Chef/Puppet, שמבטיחה בד"כ זמני תגובה מהירים יותר מ Chef/Puppet (כי יש Push), ו scalability גבוה – היכולת לעדכן אלפי שרתים במקביל.
  • ניתן להגדיר ה Salt Master בהיררכיה כך שיש Centralized Master אחד שמגדיר מה לעשות, אך כמה Masters תחתיו שמפיצים את הבשורה לשרתים שונים. גישה זו יכולה לספק Scale גבוה אף יותר (נאמר: עשרות אלפי שרתים?)
בשנת 2014 Salt הציג Queue ייעודי משלו בשם RAET שהוא Scalable ואמין יותר מ ZeroMQ – לצורך הספציפי.
עידן ה Docker – "דור רביעי?"
כל כלי ה Configuration Management שותפים למורכבים מסוימת, מורכבות שנובעת מהקושי לבצע provisioning למערכת על "שרת אמיתי בפרודקשיין". מה לעשות: אתם זקוקים לכלי מוניטורינג, אבטחה, לוגים, הגדרות, וכו' – תצורת השרת היא מורכבת.Docker הוא כלי שמנבאים שיחולל מהפיכה לא רק בסביבת ה Production – אלא גם בעולם הגדרות התצורה.
מכיוון ש Docker "מפרק" את סביבת השרת להרבה Containers קטנים, הוא גם הופך את בעיית ניהול התצורה לסט בעיות קטנות יותר: תצורת ה Application Server ב Container A, תצורת ה Nginx ב Container B, ותצורת ה Monitoring Deamon ב Container C. על אחד מהן עשויה להיות בלתי תלויה, ופשוטה הרבה יותר מתצורה כוללת.

ה dockerfile, אם כן, הוא בערך כמו קובץ ה Yaml של Ansible או Salt, המאתר כיצד להתקין תהליך ואת התלויות שלו. טעינה מחדש של container היא כ"כ מהירה (עשרות שניות) – שניתן (אולי?) להסתפק בגישה טהורה של "Immutable Servers".

מצד שני, לנהל אלפי containers (הנחה: על כל שרת יש 5-10 containers) – זו משימה קשה בהחלט! זו בעצם בעיית ה Orchestration ש Docker איננו מכסה. למשימה זו, נבנים כיום כלים ייעודיים, שהמוכרים ביניהם הם:

  • Kubernetes – כלי מבית גוגל, המשתמש בניסיון הקיים של גוגל בעבודה עם Linux Containers וניסיון שהצטבר עם כלי פנימי של גוגל בשם borg – האחראי על ה provisioning של השרתים הרבים מאוד ב Data Centers של גוגל. בעצם, גוגל כבר עושה היום משהו דומה.
    הניסיון הזה מתבטא למשל, בכל ש Kubernetes פתרה בעיות של Docker עצמו שהיו קיימות בגרסאות מוקדמות.
    Kubernetes מציע פתרון שלם יחסית, עם etcd ל container discovery, עם flannel לניהול הרשת בין ה containers (עניין מסובך ומתיש), ועוד.
    לסביבה העשירה הזו יש מחיר: יש לכלי CLI משלו, API משלו, וקבצי YAML משלו להגדרות התצורה – וזו סביבה שיש ללמוד להשתמש בה, בנוסף ל Docker.
  • Docker Swarm – הוא כלי אשר נוקט בגישה כמעט הפוכה: הוא תומך ב API הקיים של Docker, ובסביבת ה CLI – מה שאומר שקל מאוד להשתמש ב Docker Swarm עם ה toolchain הקיים של Docker (למשל: Docker Machine (לשעבר Krane) או Compose, וכו').
    Docker Swarm מתוחזק ע"י קהילת ה Docker, והוא חלק מ"פתרון כולל" שנבנה בתוך קהילה זו לניהול תצורה.
    האם זו בהחלט הגישה המועדפת? קשה לומר. התאימות ל Docker API מגבילה את הכלי למגבלות של Docker עצמו ומקשה עליו לבצע חלק מהדברים שניתן יהיה לעשות ב Kubernetes.
זה לא כ"כ משנה איזה עוד כלים קיימים או ייווצרו בקהילה של Docker.
אם וכאשר Docker יהפוך לסביבת ה Deployment המקובלת ב Production – הוא עתיד לבצע Disruption גם בעולם ה CM ולשנות אותו משמעותית ממה שאנו מכירים אותו היום.

סיכום

אם תשאלו את מי שעובד עם כלי CM כלשהו, מהו הכלי הטוב ביותר – יש סיכוי סביר שהוא יצהיר על הכלי שבו הוא כבר עובד. מדוע? כי לכלים הללו יש learning curve לא פשוט של התמחות. אם כבר מתרגלים לכלי ומתמחים בו – קשה ליזום החלפה שתדרוש למידה והסתגלות משמעותית מחדש. כפי שלא מחליפים מערכת תוכנה במכה אחת – כך גם בד"כ לא מחליפים סביבת CM במכה אחת.

הכלי הנכון ביותר לשימוש – משתנה עם הזמן, מכיוון שבחברות הצרכים משתנים: פעם יש רק לינוקס (נניח RedHat) ואז יש גם OpenSuse ו Windows. פעם ה deploy הוא תהליך חודשי – ולאחר מכן כבר מדברים על Continuous Deployment. פעם זה על שרתים של הארגון, ומעט אחרי זה – בענן. פעם על VMs וקצת אחרי זה על Containers.
הצרכים הארגוניים משתנים ככל כנראה מהר יותר ממה שניתן להסתגל לכלים השונים, ומכאן ניתן להסיק שאחוז גבוה מהארגונים משתמש בכל רגע נתון בכלי CM שאינו אופטימלי לצרכים שלו.

ישנה תקווה אמיתית שכלים חדשים ופשוטים יותר (Ansible או Swarm, למשל) יאפשרו לארגונים לבצע שינויים תכופים יותר בצורת העבודה – ולהתאים בצורה טובה יותר את מערכת ה CM לצרכים המשתנים של הארגון.

שיהיה בהצלחה!

—–
קישורים רלוונטיים
Chef vs. Ansible vs. Puppet vs. Salt בהקשר של OpenStack – אך עדיין מעניין ורלוונטי.

http://martinfowler.com/bliki/ImmutableServer.html – פוסט של מרטין פאוולר על Immutable Servers.

http://techblog.netflix.com/2013/03/ami-creation-with-aminator.html – פוסט מהבלוג של Netflix שמתאר את תהליך ה Provisioning שלהם

על Convergence מול Immutable Deployment

—–
[א] רמז לכך ש puppet נבנה בימים בהם הכלי המקובל לניהול קוד פתוח היה SourceForge? היום בוודאי היו קוראים לו PuppetHub…

כללי התיכנותיקה – 19 כללים של הנדסת תוכנה שלא ניתן להתחמק מהם

בתוכנה, כמו בתחומים אחרים – יש כללים שעוזרים לנו לכוון בצורה יעילה יותר את העשייה שלנו.
כמה מהכללים הללו הם נכונים רק לפעמים, וטובים בהקשרים מסוימים, וכמה כללים אחרים הם "כללי ברזל" שנכונים במעט בכל סיטואציה. כללים שהם ממש כמו "חוקי הפיסיקה של התוכנה".מכיוון שאין להם שם מוכר, נתתי להם שם: "כללי התיכנותיקה" (הלחם לשוני של "תכנות" ו"פיסיקה").

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

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

הנה הם לפניכם:
Conway’s Lawארגוניארכיטקטורה
"מבנה התוכנה והקשרים בין חלקיה, סופם שיהיו שיקוף של המבנה הארגוני של הארגון בה היא מפותחת" (רפרנס)
הסבר: המבנה הארגוני הוא כוח חזק מאין כמוהו, שלא ניתן להתעלם ממנו. למשל: אם אתם מתכננים קומפיילר בין 4 שלבים, אך יש לכם 3 צוותי פיתוח – סביר שבסופו של דבר אחד השלבים יהיה אנמי, ובפועל יהיה לכם קומפיילר עם 3 שלבים. הפתרון – להכיר במציאות: או שתתכננו קומפיילר בין 3 שלבים, או שתארגנו את האנשים ב 4 צוותים.

עיקרון פארטו כללי
"במקרים רבים, 80% מההשלכות (effects) נובעות מ 20% מהגורמים הפעילים (causes)"
רקע: ידוע גם בשם "כלל 80-20", והוא כלל שנוסח על ידי הכלכלן האיטלקי וילפרדו פארטו, לאחר שראה את פיזור העושר באיטליה במאה ה-19 (כיום, פיזור העושר הוא קיצוני הרבה יותר, ואולי לא משקף כבר "התפלגות טבעית של סיבה ותוצאה").
וריאציה א: מוצר
"80% המערך של מוצר, ניתן להשיג ב 20% מההשקעה"
וריאציה ב: קוד
"80% מהבאגים המשמעותיים, נובעים מ 20% מאזורי הקוד"
וריאציה ג: ארגוני
"כ 66% מהעשייה המשמעותית, נעשית על ידי כ 33% מהמתכנתים", מה שמתבטא גם ב:


כלל הכישרון ארגוניטכנולוגיה
"האלמנט שמנבא בצורה הטובה ביותר הצלחה או כישלון של תוכנה הוא לא הטכנולוגיה, שפת התכנות, או ה Framework – אלא המתכנתים שכותבים את התוכנה"

עקרון הדורות המקוצרים (short generations) כללי
"כל עשור יהיה על איש התוכנה ללמוד 50% מהמקצוע מחדש"
וריאציה: "כל עשור, 100% מהטכנולוגיות שבשימוש – יתחלפו".
מי שלא מוכן / מבין את ההשקעה הנדרשת בכדי להישאר במקצוע – ייפלט מהתחום במשבר הראשון לאחר מעבר של "דור".


עקרון ה-Code is everythingקוד
"אפשר להתווכח כמה שרוצים, האמת נמצאת במקום אחד: בקוד".
לסירוגין: "מסמכי Design אינם מתקמפלים".
הסבר: להנדסת תוכנה יש הרבה תוצרים מופשטים: רעיונות, מסמכים, תחזיות, ותוכניות. יש תוצר אחד שהוא מוחשי וקונקרטי מאין כמוהו: הקוד. חשוב לזכור שמה שקובע זה לא מה שתכננו, רצינו או התכוונו שיקרה – התוכנה היא מה שכתוב בקוד.


עקרון ה Not Invented Here (בקיצור: NIH) קוד הטיה אנושית
"הדשא של השכן ירוק יותר, אך הקוד של השכן הוא גרוע, לא מובן, ולעתים פשוט מטופש"

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

"Code Rots"
כלומר: קוד שלא עובר חידוש (refactoring) – הולך ו"נרקב" ואיכותו פוחתת. השקעה רק בפיצ'רים, ללא השקעה בחידוש הקוד תביא את הקוד למצב שאיננו ניתן יותר לתחזוקה, ויש לכתוב אותו מחדש. Guideline מקובל לאורך החיים של תוכנה עד לשלב בו יש לכתוב אותה מחדש (אם לא בוצעו פעולות refactoring, "הזרמת חמצן") הוא 3 עד 5 שנים.
היבט נוסף הוא העיקרון ש"קוד שלא נקרא כחצי שנה – הופך לקוד זר ולא מוכר" (ידוע כ Eagleson's Law). רמת הקריאות של הקוד, ועוצמת המסרים והעקרונות המשתקפים מהקוד – משפיעים רבות על קצב ה"ריקבון" של הקוד.


Lubarsky's law of Cybernetic Entomology קוד
"תמיד יש עוד באג אחד במערכת"
למשל: לאחר 11 שנה של שימוש המוני, נתגלה באג באלגוריתם החיפוש הבינארי של ספריית Java הסטנדרטית. (באג מאוד פינתי, כמובן).


לחלופין: Linus’s Law – הופרך כמיתוס
"Given enough eyeballs, all bugs are shallow".
כלומר: בהינתן מספיק עיניים בוחנות – כל הבאגים יימצאו.
הכלל נקרא על שם לינוס טורבאלדס, יוצר הלינוקס, מכיוון שהוא מבטא סוג של הנחה סמויה של קהילת הקוד הפתוח. הכלל לא הוגדר ע"י לינוס, אלא על ידי אדם אחר, אריק ריימונד.

הוכח מאז, במספר מחקרים, שיש תועלת שולית פוחחת משמעותית למספר ה Reviewers של קוד, ומעבר ל 3-4 reviewers כמעט ואין שיפור באיכות של קטע קוד (גם כי נותרים הבאגים הקשים יותר לגילוי, וגם כי אנשים מניחים שהקוד כבר נבחן בצורה מספיק טובה, ומסירים מעצמם אחריות / חשיבה ביקורתית).


ללא שם (Michael Nygard)פרודשיין
"משתמשים מגבירים בצורה בלתי-מוגבלת את אי-יציבות המערכת"
בנוסח אחר: "לעולם לא ניתן ליצור סביבת stating/testing שתחווה את כל הבעיות של סביבת production".
זו גם סוג של עקיצה למי שכותב תוכנה ללא משתמשים, ונמצא ב"אשליה" שהקוד שלו יציב, scalable, וכו'.
הכלל הוזכר לראשונה בספר (המצוין!) "!Release It"

Wirth’s law פרודשיין
"התוכנה הופכת איטית בקצב מהיר יותר, מהקצב בו חומרה נהיית מהירה"
הסבר: למרות שחומרה נעשית כל הזמן יותר מהירה (לסירוגין: שירות ענן נעשה זול), לא ניתן להסתמך על העובדה הזו בשיקולי ביצועים של תוכנה.
הרגרסיה הטבעית בביצועים של התוכנה (תוכנה שעדיין מוסיפים לה יכולות) היא מהירה יותר מהתקדמות הטכנולוגית של החומרה – ולכן תמיד יהיה צורך ב"שיפורי ביצועים" בתוכנה על מנת לשמר את רמת הביצועים שלה.


Sturgeon’s Revelation כללי
"90% מכל דבר זה שטויות"

או בצורה היותר מנוסחת שלו: "בני-אדם יודעים לבנות ציפיות הרבה יותר טוב ממה שהם יודעים לספק ציפיות. ב 90% מהמקרים אנו צפויים להתאכזב ממה שציפינו – כי בניית הציפיות הייתה טובה יותר מסיפוקן".
וריאציה: טכנולוגיה
"90% ממקרי האימוץ של טכנולוגיה חדשה – יהיו שגויים או לא יעילים".
במלים אחרות: לעתים רבות, יותר יעיל להתמקצע ולהבין כיצד לעבוד נכון עם הטכנולוגיה הנוכחית, מאשר לאמץ את הטכנולוגיה החדשה והנוצצת.


The Hype Cycleטכנולוגיה

הסבר: טכנולוגיות חדשות נוטות לחזור אחר אותו מחזור של Hype שטכנולוגיות עבר עברו:

  • הטכנולוגיה נחשפת לראשונה והציפיות ממנה גדלות בקצב תדיר. רוב השיח הוא על חזון, ולא פרקטיקה.
  • יש אינפלציה של ציפיות בלתי הגיוניות. אנשים מקשרים את הטכנולוגיה לתמונה אידאליסטית ומדומיינת – שאיננה מציאותית.
  • ישנו תהליך ארוך וכואב של התפכחות, בו מועלים החסרונות של אותה טכנולוגיה – לעתים כסדרה של השמצות וביקורות מוגזמות.
  • אנשים מבינים בהדרגה את השימושים, היתרונות, והמגבלות של הטכנולוגיה, ומתחילים להשתמש בה בצורה יעילה / נכונה / עם ציפיות מציאותיות.
  • הטכנולוגיה מגיעה לבגרות ומפיקה את המירב שניתן.
 
הנה דוגמה למיפוי של טכנולוגיות עכשוויות, והמיקום שלהן ב Hype Cycle:
 
כלל תקורת ההטמעה מתודולוגיהטכנולוגיה
אימוץ כלי או מתודולוגיה חדש, מפחית את הפריון ואיכות המוצר לתקופה מסוימת. התמורה המושגת מהמעבר לכלי / הטכניקה החדשה (בהנחה שהיא עדיפה להקשר) – תורגש רק לאחר זמן מה (נאמר: 6 חודשים).


כלל ההקשר השגוי מתודולוגיה
"אין רעיון טוב שלא ניתן להשתמש בו בצורה שגויה לחלוטין" (ידוע גם כ Flon’s Axiom)



חוק ה 90-90 ניהול זמנים / פרויקטים
"90% מהקוד – ייכתב ב 90% מהזמן. יתר עשרת האחוזים מהקוד – ייכתבו ב 90% נוספים מהזמן." (רפרנס)
יש כמה כללים דומים שמבטאים רעיון דומה:

  • "הערכת חסר תינתן, גם כאשר אנו יודעים שאנו נוטים לתת הערכות חסר." (Hofstadter's Law)
  • "הזמן המוערך לסיום פרויקט תוכנה הוא פונקציה מונוטונית עולה."
  • "הזמן שנותר לסיום הפרויקט – הוא תמיד קבוע". (Hartree's Law)

בקיצור: הערכות זמנים בתוכנה הן בהגדרה לא מדויקות, ונוטות להערכת חסר. אחת הסיבות לכך היא שבמהלך הדרך אנו מוסיפים תכולה לא-מתוכננת: "אבל חייבים שזה יהיה ככה – לא הגיוני אחרת!" ("ככה" = תוספת לא מתוכננת).



חוק פרקינסון ניהול זמנים / פרויקטים
"העובדה מתרחבת על מנת למלא את לוח הזמנים שניתן לה" (רפרנס)
הסבר: אם הגדרנו של פרויקט נתון מוקצבים 6 שבועות עבודה, גם לו תאורטית יכולנו לסיים ב-4 שבועות – בלי לשים לב אנו נמלא את כל ששת השבועות שהוקצבו (בעזרת הפחתת מהירות, או הכנסת עבודה נוספת).


Brook’s Law ניהול זמנים / פרויקטים
"הוספת אנשים לפרויקט מאחר ובשלב מתקדם – רק תגרום לפרויקט לאחר יותר" (רפרנס)
הסיבות:

  • יש זמן ramp-up עד שאנשים משתלבים בפרויקט ונהיים יעילים בו: זמן למידה וזמן הסתגלות של הסביבה אליהם.
  • התפוקה השולית הפוחתת של כל עובד נוסף בפרויקט – יורדת. בהגדרה: פרויקטים קטנים יותר (מעט אנשים) הם יעילים יותר מפרויקטים גדולים.

צורה אחרת: "The bearing of a child takes nine months, no matter how many women are assigned"


The Bergman Dilation ("התרחבות ברגמן") ניהול זמנים / פרויקטים
"לא תמיד יש זמן לכתוב את הקוד בצורה נכונה, אך ברוב הפעמים יש זמן לכתוב את הקוד מחדש".

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


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



שיהיה בהצלחה!

מבוא לאבטחת מידע ("סייבר" ושטויות שכאלו) – חלק ב'

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

לא עניתי אבל על השאלה המתבקשת: "מה עושים?" כיצד מתגוננים ו/או מתכננים מערכות תוכנה מאובטחות יותר[א]?

– על שאלות אלו אנסה לענות בפוסט הנוכחי.

מודל ה-CIA

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

  • Confidentiality (סודיות) – מניעת חשיפה לא מורשית של מידע.
    • אבני יסוד בהגנה: Authentication (אימות זהות), Authorization (ניהול הרשאות), והצפנה.
  • Integrity (שלמות הנתונים) – מניעת שינוי לא רצוי של נתונים, זיוף נתונים, או השחתת נתונים. הידיעה שנתונים שמשתמשים ניגשים אליהם הם אותנטיים ולא שונו ע"י גורם עויין.
    • אבני יסוד בהגנה: חתימה דיגיטלית, Authentication, ו Audit (רישום הגישות לנתונים)
  • Availability (זמינות) – ווידוא שניתן לגשת לנתונים בכל זמן.
    • אבני יסוד בהגנה: יתירות, וגיבויים / Disaster Recovery.
לשם המודל אין קשר לארגון הביון המרכזי, אולי מלבד מהכוונה לגרום לשם להיות קליט יותר.
המודל עוזר לנו לחשוב על האלמנטים שיש לאבטח על מנת לספק "אבטחת נתונים", ורק שילוב של שלושתם – באמת מספק אבטחה
.
למשל: נניח שיש גורם שמצפין את המידע שלי בהצפנה כפולה: ה Confidentiality בשמיים – לא ניתן לגשת למידע. אבל אם גם אני לא מסוגל לגשת למידע, כי אין לי את המפתח להצפנה (Availability) – אז מה הטעם?!זה בדיוק מה שתוכנות ransomware עושות – והן פוגעות באבטחת המידע שלנו, אפילו שהן "רק מצפינות אותו עוד יותר" (כי לנו אין את מפתח ההצפנה, ויהיה עלינו לשלם כופר על מנת לקבל אותו).

4 עקרונות יסוד נוספים

מודל ה CIA הוא שימושי – אך כנראה הוא המודל הבסיסי ביותר שניתן לחשוב עליו. להלן קבוצה של עקרונות יסוד חשובים שליקטתי. העקרונות הללו הם ה Design Principles היסודיים, בחשיבה על תכנון מערכת כמערכת מאובטחת.

Non-Repudiation (אי-התכחשות)

בכל גישה למשאב ו/או ביצוע פעולה, חשוב מאוד שיהיה ברור מי האדם שביצע את הפעולה.
הידע מי ביצע את הפעולה מאפשר לנו להגביל פעולות מסוימות (Access Control => Confidentiality), יכולת ניטור הפעולות (Monitoring => Anomaly Detection) ויכולת לבוא "בחשבון" עם מי שביצע פעולה לא ראויה (Forensics => התרעה).
את אי-ההתכחשות משיגים ע"י:
  • Authentication (אימות זהות) – ארחיב עליה בהמשך.
  • Audit או לוגים – רישום מה קרה ומי עשה את זה ומתי.
דרכים מצוינות "למסמס" אי-התכחשות הן:
  • לחלק את אותו username והססמה לקבוצת אנשים – ואז לא ניתן לדעת מי מהם ביצע את הפעולה, או האם הקבוצה בעצם התרחבה ללא "כוונת המשורר".
  • להשתמש במערכת ב"משתמשים טכניים" (technical users) להם יש הרשאות עדיפות ואיתם מבצעים את הפעולות הרגישות – תוך כדי שממסכים מי המשתמש האמיתי שיזם את הפעולה.
    • דוגמה: הפקודה "sudo bash" בלינוקס.
    • דוגמה נוספת: משתמש הפעיל חישוב של דו"ח / תהליך במערכת, והמערכת מעבירה SQL Query למשתמש טכני (שלו יש גישה מלאה לבסיס הנתונים – כי למשתמש לא נתן כזו גישה! חס ושלום). כשנגלה שמשהו לא טוב קרה בבסיס הנתונים ע"י המשתמש הטכני – לא נדע לקשר זאת לגורם אנושי.
כמה מלים על ססמאות כאמצעי אימות-זיהוי (Authentication)
לכאורה הדרך הקלאסית לזהות משתמש הוא לבקש ממנו שם משתמש וססמה. מן צירוף שרק המשתמש יודע, ואם מישהו הקליד אותו – זהו בוודאי המשתמש!
אבל:
  • לבני האדם יש דברים חשובים יותר בחיים משינון ססמאות מורכבות. רובנו "נופלים" לאותן ססמאות חוזרות (12345, password, querty, וכו') – מה שמקל על תוקף פוטנציאלי "לנחש" את הססמה שלנו. בעזרת "מילון" / סטטיסטיקה של הססמאות הנפוצות ביותר, ואולי ע"י כמה פרטי רקע שניתן למצוא עלינו ברשת. פעמים רבות יהיה ניתן "למצוא" את הססמה שלנו גם בלי להכיר אותנו באופן אישי.
    מכירים את המסכים עליהם מודבק פתק PostIt עם הססמה למערכת?
  • בעזרת תוכנת מחשב פשוטה ניתן לנסות ולנחש את הססמה שלנו ב Brute force: פשוט לנסות שוב ושוב עוד קומבינציות. אולי מילון של 8000 ססמאות נפוצות (יש כאלו לשפות דיבור שונות), ואולי לנסות את כל האפשרויות לאורך זמן. עדיין קיימות מערכות רבות שלא ינסו לחסום את המשתמש, גם כאשר הוא מנסה להיכנס למערכת עם אלפי ססמאות שונות בכל שעה, ובמשך ימים רבים.
    • ה Password Strength Meter של My1Login יעריך את חוזק הססמה כנגד Brute Force וייתן כמה טיפים. למשל: מדוע הססמה "MyPasswordIsStrong" היא חלשה למדי.
  • חלק מהחלשות שלנו כבני אנוש הן חולשות חברתיות, אותן תוקפים יודעים לנצל – מה שנקרא Social Engineering.
    • אם מישהו ממש נחמד יבקש מכם עזרה – לא תעזרו לו?
    • נניח שלא. אם הוא יעשה משהו טוב עבורכם ואז יבקש עזרה בחזרה – לא סביר יותר שתעזרו לו בחזרה? לא תתנו לו "רק לדקה" את הגישה שלכם למערכת כדי לעזור לו "במצוקה"?
    • יש סיפור על בחור אירופאי שחדר ל CIA אי שם בשנות ה-90 עם אפס אמצעים. הוא ראה בספר הטלפונים את מרחב מספרי הטלפונים של ה CIA (כולם מתחילים ב….) והתקשר באופן אקראי למשתמשים. הוא הציג את עצמו כאיש IT ואמר שהוא ממש מתנצל, אבל בשל בעיה הוא חייב לנתק אותם לכמה שעות מהמערכת.
      "אבל זה לא אפשרי! אני חייב לעבוד!" – רטן עובד ה CIA האקראי בצד השני.
      "אתה יודע מה…" גילה אמפתיה חברית איש ה-IT מדומה "תן לי את הססמה שלך ואני אסדר לך משהו. אבל אל תגלה לאף אחד!". כמה עובדים נידבו את שם המשתמש והססמה שלהם לקול בטלפון (שבכלל מקורו באירופה) – הכל מרצון טוב להמשיך לעבוד ולא להתבטל…
      התוקף, חדר למערכת, כמשתמש לגיטימי – מתחת לרדאר של כל אמצעי ההגנה (שהיו מקובלים אז).
מה אפשר לעשות?
עולם האבטחה נוטה לחלק את סגנונות אימות זהות המשתמש לשלושה Authentication Factors:
  • Something you Know – כמו ססמה או שם חיית המחמד הראשונה שלכם.
  • Something you Have – למשל כרטיס עובד, קוד שנשלח למכשיר הטלפון (הטלפון = something you have), או Certificate שמותקן על המחשב האישי (עדיף נייד).
  • Something you Are – למשל מדדים ביומטריים כמו: טביעת אצבע, חתימה, קול, צילום רשתית (זה כבר לא מדע בדיוני), צורת הליכה (שמסתבר שהיא דיי ייחודית – כמו טביעת אצבע), וכו'.
דרך אחת לחזק את יכולת האימות היא לחזק Factor ספציפי: לתת ססמה ארוכה, או לשאול אודות שם הילדה שישבה אתכם לשולחן בכיתה ג'. חיזוק שכזה הוא לעתים מתיש, וגורם למשתמשים "למאוס" בשיטה ולנסות לחפש קיצורים – מה שבד"כ לא טוב לרמת האבטחה.דרך מקובלת יותר היא לבצע Multi-Factor Authentication (בקיצור: MFA), כלומר לאמת את המשתמש ע"פ 2 Factors שונים של אימות זהות: ססמה וגם קוד שנשלח לטלפון. השילוב הזה (נניח לגישה מהבית / בעשות לא אופייניות) הוא לא מטריד כ"כ, אך הוא מקשה מאוד על תוקף פוטנציאלי להתחזות אליכם.
דוגמה נפוצה אחרת ל MFA הן מכשיר כספומט שדורש גם כרטיס אשראי וגם קוד PIN.

MFA הוא סוג של Defense-In-Depth – עקרון שעליו נדבר בהמשך.

Implicit Deny (בסלנג: "נופל סגור")

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

  • כי לא לאפשר גישה – אומר שלא ניתן לגנוב מידע.
  • כי אם נרשה גישה גם במצבי קצה – האקרים יכולים ללמוד עליהם ואז דרכם נעשית קלה יותר: עליהם "להביא" את עצמם למצב קצה – ואז הם "בפנים".
כשעבדתי בחברת סאפ – זו הייתה הפרקטיקה המקובלת. סאפ היא חברה לתוכנה עסקית – ואבטחת מידע הייתה ערך חשוב בחברה.
כשעבדתי בחברת אימפרבה, חברה של מוצר אבטחה (WAF לסוגיו. אסביר מה זה WAF בהמשך) – דווקא נקטנו בגישה של "נופל פתוח".למה? האם חברת אימפרבה דאגה פחות לאבטחה?
התשובה היא כזו: סאפ היא זו שכתבה את המוצר, ידעה מה באמת הצרכים העסקיים, ויכלה לשנות אותו ע"פ הצורך כך שגם כאשר יש Implicit Deny – המשתמשים לא נפגעים יותר מדי.
המוצר של אימפרבה הוא מוצר חיצוני, שיש לו מעט מאוד מידע על הנעשה במערכת וכיצד נכון להשתמש בה. אם בכל פעם שיש ספק היינו חוסמים את המשתמש – סביר שהרבה משתמשים היו נחסמים הרבה פעמים, ומביעים תסכול שיגרום מן הסתם ל"הרגעת" מערכת האבטחה הסוררת. זה לא מקום שחברת אבטחה יכולה להרשות לעצמה להגיע אליו.

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

Defense In Depth (הגנה לעומק)

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

הדרך הטובה ביותר להסביר לעומק עקרונות של אבטחה הם מתוך העולם המוכר המוחשי.

חומת ברלין היא דוגמה קלאסית ל"הגנה לעומק". אני אעבור בקצרה על אמצעי-ההגנה (ה Controls) העיקריים שהיא כללה, מימין לשמאל בתרשים:

  • קיר בטון חלק בגובה 4 מ' – הקשה מאוד לטיפוס.
  • שדה של ברזנטים מחודדים (spike mats, נקרא "הדשא של סטאלין") שמקשה מאוד על ריצה והופך נפילה למסוכנת.
  • גדר חשמלית.
  • מחסומי טנקים – שנועדו לחסום מעבר של רכבים.
  • 302 מגדלי שמירה עם שומרים חמושים שלא יהססו לירות בדמות לא ברורה.
  • פטרול של שומרים מלווים בכלבי תקיפה + שביל גישוש (שביל עם חול מיושר) ברוחב 6 עד 15 מ' שאדם שיעבור דרכו ישאיר עקבות – וכך ידעו על הימצאותו.
    • שביל הגישוש הוא יתיר לגדר החשמלית – לזיהוי חדירה של גורם לא מורשה למרחב.
  • מרחב גדול שהושטח על מנת להסיר מקומות מחבוא אפשריים – בו דמות שעוברת תהיה בולטת. נקרא "רצועת המוות".
  • תעלה למניעת מעבר כלי רכב.
    • זוהי הגנה יתירה למחסומי הטנקים, שהזכרנו קודם לכן.
  • קיר בטון חלק בגובה 4 מטר עם גדר תיל בראשו – החומה שגבלה עם גרמניה המערבית.
לעבור את חומר ברלין היה קשה מאוד – זה היה מנגנון הגנה אפקטיבי. רוב הנמלטים דרך חומת ברלין – היו בכלל שומרים שהוצבו בחומה.
האם לא היו בריחות ממזרח גרמניה למערב? היו. הם פשוט מאוד התבצעו במקומות אחרים ולא בברלין. זה מלמד אותנו עוד עיקרון חשוב באבטחה – חוזק האבטחה הוא כחוזק החוליה החלשה ובהחלט לא כחוזק החוליה החזקה במערכת. תוקפים אינטלגנטים תמיד ינסו לנצל את הנסיבות והאפשריות הקיימות – כנגדכם.
עוד חומה מפורסמת ש"פספסה" את העיקרון היא החומה הסינית (המרשימה!!) שמשתרעת למערב סין ואכן עצרה התקפות ממערב, אך לא עצרה את פלישת המונגולים לסין – מהצפון. (בוודאי אתם מכירים עוד דוגמאות היסטוריות דומות…).
בעולם התוכנה, Defense In Depth נראה יותר כמו התרשים הבא: ריבוי כלים ותהליכים, עם מידה מסוימת יש יתירות ביניהם (redundancy) – כך שכישלון של כל רכיב במערכת, לא יותיר את המערכת חשופה:
Layered Security (נקרא גם "Castle Approach")

האם אתם יודעים כיצד נראו טירות בימי-הביניים?
אם אתם חובבי היסטוריה ולחימה – בוודאי שאתם יודעים!

בדרך כלל היו לטירות 2 או 3 חומות, בהם שערים.
כל חומה, סיפקה רמה אחרת של אבטחה – שהתאימה לה.

למשל:

  • בתחומי החומה החיצונית היו השווקים והשטחים המשותפים לאזרחים. השומר בשער שביצע ביקורת בסיסית למדי על הנכנסים (למשל: אסור להיכנס עם נשק בולט, כמו גרזן ענק)
  • בתחומי החומה האמצעים, היו משרדי שלטון או התגוררו אצילים. השומר בשער ביצע סינון קפדני יותר. למשל: כניסה מותרת רק לאזרחים ישרים. איך מזהים יושר? ע"פ בגדים חגיגיים ונקיים, כמובן!
  • החומה הפנימית ביותר הגנה על הנכס החשוב ביותר של הממלכה: המלך! כניסה בשער זה התאפשר רק בתיאום מראש והיכרות אישית עם הנכנסים.
ניתן היה לבנות את העיר כשלושה רבעים בלתי-תלויים, כשלכל רובע יש שער עם כללי כניסה משלו.

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

דוגמה מהעולם האמיתי

באופן דומה למדי, אנו מתכננים את ה Data Center המודרני. (הערה: אני מתייחס ל Data Center בענן, בו לא צריך לערבב את הנושא של תחנות-קצה של העובדים כמו ב On-Premises):

האינטרנט

מחוץ ל Data Center שורר האינטרנט – מלא באיומים ופורעי חוק.

כדרך קבע bots עוינים (יש גם bots ידידותיים. למשל: מנוע חיפוש, או כל אלו שעשיו מפתחים לפייסבוק) שפועלים באינטרנט ומנסים לגשת ל Data Center שלנו:
  • הם סורקים את ה ports שפתוחים לאינטרנט, ומנסים לזהות פגיעויות ידועות (באגים, קונפיגורציה לא מספיקה, וכו').
  • מנסים להפיץ תולעים, סוסים טרויאנים, או Malware (נוזקות) מסוגים שונים ומשונים.
  • אוספים מידע על המערכת שלנו ואופי השימוש בה. מידע שיוכל לשמש כיתרון עבור התוקף האינטליגנטי.
מכאן אנו משתמשים (לצורך הדוגמה – בפועל זה משתנה ממערכת למערכת) ב3 שכבות של רשת: DMZ, רשת אמצעית, ורשת פנימית. בכניסה לכל רשת יש "שער" זהו רכיב הגנה בסיסי בשם Firewall.ה Firewall בוחן את כל ההודעות ברמת ה (Internet Protocol (IP (+ התייחסות ל port של tcp) ומסנן תעבורה שמזוהה כעוינת ע"פ חוקים שהוגדרו לו. למשל:

  • חסימת הודעות משובשות / שלא עומדות בתקן הפרוטוקול (ניסיונות לאתגר את אמינות המערכת שלנו).
  • חסימת הודעות שמקורן ב ip address של תוקף / לא בטוח. או שאנו מגדירים את הכתובות הללו בעצמנו על פי ניסיון עבר, או שאנו מנויים לשירות חיצוני שעוקב ומעדכן אותנו על כתובות כאלו.
  • חסימת תעבורה שמיישמת התקפות נפוצות: למשל – לשלוח הודעה שבה כתובת השלוח היא הכתובת שלנו, כך שננסה לענות לעצמנו (וכך נעמיס את עצמו סתם).
ה DMZ (קיצור של demilitarized zone = "איזור מפורז")
ה DMZ הוא שכבת הגנה ראשונה שמסננת את ה Traffic מהאינטרנט. ב Data Center בענן, יהיו ב DMZ מעט מאוד שרתים – שתפקידם הוא בעיקר בקרה והגנה (ומכאן השם).
ה DMZ נוגע ב 2 Firewalls:
  • אחד שמחבר את ה DMZ לאינטרנט – וכולל חוקי הגנה גנריים ובסיסיים (כפי שציינתי למעלה)
  • אחד שמחבר את ה DMZ לרשת הפנימית יותר, ומאפשר רק תעבורה מתוך השרתים שלנו – כאלו שסיננו את התעבורה בצורה מקיפה יותר ואישרו אותה.
על אילו שרתים מדובר:
Reverse Proxy – שרת שמעביר תקשורת פנימה ובחזרה (התשובות של השרתים שלנו), אך מסתיר את הכתובות האמיתיות של השרתים הפנימיים (Network Address Translation). מדוע להסתיר את מבנה הרשת הפנימית שלנו? כדי להקשות על תוקף לנהל התקפה. למשל: תוקף החדיר Malware לשרת הפנימית אך הוא לא יודע מה לפקוד עליו כי הוא לא מכיר את השמות האמיתיים של השרתים.
זה התפקיד הראשון של ה Reverse Proxy אבל התפקיד החשוב שלו הוא להיות איתן.
איתן? כן. שרתי האינטרנט שלנו (nginx ,tomcat, וכו') הם מורכבים, ולא תמיד מתוחזקים ו/או מקונפגים בחשיבה על Security. לא תמיד מעודכנים בעדכוני האבטחה האחרונים. התוצאה – יש בהם הרבה פגיעויות, שחלק מהן אולי מוכרות לתוקפים.
ה Reverse Proxy הוא שרת פשוט למדי שמתוחזק בחשיבה על Security ומעצם כך כמות הפגיעויות שלו נמוכה משמעותית. יש לעדכן אותו ואת מערכת ההפעלה עליו הוא רץ בצורה תדירה.
אנו מעדיפים שה Traffic העוין מהאינטרנט קודם כל ייתקל בשרת מעודכן שכזה – ועליו וינסה עליו את "הטריקים שלו" ( – ולא יצליח) מאשר שייתקל בתוכנה שלנו שאותה יותר קשה להחזיק עמידה ומעודכנת.
Web Application Firewall (בקיצור WAF) – היא הגרסה המודרנית יותר של Reverse Proxy, שכוללת גם את סט היכולות הקלאסי של Reverse Proxy. בדומה ל Firewall, ש"מבין" תעבורה של פרוטוקול IP (פרוטוקול האינטרנט) ויודע לסנן ע"פ חוקים תעבורה בעייתית, ה WAF "מבין" HTTP ויודע לסנן תעבורה בעייתית: תעבורה שמנסה להגיע ל URLs לא תקינים, שמנסה לסרוק רנדומלית URLs עם HTTP Method חשוד (למשל: קריאה ל DELETE על כל ה URLs הידועים של המערכת).
התעבורה הנ"ל יכולה להיות תקינה לחלוטין מבחינת ה Firewall (פרוטוקול IP), אך דיי ברור שהיא עוינת ברגע שמתבוננים בה ברמת ה HTTP. על מנת "לסנן" HTTP יש "להרכיב" את ה packets של IP לכדי הודעת HTTP request, מה שנעדיף לעשות על תוכן שכבר עבר סינון ראשוני של Firewall.
הערה: עבור מערכות שאינן בענן (on-premises) תפקיד ה DMZ הוא מעט שונה (למשל: מכיל שרתי אינטרנט ציבוריים), לא אכנס להבדלים אלו ברמת הפוסט.
רשת אמצעית

ברשת הפנימית הראשונית – אנו מציבים את שרתי הווב שלנו. אלו שמתקשרים עם המשתמשים (דרך ווב או דרך APIs). התעבורה שמגיעה עליהם עברה כבר סינון של ה Firewall החיצוני וה Reverse Proxy (או WAF), וה Firewall שבכניסה לרשת מאפשר רק לתעבורה כזו להיכנס (ע"י חסימת כל כתובות ה IP מלבד אלו של ה Reverse Proxy / WAF).ברשת הפנימית נמצא באופן טיפוסי את הרכיבים הבאים:

Proxy – פרוקסי הוא שרת אינטרנט שמאפשר גישה החוצה אל האינטרנט. עצם הצורך בגישה הוא עסקי ולא דווקא נוגע לאבטחה. בנוסף, ה Proxy לרוב מבצע Caching לתוכן HTTP שניגשים אליו הרבה – וכך משפר את הביצועים של הרשת.
היבט האבטחה של ה Proxy הוא שניתן להגדיר עליו כללים: להיכן אסור לצאת / לשלוח הודעות. ההגדרות יכולות להיות הן ברמת ה IP (כתובת IP) או ברמת ה HTTP (כלומר: URL Pattern).
כאשר יש תוקף שהצליח לגשת לרשת הפנימית שלנו, הוא יצטרך הרבה פעמים לגשת חזרה לאינטרנט. או על מנת לקבל הוראות נוספות לגבי התקיפה, או בכדי לשלוח את המידע שנגנב – חזרה לתוקף. אם נצליח לחסום כתובות IP בעייתיות – אזי נוכל להקשות על התוקפים ולעתים אף לסכל את ההתקפות שלהם.
ה Proxy הקלאסי הוא רכיב דיי בסיסי עם רשימת Deny סטטאטית שיש לנהל בצורה ידנית.
Identity Detection / Prevention System (בקיצור IDS/IPS)
רכיבים אלו מאזינים לתעבורת הרשת לרשת הפנימית (זו שעברה סינון ראשוני ע"פ חוקי Firewall / WAF) ולזהות דפוסים חריגים או כאלו שנראים כמו התקפה פוטנציאלית. ההבדל המהותי בין IDS ל IPS הוא ש IDS, ברגע שזיהה משהו שנראה לו כמו התקפה יעלה Alert – לאנשי ה DevOps / Security. ה IPS יכול לקחת גם החלטה לחסום את תעבורת הרשת ולעצור את ההתקפה (במידה של זיהוי שגוי – הוא יעצור תעבורה לגיטימית).
החלוקה ל IDS/IPS היא דיי מלאכותית וסביר יותר למצוא כלי שיכול לעשות גם וגם, כאשר בד"כ הוא מעלה התראות, במקרים מסוימים "בודק את המשתמש" (מאט את התשובות אליו או מציג בפניו מבחן Captcha), ורק במקרים קיצוניים – חוסם.
יש חפיפה מסוימת בין WAF או Firewall חכמים ובין IDS/IPS, אבל כפי שציינו קודם לכן בפוסט – יש ייתרון ביתירות הזו בדמות Defense In Depth. כלי אחד שכשל – לא יגרום למערכת שלנו להיות חשופה.

Physical Security – זה גם חלק מהעניין. מקור: onthetech.com
רשת פנימית
ברשת הפנימית אנו מציבים את בסיסי הנתונים שלנו. בסיסי הנתונים הם שרתים שמחזיקים Assets רגישים ביותר (המידע שלנו!) ואנו יודעים לנטר בצורה דיי ברורה איזה תעבורה אמורה להגיע אליהם. במקרה שלנו: רק תעבורה מתוך שרתי הווב/אפליקציה שאישרנו. כל שרת אינטרנט – רשאי לגשת ל DB מסוים מאוד.
אם כן, Firewall פשוט יכול לספק הגבלה הדוקה על הכללים הללו ולאפשר רק את התעבורה הרצויה. בד"כ לא נמצא מוצרי הגנה נוספים ברמת הרשת בתוך הרשת הפנימית – כי התעבורה כבר מסוננת היטב.
סביר יותר שכאן נמצא כלי monitoring (למשל, אבל לא רק HIDS או Agents שונים) שמותקנים על שרתי ה DB עצמם ומנטרים את ההתנהגות על המערכת.

מה הצעד הבא?

מודל ה CIA והעקרונות הנוספים שהצגתי הם הבסיס: הם חשובים מאוד, אבל אין דיי בהם בכדי להכווין אותנו כיצד להגן על מערכת מורכבת.
חשבו על הארגון / המוצר שלכם – האם ברור לכם כבר אילו צעדים מעשיים חשוב לקחת בכדי להגן עליו בצורה טובה מספיק? באיזה עדיפות ובאיזה סדר?
– אני מניח שלא. וגם אם כן – אתם כנראה רואים תמונה חלקית מאוד של המצב.
לשם כך נוצרו מודלים ("Frameworks") שעוזרים למי שמשתמש בהם לתכנן מקצה לקצה – כיצד להקים ולתחזק מערך הגנה.
למשל, מודל ה NIST Cybersecurity Framework מגדיר את היסודות (cores) הבאים:

לכל יסוד, יש קטגוריה של כללים ו guidelines – איך להשיג אותה, אשר מורכבת מהירככיה של מדריכים שהולכים ונהיים מפורטים כיצד לכסות את התחום.
למשל: אתם רוצים לאבטח את גישת ה SSH לשרתי הפרודקשיין שלכם? אפשר לחפש בקטלוג המדריכים של NIST ולמצוא את NIST.IR.7966 – מדריך בן 50 עמודים שממצה את הנושא עד תום!
המדריך מתאר את עיקרי הטכנולוגיה מאחורי פרוטוקול / כלי SSH, את החולשות, ואת תחומי ההגנה ("Control Areas") המומלצים על מנת למתן / לבטל את החולשות הללו. למשל:
  • ניהול חשבונות
  • אכיפת גישה
  • צמצום גישה (Least Privilege principle)
  • Audit וניטור
  • ניהול סיכונים (בהיבט ה SSH)
  • זיהוי ואימות משתמשים.

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

הרעיון של רוב ה Frameworks הוא לא להציע רשימה שטוחה של אמצי-אבטחה (Controls) – בנוסח "חייבים את הכל!".
הגישה הבוגרת היא לאזן בין צרכים עסקיים לאבטחה – ע"פ ניהול סיכונים שמותאם לארגון / מוצר ולצרכים הייחודיים שלו. ע"פ הגישה הזו: ניתן (ולעתים אף חשוב) לקחת סיכונים – כל עוד מנהלים אותם.
מקור: https://rofori.wordpress.com
חוץ מ NIST CSF (קיצור של Cyber Security Framework) – אלו עוד Framework פופולריים קיימים?

לרוב מחלקים אותם ל-3 קטגוריות:
  • Frameworks רגלוטוריים – אותם המדינה מחייבת על ארגונים מסויימים.
    • למשל: HIPAA לארגונים המחזיקים מידע רפואי, SOX – לחברות בורסאיות בארה"ב, NERC CIP – לחברות החשמל בצפון אמריקה, וכו'
  • Frameworks רגלוטוריים למחצה – אשר ארגון מקבל על עצמו כחלק מחוזה / הסדר מסחרי.
    • הדוגמה הכי נפוצה: PCI-DSS של חברות האשראי. אם אתם מנהלים מידע על כרטיסי אשראי ואתם לא עומדים ברמת ההגנה של ה Framework / או בסטנדרטים שלו (למשל: לא יותר מ 1% מהעסקאות שאתם סולקים הם לא-לגיטימיות) – חברות האשראי עלולות להפסיק לעבוד אתכם. עבור ארגונים רבים – זהו עניין קיומי.
    • יש Frameworks קצת פחות ידועים בעולם עריכת הדין, חשבנאות, וכו'.
  • Voluntary Frameworks – שהארגון בוחר לאמץ ביוזמתו בגלל צרכים כאלו או אחרים.
    • ISO/IEC 27001 – הוא ה Framework הנפוץ בתחום, ובד"כ אימוץ שלו כולל הסמכה ע"י גוף שהוסמך לכך (חברות ייעוץ שונות).
      • הוא נחשב בסיסי, נדרש לעתים על מנת להיות ספק של ארגונים גדולים. דיי "מרובע" בתפיסות שלו, בעיקר מסביב לתהליכים.
      • יש לו 2 גרסאות תקפות: 2005 – גרסה מאוד ממוקדת תהליכים ("Plan-Do-Check-Act") והתיעוד שלהם (למי שמכיר ISO 9000), וגרסאת 2013 – שנחשבת יותר גמישה ומעשית.
    • NIST SP800-53 (נקרא גם NIST 800 series) – הוא תקן אבטחה לו נדרשים גופים ממשלתיים בארה"ב (ועוד כמה מדינות שאמצו אותו כתקן) – אבל גם זמין לכל דורש.
    • (ISC)2 Common Body of Knowledge (CBK) – זה בעצם ה Framework ה"פנימי" של הסמכות ה CISSP – ההסמכה ה"נחשבת" בעולם אבטחת המידע.
    • (DHS Cyber Resilience Review (CRR – עוד Framework אמריקאי (יש רבים כאלו), הפעם של הארגון לבטחון המולדת (DHS).
    • CIS Critical Security Controls (כרגע בגרסה 6.0) – תקן "פתוח", שנוצר ע"י קבוצה של מומחי-אבטחה בלתי תלויים, וללא מטרות רווח, ש"מחוייבים לחופשיות האינטרנט".
      • לעתים מזוהה עם חברת SANS – שמסייעת להפיץ אותו.
    • OWASP TOP 10 – זהו לא Framework, אלא ניתוח תלת-שנתי של 10 ההתקפות הנפוצות ביותר על שרתי ווב, מידע פרטי, מובייל, וכו' (יש מספר גרסאות של הדו"ח). אם אתם רוצים להתחיל עם הבסיס של הבסיס – זה המקום.
    • וכו' וכו'
אם אתם רוצים להקים מערך הגנה שלם (לא מושלם. שלם) ומאוזן – כדאי להשתמש ב Framework כנקודת התייחסות.
"אני מבין באבטחת מידע, ועובד לפי השיטה שלי" – היא לרוב לא גישה שמגיעים איתה רחוק, אלא אם מדובר במומחה אמיתי, שכבר ה Frameworks הללו מאחוריו. אם יש לכם ספק – שאלו את "המומחה" לאילו Frameworks הגישה שלו דומה, ומה ההבדלים. מעניין.

אם אתם פשוט כותבים תוכנה ומנסים לאבטח אותה, ולא לאבטח ארגון שלם – כנראה ש OWASP זה השלב הראשון, ו ISC^2 / CIS / NIST – הם המקומות להמשיך וללמוד מהם /לקבל מהם מושג וכיוון.

סיכום

המידע הזה עשה לי הרבה סדר בראש כשנתקלתי בו.
במשך שנים הכרתי כל מיני סוגי התקפות (DDOS, ARP Poisoning, או CSRF) – אך לא היה לי כל סדר מה יותר חשוב ממה, ובאיזה אופן כדאי להתגונן.

אני מקווה שהפוסט הזה עשה מעט סדר. עולם אבטחת המידע ("סייבר") הוא גדול ומורכב. יש תחומי מומחיות של Penetration Testing, איתור וניתוח Malware, מודיעין, Reverse Engineering, ועוד.

אני? אני ניסיתי רק לתת את הבסיס.

שיהיה בהצלחה!

—–

[א] לא קיימת מערכת מוגנת ב 100%, וגם אם תיאורטית היה ניתן ליצור אותה – היא לא הייתה משתלמת עסקית. מחירי האבטחה עולים בצורה מעריכית – ככל שאנו הולכים ומתקרבים ל"אבטחה מושלמת".