פיתוח מאובטח & פריסה באמצעות Cloud Build, Artifact Registry ו-GKE

1. מבוא

‏Container Analysis מספק בדיקות לאיתור נקודות חולשה ואחסון מטא-נתונים של קונטיינרים. שירות הסריקה מבצע בדיקות לאיתור נקודות חולשה בתמונות ב-Artifact Registry וב-Container Registry, ולאחר מכן מאחסן את המטא-נתונים שנוצרים ומאפשר שימוש בהם דרך ממשק API. אחסון מטא-נתונים מאפשר לכם לאחסן מידע ממקורות שונים, כולל סריקת נקודות חולשה, שירותי Google Cloud וספקי צד שלישי.

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

  • כשהסריקה האוטומטית מופעלת, הסריקה מופעלת באופן אוטומטי בכל פעם שדוחפים תמונה חדשה ל-Artifact Registry או ל-Container Registry. המידע על נקודות החולשה מתעדכן כל הזמן כשמתגלות נקודות חולשה חדשות.
  • כשהאפשרות On-Demand Scanning מופעלת, צריך להריץ פקודה כדי לסרוק קובץ אימג' מקומי או קובץ אימג' ב-Artifact Registry או ב-Container Registry. סריקת קונטיינרים על פי דרישה מאפשרת לכם לקבוע מתי תסרקו את הקונטיינרים. לדוגמה, אפשר לסרוק קובץ אימג' שנוצר באופן מקומי ולתקן נקודות חולשה לפני שמאחסנים אותו במרשם. תוצאות הסריקה זמינות למשך עד 48 שעות לאחר השלמת הסריקה, ומידע על נקודות חולשה לא מתעדכן אחרי הסריקה.

כשמשתמשים ב-Container Analysis שמשולב בצינור עיבוד הנתונים של CI/CD, אפשר לקבל החלטות על סמך המטא-נתונים האלה. לדוגמה, אפשר להשתמש ב-Binary Authorization כדי ליצור מדיניות פריסה שמאפשרת פריסה רק של תמונות תואמות מרשומות מהימנות.

מה תלמדו

  • איך מפעילים סריקה אוטומטית
  • איך מבצעים סריקה על פי דרישה
  • איך לשלב סריקה בצינור עיבוד נתונים ל-build
  • איך חותמים על תמונות שאושרו
  • איך משתמשים בפקדי אישור של GKE כדי לחסום תמונות
  • איך מגדירים את GKE כך שיאפשר רק תמונות חתומות שאושרו

2. הגדרה ודרישות

הגדרת סביבה בקצב אישי

  1. נכנסים למסוף Google Cloud ויוצרים פרויקט חדש או משתמשים מחדש בפרויקט קיים. אם עדיין אין לכם חשבון Gmail או חשבון Google Workspace, עליכם ליצור חשבון.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • שם הפרויקט הוא השם המוצג של המשתתפים בפרויקט. זוהי מחרוזת תווים שלא משמשת את Google APIs. אפשר לעדכן את המיקום הזה בכל שלב.
  • מזהה הפרויקט הוא ייחודי לכל הפרויקטים ב-Google Cloud ואי אפשר לשנות אותו אחרי שמגדירים אותו. מסוף Cloud יוצר באופן אוטומטי מחרוזת ייחודית. בדרך כלל לא משנה מה המחרוזת הזו. ברוב ה-codelabs תצטרכו להפנות למזהה הפרויקט (בדרך כלל הוא מזוהה בתור PROJECT_ID). אם המזהה שנוצר לא מוצא חן בעיניכם, תוכלו ליצור מזהה אקראי אחר. לחלופין, אפשר לנסות שם משלכם ולבדוק אם הוא זמין. לא ניתן לשנות את השם אחרי השלב הזה, והוא יישאר למשך כל תקופת הפרויקט.
  • לידיעתכם, יש ערך שלישי, מספר פרויקט, שמשתמשים בו בחלק מממשקי ה-API. מידע נוסף על כל שלושת הערכים האלה זמין במסמכי העזרה.
  1. בשלב הבא, כדי להשתמש במשאבים או ב-API של Cloud, תצטרכו להפעיל את החיוב במסוף Cloud. השלמת הקודלאב הזה לא אמורה לעלות הרבה, אם בכלל. כדי להשבית את המשאבים ולמנוע חיובים אחרי סיום המדריך, אפשר למחוק את המשאבים שיצרתם או למחוק את הפרויקט כולו. משתמשים חדשים ב-Google Cloud זכאים להשתתף בתוכנית תקופת ניסיון בחינם בסך 300$.

