יצירה ואימות של אישור המקור של Build

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

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

‫Cloud Build תומך ביצירת אישור המקור של Build שעומדים בדרישות של רמת אבטחה 3 של רמות של שרשרת אספקה לארטיפקטים של תוכנה (SLSA) על סמך המפרטים של SLSA בגרסה 0.1 ובגרסה 1.0.

במסגרת התמיכה במפרט SLSA v1.0, ‏ Cloud Build מספק פרטים על buildType באישור המקור של Build. אתם יכולים להשתמש בסכימה buildType כדי להבין את התבנית עם הפרמטרים שמשמשת לתהליך הבנייה, כולל הערכים שמתועדים ב-Cloud Build והמקור של הערכים האלה. מידע נוסף זמין במאמר בנושא Cloud Build buildType v1.

מגבלות

לפני שמתחילים

  1. מפעילים את ממשקי ה-API של Cloud Build,‏ Container Analysis ו-Artifact Registry.

    תפקידים שנדרשים להפעלת ממשקי API

    כדי להפעיל ממשקי API, נדרשת ההרשאה serviceusage.services.enable. אם יצרתם את הפרויקט, סביר להניח שכבר יש לכם את ההרשאה הזו דרך התפקיד 'בעלים' (roles/owner). אחרת, תוכלו לקבל את ההרשאה הזו דרך התפקיד 'אדמין בממשק 'שימוש בשירות'' (roles/serviceusage.serviceUsageAdmin). איך מקצים תפקידים

    הפעלת ממשקי ה-API

  2. כדי להשתמש בדוגמאות של שורת הפקודה במדריך הזה, צריך להתקין ולהגדיר את Google Cloud SDK.

  3. ודאו שיש לכם את קוד המקור.

  4. יש לכם מאגר ב-Artifact Registry.

יצירת אישור המקור של Build

בהוראות הבאות מוסבר איך ליצור אישור המקור של Build עבור קובצי אימג' של קונטיינר שמאוחסנים ב-Artifact Registry:

  1. בקובץ תצורת ה-build, מוסיפים את השדה images כדי להגדיר את Cloud Build לאחסון קובצי האימג' שנוצרו ב-Artifact Registry אחרי שה-build מסתיים.

    ‫Cloud Build לא יכול ליצור נתוני מקור אם אתם מעבירים בדחיפה את קובץ האימג' ל-Artifact Registry באמצעות שלב docker push מפורש.

    בקטע הקוד הבא מוצגת הגדרת build ליצירת קובץ אימג' של קונטיינר ולאחסון שלו במאגר Docker ב-Artifact Registry:

    YAML

      steps:
      - name: 'gcr.io/cloud-builders/docker'
        args: [ 'build', '-t', 'LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE', '.' ]
      images: ['LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE']
    

    כאשר:

    • LOCATION: המיקום האזורי או הרב-אזורי של המאגר.
    • PROJECT_ID: מזהה הפרויקט ב- Google Cloud .
    • REPOSITORY: השם של מאגר Artifact Registry.
    • IMAGE: השם של קובץ האימג' בקונטיינר.

    JSON

      {
      "steps": [
          {
              "name": "gcr.io/cloud-builders/docker",
              "args": [
                  "build",
                  "-t",
                  "LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE",
                  "."
              ]
          }
      ],
      "images": [
          "LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE"
      ]
      }
    

    כאשר:

    • LOCATION: המיקום האזורי או הרב-אזורי של המאגר.
    • PROJECT_ID: מזהה הפרויקט ב- Google Cloud .
    • REPOSITORY: השם של מאגר Artifact Registry.
    • IMAGE: השם של קובץ האימג' בקונטיינר.
  2. בקטע options של קובץ ההגדרה של ה-build, מוסיפים את האפשרות requestedVerifyOption ומגדירים את הערך VERIFIED.

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

    YAML

    options:
      requestedVerifyOption: VERIFIED
    

    JSON

    {
        "options": {
            "requestedVerifyOption": "VERIFIED"
        }
    }
    
  3. מתחילים את הבנייה.

הצגת אישור המקור של Build

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

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

console

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

כדי לראות את החלונית Security insights:

  1. פותחים את הדף Build History במסוף Google Cloud :

    פתיחת הדף Build History

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

  3. בעמודה תובנות בנושא אבטחה, לוחצים על הצגה.

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

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

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

‫CLI של gcloud

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

  gcloud artifacts docker images describe \
  LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE@sha256:HASH \
  --show-provenance --format=FORMAT