הפעלת Cloud Shell Editor

סדנת ה-Lab הזו תוכננה ונבדקה לשימוש עם Google Cloud Shell Editor. כדי לגשת לעורך:

  1. נכנסים לפרויקט ב-Google בכתובת https://console.cloud.google.com.
  2. בפינה השמאלית העליונה, לוחצים על סמל עורך Cloud Shell.

8560cc8d45e8c112.png

  1. ייפתח חלון חדש בחלק התחתון של החלון.

הגדרת הסביבה

ב-Cloud Shell, מגדירים את מזהה הפרויקט ואת מספר הפרויקט. שומרים אותם כמשתנים PROJECT_ID ו-PROJECT_ID.

export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID \
    --format='value(projectNumber)')

הפעלת שירותים

מפעילים את כל השירותים הנדרשים:

gcloud services enable \
  cloudkms.googleapis.com \
  cloudbuild.googleapis.com \
  container.googleapis.com \
  containerregistry.googleapis.com \
  artifactregistry.googleapis.com \
  containerscanning.googleapis.com \
  ondemandscanning.googleapis.com \
  binaryauthorization.googleapis.com 

יצירת מאגר ב-Artifact Registry

בשיעור ה-Lab הזה נשתמש ב-Artifact Registry כדי לאחסן ולסרוק את התמונות. יוצרים את המאגר באמצעות הפקודה הבאה.

gcloud artifacts repositories create artifact-scanning-repo \
  --repository-format=docker \
  --location=us-central1 \
  --description="Docker repository"

מגדירים את Docker כך שישתמש בפרטי הכניסה שלכם ב-gcloud כשתיגשו ל-Artifact Registry.

gcloud auth configure-docker us-central1-docker.pkg.dev

3. סריקה אוטומטית

הסריקה של הארטיפקטים מופעלת באופן אוטומטי בכל פעם שדוחפים קובץ אימג' חדש ל-Artifact Registry או ל-Container Registry. המידע על נקודות החולשה מתעדכן כל הזמן כשמתגלות נקודות חולשה חדשות. בקטע הזה נדחוף קובץ אימג' ל-Artifact Registry ונבחן את התוצאות.

יצירה של ספריית עבודה ושינוי אליה

mkdir vuln-scan && cd vuln-scan

הגדרת תמונה לדוגמה

יוצרים קובץ בשם Dockerfile עם התוכן הבא.

cat > ./Dockerfile << EOF
FROM gcr.io/google-appengine/debian9@sha256:ebffcf0df9aa33f342c4e1d4c8428b784fc571cdf6fbab0b31330347ca8af97a

# System
RUN apt update && apt install python3-pip -y

# App
WORKDIR /app
COPY . ./

RUN pip3 install Flask==1.1.4
RUN pip3 install gunicorn==20.1.0

CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app

EOF

יוצרים קובץ בשם main.py עם התוכן הבא:

cat > ./main.py << EOF
import os
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    name = os.environ.get("NAME", "Worlds")
    return "Hello {}!".format(name)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
EOF

יצירה של קובץ build והעברה (push) של קובץ האימג' ל-AR

איך משתמשים ב-Cloud Build כדי ליצור קונטיינר ולהעביר אותו באופן אוטומטי ל-Artifact Registry. שימו לב לתג bad בתמונה. כך תוכלו לזהות אותו בשלבים הבאים.

gcloud builds submit . -t us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:bad

בדיקת פרטי התמונה