מחליפים את מה שכתוב בשדות הבאים:

  • LOCATION: המיקום האזורי או הרב-אזורי של המאגר.
  • PROJECT_ID: מזהה הפרויקט ב- Google Cloud .
  • REPOSITORY: השם של מאגר Artifact Registry.
  • IMAGE: השם של קובץ האימג' בקונטיינר.
  • HASH: ערך הגיבוב (hash) מסוג sha256 של התמונה. אפשר למצוא את זה בפלט של הבנייה.
  • FORMAT: הגדרה אופציונלית שבה אפשר לציין פורמט פלט.

פלט לדוגמה

מקורות המידע על הבנייה נראים כך:

      image_summary:
      digest: sha256:7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3
      fully_qualified_digest: us-central1-docker.pkg.dev/my-project/my-repo/my-image@sha256:7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3
      registry: us-central1-docker.pkg.dev
      repository: my-repo
      slsa_build_level: 0
    provenance_summary:
      provenance:
      - build:
          inTotoSlsaProvenanceV1:
            _type: https://in-toto.io/Statement/v1
            predicate:
              buildDefinition:
                buildType: https://cloud.google.com/build/gcb-buildtypes/google-worker/v1
                externalParameters:
                  buildConfigSource:
                    path: cloudbuild.yaml
                    ref: refs/heads/main
                    repository: git+https://github.com/my-username/my-git-repo
                  substitutions: {}
                internalParameters:
                  systemSubstitutions:
                    BRANCH_NAME: main
                    BUILD_ID: e73ca1d4-ec4a-4ea6-acdd-ac8bb16dcc79
                    COMMIT_SHA: 525c52c501739e6df0609ed1f944c1bfd83224e7
                    LOCATION: us-west1
                    PROJECT_NUMBER: '265426041527'
                    REF_NAME: main
                    REPO_FULL_NAME: my-username/my-git-repo
                    REPO_NAME: my-git-repo
                    REVISION_ID: 525c52c501739e6df0609ed1f944c1bfd83224e7
                    SHORT_SHA: 525c52c
                    TRIGGER_BUILD_CONFIG_PATH: cloudbuild.yaml
                    TRIGGER_NAME: github-trigger-staging
                  triggerUri: projects/265426041527/locations/us-west1/triggers/a0d239a4-635e-4bd3-982b-d8b72d0b4bab
                resolvedDependencies:
                - digest:
                    gitCommit: 525c52c501739e6df0609ed1f944c1bfd83224e7
                  uri: git+https://github.com/my-username/my-git-repo@refs/heads/main
                - digest:
                    sha256: 154fcd4d2d65c6a35b06b98053a0829c581e223d530be5719326f5d85d680e8d
                  uri: gcr.io/cloud-builders/docker@sha256:154fcd4d2d65c6a35b06b98053a0829c581e223d530be5719326f5d85d680e8d
              runDetails:
                builder:
                  id: https://cloudbuild.googleapis.com/GoogleHostedWorker
                byproducts:
                - {}
                metadata:
                  finishedOn: '2023-08-01T19:57:10.734471Z'
                  invocationId: https://cloudbuild.googleapis.com/v1/projects/my-project/locations/us-west1/builds/e73ca1d4-ec4a-4ea6-acdd-ac8bb16dcc79
                  startedOn: '2023-08-01T19:56:57.451553160Z'
            predicateType: https://slsa.dev/provenance/v1
            subject:
            - digest:
                sha256: 7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3
              name: https://us-central1-docker.pkg.dev/my-project/my-repo/my-image
            - digest:
                sha256: 7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3
              name: https://us-central1-docker.pkg.dev/my-project/my-repo/my-image:latest
        createTime: '2023-08-01T19:57:14.810489Z'
        envelope:
          payload:
          eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdMWQ0LWVjNGEtNGVhNi1hY2RkLWFjOGJiMTZkY2M3OSIsICJzdGFydGVkT24iOiIyMDIzLTA4LTAxVDE5OjU2OjU3LjQ1MTU1MzE2MFoiLCAiZmluaXNoZWRPbiI6IjIwMjMtMDgtMDFUMTk6NTc6MTAuNzM0NDcxWiJ9LCAiYnlwcm9kdWN0cyI6W3t9XX19fQ==...
          payloadType: application/vnd.in-toto+json
          signatures:
          - keyid: projects/verified-builder/locations/global/keyRings/attestor/cryptoKeys/google-hosted-worker/cryptoKeyVersions/1
            sig: MEUCIQCss8UlQL2feFePRJuKTE8VA73f85iqj4OJ9SvVPqTNwAIgYyuyuIrl1PxQC5B109thO24Y6NA4bTa0PJY34EHRSVE=
        kind: BUILD
        name: projects/my-project/occurrences/71787589-c6a6-4d6a-a030-9fd041e40468
        noteName: projects/argo-qa/notes/intoto_slsa_v1_e73ca1d4-ec4a-4ea6-acdd-ac8bb16dcc79
        resourceUri: https://us-central1-docker.pkg.dev/my-project/my-repo/my-image@sha256:7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3
        updateTime: '2023-08-01T19:57:14.810489Z'
    

כמה דברים חשובים שכדאי לשים לב אליהם בדוגמה הזו:

  • מקור: ה-build הופעל ממאגר ב-GitHub.

  • הפניה לאובייקט: השדות בשמות digest ו-fileHash מתייחסים לאותו אובייקט. השדה digest שכלול בפלט לדוגמה מקודד בבסיס 16 (קידוד הקסדצימלי). אם אתם משתמשים בנתוני מקוריות בגרסה 0.1 של SLSA, הפלט שלכם משתמש בשדה fileHash שמקודד ב-base 64.

  • חתימות: אם אתם משתמשים בנתוני מקור של SLSA בגרסה 0.1, הפלט שלכם מכיל שתי חתימות בשדה envelope. החתימה הראשונה, עם שם המפתח provenanceSigner, משתמשת בחתימה שתואמת ל-DSSE (בפורמט של קידוד לפני אימות (PAE)), שאפשר לאמת במדיניות של Binary Authorization. מומלץ להשתמש בחתימה הזו בשימושים חדשים של המקור הזה. החתימה השנייה, עם שם המפתח builtByGCB, מסופקת לשימוש במערכות מדור קודם.

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

  • Payload: דוגמת המידע על מקורות שמוצגת בדף הזה מקוצרת כדי שיהיה קל לקרוא אותה. הפלט בפועל יהיה ארוך יותר, כי המטען הייעודי (payload) הוא גרסה בקידוד Base64 של כל מטא-נתוני המקור.

  • יחסי תלות: יחסי התלות שאתם מציינים בקובץ הבנייה נכללים בתיעוד המקור, בשדה resolvedDependencies.

הצגת מקורות של פריטי מידע שאינם קשורים למאגרי תגים

כשמעלים ארטיפקטים של build ל-Artifact Registry, ‏ Cloud Build יוצר מטא-נתונים של מקוריות SLSA לאפליקציות עצמאיות של Go,‏ Java (Maven),‏ Python ו-Node.js (npm).

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

    בסיום הבנייה, רושמים את BuildID.

  2. אפשר לאחזר את מטא-נתוני המקור באמצעות קריאה ישירה ל-API או באמצעות gcloud CLI. כדי למצוא את המקור של גרסת build ספציפית, צריך לסנן את התוצאות לפי מזהה ה-build.

    gcloud

    gcloud container analysis occurrences list \
      --project="PROJECT_ID" \
      --filter='kind="BUILD" AND build.inTotoSlsaProvenanceV1.predicate.runDetails.metadata.invocationId="https://cloudbuild.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/builds/BUILD_ID"' \
      --format=json
    

    curl

    alias gcurl='curl -H "Authorization: Bearer $(gcloud auth print-access-token)" -H "Content-Type: application/json"'
    
    PROJECT_ID="PROJECT_ID"
    LOCATION="LOCATION"
    BUILD_ID="BUILD_ID"
    
    FILTER="kind%3D%22BUILD%22%20AND%20build.inTotoSlsaProvenanceV1.predicate.runDetails.metadata.invocationId%3D%22https%3A%2F%2Fcloudbuild.googleapis.com%2Fv1%2Fprojects%2F${PROJECT_ID}%2Flocations%2F${LOCATION}%2Fbuilds%2F${BUILD_ID}%22"
    
    gcurl "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/occurrences?filter=${FILTER}"
    

    מחליפים את הפלייסהולדרים בדוגמאות הקודמות:

    • PROJECT_ID: מזהה הפרויקט ב- Google Cloud .
    • LOCATION: האזור שבו בוצעה הבנייה, למשל us-central1.
    • BUILD_ID: המזהה של הגרסה שמעניינת אתכם.

    הפונקציה מחזירה את המופעים הספציפיים של סוג BUILD שתואמים למזהה הבנייה שצוין.

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

אימות המקור

בקטע הזה מוסבר איך לאמת את מקורות ה-build של קובצי אימג' בקונטיינר.

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

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

מידע נוסף זמין במאמר בנושא הגנה על גרסאות build.

אימות מקור באמצעות הכלי לאימות SLSA

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

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