בסיום תהליך ה-build, בודקים את התוצאות של האימג' ושל נקודות החולשה במרכז הבקרה של Artifact Registry.

  1. פתיחת Artifact Registry במסוף Cloud
  2. לוחצים על artifact-scanning-repo כדי להציג את התוכן.
  3. לוחצים על פרטי התמונה.
  4. לוחצים על סיכום התמונה האחרון
  5. בסיום הסריקה, לוחצים על הכרטיסייה 'נקודות חולשה' של התמונה.

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

361be7b3bf293fca.png

הסריקה האוטומטית מופעלת כברירת מחדל. כדאי לעיין בהגדרות של Artifact Registry כדי לראות איך אפשר להשבית או להפעיל את הסריקה האוטומטית.

4. סריקה על פי דרישה

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

יצירת קובץ אימג'

בשלב הזה תשתמשו ב-Docker המקומי כדי ליצור את קובץ האימג' במטמון המקומי.

docker build -t us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image .

סריקת התמונה

אחרי יצירת התמונה, מבקשים סריקה של התמונה. תוצאות הסריקה מאוחסנות בשרת מטא-נתונים. המשימה תושלם עם מיקום התוצאות בשרת המטא-נתונים.

gcloud artifacts docker images scan \
    us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image \
    --format="value(response.scan)" > scan_id.txt

בדיקת קובץ הפלט

כדאי לעיין בתוצאה של השלב הקודם שנשמרה בקובץ scan_id.txt. שימו לב למיקום הדוח של תוצאות הסריקה בשרת המטא-נתונים.

cat scan_id.txt

בדיקת תוצאות הסריקה המפורטות

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

gcloud artifacts docker images list-vulnerabilities $(cat scan_id.txt) 

הפלט מכיל כמות משמעותית של נתונים על כל נקודות החולשה בתמונה.

סימון בעיות קריטיות

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

export SEVERITY=CRITICAL

gcloud artifacts docker images list-vulnerabilities $(cat scan_id.txt) --format="value(vulnerability.effectiveSeverity)" | if grep -Fxq ${SEVERITY}; then echo "Failed vulnerability check for ${SEVERITY} level"; else echo "No ${SEVERITY} Vulnerabilities found"; fi

הפלט מהפקודה הזו יהיה

Failed vulnerability check for CRITICAL level

5. סריקת צינור עיבוד נתונים ליצירת גרסאות build

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

מתן גישה לחשבון השירות של Cloud Build

ל-Cloud Build יידרשו הרשאות גישה לממשק ה-API לסריקה על פי דרישה. נותנים גישה באמצעות הפקודות הבאות.

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/iam.serviceAccountUser"
        
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/ondemandscanning.admin"

יצירת צינור עיבוד הנתונים של Cloud Build

הפקודה הבאה תיצור בתיקייה קובץ cloudbuild.yaml שישמש בתהליך האוטומטי. בדוגמה הזו, השלבים מוגבלים לתהליך ה-build בקונטיינר. בפועל, צריך לכלול הוראות ובדיקות ספציפיות לאפליקציה בנוסף לשלבים בקונטיינר.

יוצרים את הקובץ באמצעות הפקודה הבאה.

cat > ./cloudbuild.yaml << EOF
steps:

# build
- id: "build"
  name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', '.']
  waitFor: ['-']

#Run a vulnerability scan at _SECURITY level
- id: scan
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
    (gcloud artifacts docker images scan \
    us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image \
    --location us \
    --format="value(response.scan)") > /workspace/scan_id.txt

#Analyze the result of the scan
- id: severity check
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
      gcloud artifacts docker images list-vulnerabilities \$(cat /workspace/scan_id.txt) \
      --format="value(vulnerability.effectiveSeverity)" | if grep -Fxq CRITICAL; \
      then echo "Failed vulnerability check for CRITICAL level" && exit 1; else echo "No CRITICAL vulnerability found, congrats !" && exit 0; fi