כדי להשתמש בכלי לאימות SLSA:

  1. מתקינים גרסה 2.1 ואילך ממאגר slsa-verifier

    go install github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier@VERSION
    
  2. ב-CLI, מגדירים משתנה למזהה התמונה:

    export IMAGE=LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE@sha256:HASH
    

    כאשר:

    • LOCATION: מיקום אזורי או רב-אזורי.
    • PROJECT_ID: Google Cloud מזהה הפרויקט.
    • REPOSITORY: שם המאגר.
    • IMAGE: שם התמונה.
    • HASH: ערך הגיבוב (hash) מסוג sha256 של התמונה. אפשר למצוא את זה בפלט של הבנייה.
  3. נותנים ל-CLI של gcloud הרשאות גישה לנתוני המקור כדי שמאמת ה-SLSA יוכל לגשת אליהם:

    gcloud auth configure-docker LOCATION-docker.pkg.dev
    
  4. מאחזרים את מקור התמונה ושומרים אותו כ-JSON:

    gcloud artifacts docker images describe $IMAGE --format json --show-provenance > provenance.json
    
  5. אימות המקור:

    slsa-verifier verify-image "$IMAGE" \
    --provenance-path provenance.json \
    --source-uri SOURCE \
    --builder-id=BUILDER_ID
    

    כאשר:

    • SOURCE הוא מזהה המשאבים האחיד (URI) של מאגר המקור של התמונה, לדוגמה github.com/my-repo/my-application.
    • BUILDER_ID המזהה הייחודי של הכלי ליצירת תוספים, לדוגמה https://cloudbuild.googleapis.com/GoogleHostedWorker

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

    הפלט אמור להיראות כך: PASSED: Verified SLSA provenance או FAILED: SLSA verification failed: <error details>.

מידע נוסף על דגלים אופציונליים זמין במאמר בנושא אפשרויות.

אימות מטא-נתוני המקור באמצעות ה-CLI של gcloud

כדי לוודא שלא נעשה שינוי באישור המקור של Build, אפשר לאמת את המקור באמצעות השלבים הבאים:

  1. יוצרים ספרייה חדשה ועוברים אליה.

    mkdir provenance && cd provenance
    
  2. בעזרת המידע מהשדה keyid, מאתרים את המפתח הציבורי.

    gcloud kms keys versions get-public-key 1 --location global --keyring attestor \
      --key builtByGCB --project verified-builder --output-file my-key.pub
    
  3. המאפיין payload מכיל את ייצוג ה-JSON של מקור הנתונים, בקידוד base64url. מפענחים את הנתונים ומאחסנים אותם בקובץ.

    gcloud artifacts docker images describe \
    LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE@sha256:HASH --show-provenance \
      --format=json | jq -r '.provenance_summary.provenance[] | select(.build.intotoStatement.predicateType == "https://slsa.dev/provenance/v0.1") | .envelope.payload' | tr '\-_' '+/' | base64 -d > provenance.json
    

    כשסוגי המקורות של SLSA גרסה 0.1 וגרסה 1.0 זמינים, הם מאוחסנים. אם רוצים לסנן לפי גרסה 1.0, צריך לשנות את predicateType ל-https://slsa.dev/provenance/v1. לדוגמה:

    gcloud artifacts docker images describe \
    LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE@sha256:HASH --show-provenance \
      --format=json | jq -r '.provenance_summary.provenance[] | select(.build.intotoStatement.predicateType == "https://slsa.dev/provenance/v1") | .envelope.payload' | tr '\-_' '+/' | base64 -d > provenance.json
    
  4. המעטפה מכילה גם את החתימה על המקור. מפענחים את הנתונים ומאחסנים אותם בקובץ.

      gcloud artifacts docker images describe LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE@sha256:HASH --show-provenance \
      --format=json | jq -r '.provenance_summary.provenance[] | select(.build.intotoStatement.predicateType == "https://slsa.dev/provenance/v0.1") | .envelope.signatures[0].sig' | tr '\-_' '+/' | base64 -d > signature.bin
    

    אם רוצים לסנן לפי גרסה 1.0, צריך לשנות את predicateType ל-https://slsa.dev/provenance/v1. לדוגמה:

    gcloud artifacts docker images describe LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE@sha256:HASH --show-provenance \
    --format=json | jq -r '.provenance_summary.provenance[] | select(.build.intotoStatement.predicateType == "https://slsa.dev/provenance/v1") | .envelope.signatures[0].sig' | tr '\-_' '+/' | base64 -d > signature.bin
    
  5. הפקודה שלמעלה מתייחסת לחתימת המקור הראשונה (.provenance_summary.provenance[0].envelope.signatures[0]) שנחתמה על ידי המפתח provenanceSigner. המטען הייעודי חתום על המעטפה בפורמט PAE. כדי לאמת את המקור, מריצים את הפקודה הזו כדי להמיר את המקור לפורמט PAE הצפוי של "DSSEv1" + SP + LEN(type) + SP + type + SP + LEN(body) + SP + body.

    echo -n "DSSEv1 28 application/vnd.in-toto+json $(cat provenance.json | wc -c) $(cat provenance.json)" > provenance.json
    
  6. מאמתים את החתימה.

    openssl dgst -sha256 -verify my-key.pub -signature signature.bin provenance.json
    

    אחרי אימות מוצלח, הפלט הוא Verified OK.

המאמרים הבאים