#Retag
- id: "retag"
  name: 'gcr.io/cloud-builders/docker'
  args: ['tag',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']


#pushing to artifact registry
- id: "push"
  name: 'gcr.io/cloud-builders/docker'
  args: ['push',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']

images:
  - us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image
EOF

הפעלת צינור עיבוד הנתונים של CI

שולחים את ה-build לעיבוד כדי לוודא שה-build נכשל כשנמצאת נקודת חולשה ברמת קריטית.

gcloud builds submit

בדיקת כשל ב-build

ה-build ששלחתם עכשיו ייכשל כי התמונה מכילה נקודות חולשה קריטיות.

בודקים את הכישלון של ה-build בדף Cloud Build History

תיקון הפגיעות

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

משנים את קובץ Dockerfile כך שישתמש בקובץ האימג' של Debian 10 באמצעות הפקודה הבאה:

cat > ./Dockerfile << EOF
from python:3.8-slim  

# App
WORKDIR /app
COPY . ./

RUN pip3 install Flask==2.1.0
RUN pip3 install gunicorn==20.1.0

CMD exec gunicorn --bind :\$PORT --workers 1 --threads 8 main:app

EOF

מריצים את תהליך ה-CI עם התמונה הטובה

שולחים את ה-build לעיבוד כדי לוודא שה-build יצליח אם לא יימצאו נקודות חולשה ברמת קריטיות.

gcloud builds submit

בדיקת הצלחת ה-build

ה-build ששלחת עכשיו יצליח כי קובץ האימג' המעודכן לא מכיל נקודות חולשה קריטיות.

בודקים את הצלחת ה-build בדף Cloud Build History

בדיקת תוצאות הסריקה

בדיקת קובץ האימג' תקין ב-Artifact Registry

  1. פותחים את Artifact Registry במסוף Cloud
  2. לוחצים על artifact-scanning-repo כדי להציג את התוכן.
  3. לוחצים על פרטי התמונה.
  4. לוחצים על סיכום התמונה האחרון
  5. לוחצים על הכרטיסייה 'נקודות חולשה' של התמונה.

6. חתימה על תמונות

יצירת הערה של גורם אימות

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

יצירת הערה

cat > ./vulnz_note.json << EOM
{
  "attestation": {
    "hint": {
      "human_readable_name": "Container Vulnerabilities attestation authority"
    }
  }
}
EOM

שומרים את ההערה

NOTE_ID=vulnz_note

curl -vvv -X POST \
    -H "Content-Type: application/json"  \
    -H "Authorization: Bearer $(gcloud auth print-access-token)"  \
    --data-binary @./vulnz_note.json  \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/?noteId=${NOTE_ID}"

אימות ההערה

curl -vvv  \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/${NOTE_ID}"

יצירת גורם אימות (attestor)

חותמים משמשים לביצוע תהליך החתימה בפועל על התמונה, והם יצרפו את ההערה לתמונה לצורך אימות מאוחר יותר. יוצרים את המאמת לשימוש מאוחר יותר.

יצירת גורם אימות

ATTESTOR_ID=vulnz-attestor

gcloud container binauthz attestors create $ATTESTOR_ID \
    --attestation-authority-note=$NOTE_ID \
    --attestation-authority-note-project=${PROJECT_ID}

אימות המאמת

gcloud container binauthz attestors list

שימו לב שהשורה האחרונה מציינת NUM_PUBLIC_KEYS: 0 שתצטרכו לספק מפתחות בשלב מאוחר יותר

חשוב לזכור ש-Cloud Build יוצר באופן אוטומטי את המאמת built-by-cloud-build בפרויקט כשמריצים build שיוצר קובצי אימג'. לכן, הפקודה שלמעלה מחזירה שני מאמתים, vulnz-attestor ו-built-by-cloud-build. אחרי יצירת קובצי האימג', מערכת Cloud Build חותמת עליהם באופן אוטומטי ויוצרת להם אימותים.

הוספת תפקיד IAM

לחשבון השירות של Binary Authorization צריכות להיות הרשאות להצגת הערות האימות. נותנים את הגישה באמצעות קריאת ה-API הבאה

PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}"  --format="value(projectNumber)")

BINAUTHZ_SA_EMAIL="service-${PROJECT_NUMBER}@gcp-sa-binaryauthorization.iam.gserviceaccount.com"


cat > ./iam_request.json << EOM
{
  'resource': 'projects/${PROJECT_ID}/notes/${NOTE_ID}',
  'policy': {
    'bindings': [
      {
        'role': 'roles/containeranalysis.notes.occurrences.viewer',
        'members': [
          'serviceAccount:${BINAUTHZ_SA_EMAIL}'
        ]
      }
    ]
  }
}
EOM

שימוש בקובץ כדי ליצור את מדיניות ה-IAM

curl -X POST  \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    --data-binary @./iam_request.json \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/${NOTE_ID}:setIamPolicy"

הוספת מפתח KMS

לאמתן נדרשים מפתחות קריפטוגרפיים כדי לצרף את ההערה ולספק חתימות שניתן לאמת. בשלב הזה תיצורו מפתחות ותשמרו אותם ב-KMS כדי ש-Cloud Build יוכל לגשת אליהם מאוחר יותר.

קודם מוסיפים כמה משתני סביבה כדי לתאר את המפתח החדש

KEY_LOCATION=global
KEYRING=binauthz-keys
KEY_NAME=codelab-key
KEY_VERSION=1

יצירת אוסף מפתחות לאחסון קבוצת מפתחות

gcloud kms keyrings create "${KEYRING}" --location="${KEY_LOCATION}"

יצירת זוג מפתחות אסימטרי חדש לחתימה עבור המאמת

gcloud kms keys create "${KEY_NAME}" \
    --keyring="${KEYRING}" --location="${KEY_LOCATION}" \
    --purpose asymmetric-signing   \
    --default-algorithm="ec-sign-p256-sha256"

המפתח אמור להופיע בדף KMS במסוף Google Cloud.

עכשיו משייך את המפתח למאמת באמצעות הפקודה gcloud binauthz:

gcloud beta container binauthz attestors public-keys add  \
    --attestor="${ATTESTOR_ID}"  \
    --keyversion-project="${PROJECT_ID}"  \
    --keyversion-location="${KEY_LOCATION}" \
    --keyversion-keyring="${KEYRING}" \
    --keyversion-key="${KEY_NAME}" \
    --keyversion="${KEY_VERSION}"

אם תדפיסו שוב את רשימת הרשות, המפתח אמור להופיע כרשום:

gcloud container binauthz attestors list

יצירת אימות חתום

בשלב הזה, התכונות שמוגדרות מאפשרות לכם לחתום על תמונות. משתמשים באימות (attestor) שיצרתם קודם כדי לחתום על קובץ האימג' בקונטיינר שבו עבדתם

CONTAINER_PATH=us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image

DIGEST=$(gcloud container images describe ${CONTAINER_PATH}:latest \
    --format='get(image_summary.digest)')

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

gcloud beta container binauthz attestations sign-and-create  \
    --artifact-url="${CONTAINER_PATH}@${DIGEST}" \
    --attestor="${ATTESTOR_ID}" \
    --attestor-project="${PROJECT_ID}" \
    --keyversion-project="${PROJECT_ID}" \
    --keyversion-location="${KEY_LOCATION}" \
    --keyversion-keyring="${KEYRING}" \
    --keyversion-key="${KEY_NAME}" \
    --keyversion="${KEY_VERSION}"

במונחים של Container Analysis, הפעולה הזו תיצור אירוע חדש ותצרף אותו להערה של המאמת. כדי לוודא שהכול פועל כצפוי, אפשר להציג את האישורים

gcloud container binauthz attestations list \
   --attestor=$ATTESTOR_ID --attestor-project=${PROJECT_ID}

7. חתימה באמצעות Cloud Build

הפעלתם את 'חתימת תמונות' והשתמשתם באופן ידני באימות (attestation) כדי לחתום על התמונה לדוגמה. בפועל, כדאי להחיל את האימותים במהלך תהליכים אוטומטיים כמו צינורות עיבוד נתונים של CI/CD.

בקטע הזה מגדירים את Cloud Build לאימות אוטומטי של תמונות.

תפקידים

מוסיפים את התפקיד 'צפייה באימות של Binary Authorization' לחשבון השירות ב-Cloud Build:

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
  --role roles/binaryauthorization.attestorsViewer

מוסיפים את התפקיד Cloud KMS CryptoKey Signer/Verifier לחשבון השירות של Cloud Build (חתימה מבוססת-KMS):

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
  --role roles/cloudkms.signerVerifier

מוסיפים את התפקיד 'צירוף מופעי Container Analysis להערות' לחשבון השירות של Cloud Build:

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
  --role roles/containeranalysis.notes.attacher

הכנת שלב ה-build בהתאמה אישית ב-Cloud Build

כדי לפשט את תהליך האימות, נשתמש בשלב build מותאם אישית ב-Cloud Build. Google מספקת את השלב הזה של build בהתאמה אישית, שכולל פונקציות עזר כדי לייעל את התהליך. לפני השימוש, צריך ליצור את הקוד של שלב ה-build בהתאמה אישית בקונטיינר ולהעביר אותו ל-Cloud Build. כדי לעשות זאת, מריצים את הפקודות הבאות:

git clone https://github.com/GoogleCloudPlatform/cloud-builders-community.git
cd cloud-builders-community/binauthz-attestation
gcloud builds submit . --config cloudbuild.yaml
cd ../..
rm -rf cloud-builders-community

הוספת שלב חתימה לקובץ cloudbuild.yaml

בשלב הזה תוסיפו את שלב האימות לצינור עיבוד הנתונים של Cloud Build שיצרתם מקודם.

  1. בודקים את השלב החדש שרוצים להוסיף.

בדיקה בלבד. אסור להעתיק

#Sign the image only if the previous severity check passes
- id: 'create-attestation'
  name: 'gcr.io/${PROJECT_ID}/binauthz-attestation:latest'
  args:
    - '--artifact-url'
    - 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image'
    - '--attestor'
    - 'projects/${PROJECT_ID}/attestors/$ATTESTOR_ID'
    - '--keyversion'
    - 'projects/${PROJECT_ID}/locations/$KEY_LOCATION/keyRings/$KEYRING/cryptoKeys/$KEY_NAME/cryptoKeyVersions/$KEY_VERSION'
  1. מחליפים את הקובץ cloudbuild.yaml בצינור עיבוד הנתונים המלא המעודכן.
cat > ./cloudbuild.yaml << EOF
steps:

# build
- id: "build"
  name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', '.']
  waitFor: ['-']

#Run a vulnerability scan at _SECURITY level
- id: scan
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
    (gcloud artifacts docker images scan \
    us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image \
    --location us \
    --format="value(response.scan)") > /workspace/scan_id.txt

#Analyze the result of the scan
- id: severity check
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
      gcloud artifacts docker images list-vulnerabilities \$(cat /workspace/scan_id.txt) \
      --format="value(vulnerability.effectiveSeverity)" | if grep -Fxq CRITICAL; \
      then echo "Failed vulnerability check for CRITICAL level" && exit 1; else echo "No CRITICAL vulnerability found, congrats !" && exit 0; fi

#Retag
- id: "retag"
  name: 'gcr.io/cloud-builders/docker'
  args: ['tag',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image', 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']


#pushing to artifact registry
- id: "push"
  name: 'gcr.io/cloud-builders/docker'
  args: ['push',  'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good']


#Sign the image only if the previous severity check passes
- id: 'create-attestation'
  name: 'gcr.io/${PROJECT_ID}/binauthz-attestation:latest'
  args:
    - '--artifact-url'
    - 'us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good'
    - '--attestor'
    - 'projects/${PROJECT_ID}/attestors/$ATTESTOR_ID'
    - '--keyversion'
    - 'projects/${PROJECT_ID}/locations/$KEY_LOCATION/keyRings/$KEYRING/cryptoKeys/$KEY_NAME/cryptoKeyVersions/$KEY_VERSION'



images:
  - us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image:good
EOF

הרצת ה-build

gcloud builds submit

בדיקת ה-build בהיסטוריית Cloud Build

פותחים את מסוף Cloud בדף Cloud Build History ובודקים את הגרסה האחרונה שנוצרה וההפעלה המוצלחת של שלבי ה-build.

8. כללי מדיניות בקרה על אישור בקשות

Binary Authorization היא תכונה ב-GKE וב-Cloud Run שמאפשרת לאמת כללים לפני שמאפשרים להריץ קובץ אימג' של קונטיינר. האימות מתבצע בכל בקשה להרצת קובץ אימג', בין אם מדובר בצינור עיבוד נתונים מהימן של CI/CD או במשתמש שמנסה לפרוס קובץ אימג' באופן ידני. היכולת הזו מאפשרת לכם לאבטח את סביבות זמן הריצה בצורה יעילה יותר מאשר רק באמצעות בדיקות צינור עיבוד הנתונים של CI/CD.

כדי להבין את היכולת הזו, נשנה את מדיניות ברירת המחדל של GKE כדי לאכוף כלל הרשאה מחמיר.

יצירת אשכול GKE

יוצרים את האשכול ב-GKE:

gcloud beta container clusters create binauthz \
    --zone us-central1-a  \
    --binauthz-evaluation-mode=PROJECT_SINGLETON_POLICY_ENFORCE

מאפשרים ל-Cloud Build לפרוס באשכול הזה:

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
        --role="roles/container.developer"

מדיניות הרשאה לכל

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

  1. בדיקת המדיניות הקיימת
gcloud container binauthz policy export
  1. שימו לב שמדיניות האכיפה מוגדרת כ-ALWAYS_ALLOW

evaluationMode: ALWAYS_ALLOW

  1. פריסה של גרסת build לדוגמה כדי לוודא שאפשר לפרוס כל דבר
kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080
  1. אימות שהפריסה בוצעה
kubectl get pods

יוצג הפלט הבא

161db370d99ffb13.png

  1. מחיקת הפריסה
kubectl delete pod hello-server

מדיניות דחייה של כולם

עכשיו מעדכנים את המדיניות כך שלא תתאפשר הצגת תמונות.

  1. ייצוא המדיניות הנוכחית לקובץ שניתן לעריכה
gcloud container binauthz policy export  > policy.yaml
  1. שנה את המדיניות

בכלי לעריכת טקסט, משנים את הערך של evaluationMode מ-ALWAYS_ALLOW ל-ALWAYS_DENY.

edit policy.yaml

קובץ ה-YAML של המדיניות אמור להיראות כך:

globalPolicyEvaluationMode: ENABLE
defaultAdmissionRule:
  evaluationMode: ALWAYS_DENY
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
name: projects/PROJECT_ID/policy
  1. פותחים את Terminal ומחילים את המדיניות החדשה. ממתינים כמה שניות עד שהשינוי יופץ.
gcloud container binauthz policy import policy.yaml
  1. ניסיון בפריסת עומס עבודה לדוגמה
kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080
  1. הפריסה נכשלת עם ההודעה הבאה
Error from server (VIOLATES_POLICY): admission webhook "imagepolicywebhook.image-policy.k8s.io" denied the request: Image gcr.io/google-samples/hello-app:1.0 denied by Binary Authorization default admission rule. Denied by always_deny admission rule

החזרת המדיניות להרשאה לכולם

לפני שממשיכים לקטע הבא, חשוב לבטל את השינויים במדיניות

  1. שנה את המדיניות

בכלי לעריכת טקסט, משנים את הערך של evaluationMode מ-ALWAYS_DENY ל-ALWAYS_ALLOW.

edit policy.yaml

קובץ ה-YAML של המדיניות אמור להיראות כך:

globalPolicyEvaluationMode: ENABLE
defaultAdmissionRule:
  evaluationMode: ALWAYS_ALLOW
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
name: projects/PROJECT_ID/policy
  1. החלת המדיניות שהוחזרה למצב הקודם
gcloud container binauthz policy import policy.yaml

9. חסימה של נקודות חולשה ב-GKE

בקטע הזה משלבים את מה שלמדתם עד עכשיו, על ידי הטמעת צינור עיבוד נתונים של CI/CD עם Cloud Build, שמסורק את התמונות ולאחר מכן בודק נקודות חולשה לפני החתימה על התמונה והניסיון לפרוס אותה. GKE ישתמש ב-Binary Authorization כדי לאמת שלתמונה יש חתימה מסריקת נקודות החולשה, לפני שהוא יאפשר לה להריץ את האימג'.

d5c41bb89e22fd61.png

עדכון המדיניות של GKE כך שתחייב אימות

Require images חותמים על ידי האימות (attestor) על ידי הוספת clusterAdmissionRules למדיניות GKE BinAuth

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

COMPUTE_ZONE=us-central1-a

cat > binauth_policy.yaml << EOM
defaultAdmissionRule:
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
  evaluationMode: ALWAYS_DENY
globalPolicyEvaluationMode: ENABLE
clusterAdmissionRules:
  ${COMPUTE_ZONE}.binauthz:
    evaluationMode: REQUIRE_ATTESTATION
    enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
    requireAttestationsBy:
    - projects/${PROJECT_ID}/attestors/vulnz-attestor
EOM

החלת המדיניות

gcloud beta container binauthz policy import binauth_policy.yaml

ניסיון לפרוס את התמונה הלא חתומה

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

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

אחזור של תקציר התמונה של התמונה הפגומה

CONTAINER_PATH=us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image


DIGEST=$(gcloud container images describe ${CONTAINER_PATH}:bad \
    --format='get(image_summary.digest)')

שימוש ב-digest בתצורה של Kubernetes

cat > deploy.yaml << EOM
apiVersion: v1
kind: Service
metadata:
  name: deb-httpd
spec:
  selector:
    app: deb-httpd
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deb-httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deb-httpd
  template:
    metadata:
      labels:
        app: deb-httpd
    spec:
      containers:
      - name: deb-httpd
        image: ${CONTAINER_PATH}@${DIGEST}
        ports:
        - containerPort: 8080
        env:
          - name: PORT
            value: "8080"

EOM

ניסיון לפרוס את האפליקציה ב-GKE

kubectl apply -f deploy.yaml

בודקים את עומס העבודה במסוף ומציינים את השגיאה שבה מצוין שהפריסה נדחתה:

No attestations found that were valid and signed by a key trusted by the attestor

פריסה של קובץ אימג' חתום

אחזור של תקציר התמונה של התמונה הפגומה

CONTAINER_PATH=us-central1-docker.pkg.dev/${PROJECT_ID}/artifact-scanning-repo/sample-image


DIGEST=$(gcloud container images describe ${CONTAINER_PATH}:good \
    --format='get(image_summary.digest)')

שימוש ב-digest בתצורה של Kubernetes

cat > deploy.yaml << EOM
apiVersion: v1
kind: Service
metadata:
  name: deb-httpd
spec:
  selector:
    app: deb-httpd
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deb-httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deb-httpd
  template:
    metadata:
      labels:
        app: deb-httpd
    spec:
      containers:
      - name: deb-httpd
        image: ${CONTAINER_PATH}@${DIGEST}
        ports:
        - containerPort: 8080
        env:
          - name: PORT
            value: "8080"

EOM

פריסת האפליקציה ב-GKE

kubectl apply -f deploy.yaml

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

10. מעולה!

כל הכבוד, סיימת את הקודלאב!

הנושאים שעסקנו בהם:

  • איך מפעילים סריקה אוטומטית
  • איך מבצעים סריקה על פי דרישה
  • איך לשלב סריקה בצינור עיבוד נתונים ל-build
  • איך חותמים על תמונות שאושרו
  • איך משתמשים בפקדי אישור של GKE כדי לחסום תמונות
  • איך מגדירים את GKE כך שיאפשר רק תמונות חתומות שאושרו

השלב הבא:

הסרת המשאבים

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

מחיקת הפרויקט

הדרך הקלה ביותר לבטל את החיוב היא למחוק את הפרויקט שיצרתם בשביל המדריך.