לקוחות Security Command Center מתקשים לקבל תצוגה מרכזית ומקיפה של תוצאות הסריקה מסביבות Continuous Integration/Continuous Delivery (CI/CD). היעדר תצוגה מאוחדת מקשה על ניהול נקודות חולשה. השילוב של CI/CD הוא רכיב של הגנה על ארטיפקטים (גרסת טרום-השקה (Preview)) שמאפשר לכם לחבר כמה פייפליינים של CI/CD כדי לזהות נקודות חולשה לאורך מחזור החיים של פיתוח התוכנה.
השילוב של CI/CD תומך ב-GitHub Actions, ב-Cloud Build וב-Jenkins. אחרי החיבור, אפשר להשתמש בכל אחת מהפלטפורמות האלה של CI/CD כדי להגדיר מדיניות הגנה על ארטיפקטים, וכך לקבל תובנות ולשלוט באופן פרואקטיבי במצב האבטחה.
סקירה כללית
שילוב של CI/CD מציע את היתרונות הבאים:
- אכיפת מדיניות מקצה לקצה: מסייעת להגנה על ארטיפקטים להחיל מדיניות אבטחה עקבית מקוד לענן.
- זיהוי מקיף של איומים: סריקה לאיתור נקודות חולשה, סודות חשופים, רישיונות בעייתיים וחבילות זדוניות.
- תאימות רחבה ל-CI/CD: פועל עם Jenkins ו-GitHub Actions.
- אופטימיזציה ל-CI/CD: קובץ בינארי קל משקל מבטיח פעולה יעילה בסביבות מקומיות.
- Flexible output: מספק תוצאות בפורמטים JSON ו-SARIF שהם פורמטים סטנדרטיים בתעשייה.
- תובנות אבטחה מרכזיות: מספקות תצוגות ברורות של התאמה למדיניות ישירות במרכז הבקרה לאבטחה.
הסורק הזה מאכלס את Security Command Center באופן מקורי, ומספק תצוגה מאוחדת של ממצאי אבטחה שמתמקדת בנכסים, החל מיצירת הארטיפקט.
השילוב עם CI/CD עוזר לאכוף את מדיניות ההגנה על ארטיפקטים בכל מחזור החיים של התוכנה. כך מוודאים שהארטיפקטים מאומתים בהתאם לתקנים, החל משלב הבנייה ועד לפריסה.
קהל
שילוב של CI/CD יכול לעזור לבעלי העניין במשימות הבאות:
- משתמשים עיקריים: צוותי DevOps וצוותי הנדסת פלטפורמות
- ניהול ושילוב: אחראי על ניהול כלי הסריקה ושילובו ישירות בצינורות עיבוד נתונים של CI/CD.
- הגדרת כללי מדיניות: הגדרת שלבי הסריקה.
- מעקב אחרי תאימות: עוקבים אחרי התאימות של הגרסה ועובדים עם אדמינים של אבטחה כדי לשפר את המדיניות.
- משתמשים משניים: אדמינים של אבטחה
- יוצרי מדיניות: מגדירים ואוכפים מדיניות אבטחה על סמך חשיבות עסקית.
- אוטומציה של אכיפה: אוטומציה של אבטחה ב-CI/CD כדי לצמצם את הרעש שנובע מחולשות ולהגדיר קריטריונים לשליטה בגישה.
- פיקוח: שיתוף פעולה עם DevOps והצעת מרכז שליטה לניהול כדי לעקוב אחרי פגיעויות שמוגנות על ידי שער.
- משתמשים משניים: מפתחי אפליקציות
- בדיקה ותיקון: אפשר לבדוק את תוצאות הערכת המדיניות, לבדוק את תוצאות הבנייה ולתקן בעיות אבטחה שסומנו.
- הערכה: מתחילים בהערכת המדיניות באופן עקיף דרך תהליך build של צינור ה-CI.
- שמירה על תאימות: שמירה על תאימות לדרישות האבטחה בלי לשבש את תהליכי העבודה של הפיתוח.
מושגים והגדרות חשובים
- נקודות חולשה וחשיפה נפוצות (CVE): נקודת חולשה באבטחת מחשב שנחשפה לציבור וקיבלה מזהה ייחודי. המזהים האלה עוזרים לעקוב אחרי נקודות חולשה לצורך תיקון.
- רשימת חומרים (BOM) של תוכנה (SBOM): מלאי של רכיבי תוכנה ויחסי תלות שמתאים לקריאה למחשבים. ה-SBOM כולל מידע על הגרסה, המקור ופרטים רלוונטיים אחרים של כל רכיב. אפשר להשתמש ב-SBOM כדי לזהות CVE וסיכוני אבטחה אחרים.
- ארטיפקט: פלט של פיתוח תוכנה שעבר אימות וקיבל גרסה, כמו נתונים או פריט שנוצרו במהלך תהליך build.
- תג Connector: תג לתמונות. כשמעבירים את המחבר מצינור ה-CI לשירות הגנה על ארטיפקטים, הוא קובע אילו מדיניות להפעיל מול התמונה שנבנית.
- מדיניות CI: מדיניות בנושא פגיעויות שמגדירה כללים או קריטריונים לשליטה בפגיעויות ובחבילות שמותרות בסביבה שלכם.
תהליך עבודה כללי
- יצירת מחברים של CI.
- יוצרים כללי מדיניות להגנה על ארטיפקטים באמצעות המחברים שהוגדרו בשלב הקודם כדי להגדיר את היקף המדיניות.
- הפעלת הערכות של ארטיפקטים.
במהלך ההערכה, נוצרת תמונה והיא נבדקת בהשוואה למדיניות מוגדרת מראש. אם המדיניות נכשלת, ה-build נכשל. מהנדסי DevOps או מהנדסי אפליקציות צריכים לבדוק את פרטי הכשל כדי למצוא את נקודת החולשה הספציפית, לעדכן את התלות בהתאם לפרטי ה-CVE ולהפעיל מחדש את צינור הנתונים.
לפני שמתחילים
כדי להשתמש בשילוב CI/CD, צריך להפעיל את הגנה על ארטיפקטים. הוראות מפורטות מופיעות בקטע לפני שמתחילים במאמרי העזרה בנושא הגנה על ארטיפקטים.
אחרי זה תוכלו ליצור מחברים במסוףGoogle Cloud או באמצעות Google Cloud CLI.
יצירת מחבר במסוף Google Cloud
כדי ליצור מחבר:
במסוף Google Cloud , עוברים אל Security > Settings (אבטחה > הגדרות).
בכרטיס Artifact guard (הגנה על ארטיפקטים), לוחצים על Manage settings (ניהול הגדרות).
לוחצים על Create connector (יצירת מחבר) ומזינים את הפרטים הבאים של המחבר:
- מזהה המחבר: הוספת מזהה למחבר.
- תיאור: מזינים תיאור של המחבר.
- פלטפורמת CI/CD: בוחרים את פלטפורמת ה-CI/CD המתאימה מהרשימה. אפשר להשתמש במחבר הזה רק בצינורות עיבוד נתונים שנבנו באמצעות פלטפורמת ה-CI/CD שסופקה.
לוחצים על יצירה.
הודעה מאשרת שהמחבר נוצר בהצלחה. המחברים הזמינים מפורטים בטבלה Connectors.
כדי להסיר מחבר, לוחצים על ליד המחבר, בוחרים באפשרות מחיקת המחבר ופועלים לפי ההנחיות. לוחצים על ביטול כדי להפסיק את הפעולה.
כדי לקשר מדיניות למחבר, לוחצים על לצד המחבר ובוחרים באפשרות הוספת מדיניות. ממשיכים בשלבים ליצירת מדיניות של הגנה על ארטיפקטים. מידע נוסף זמין במאמר יצירת מדיניות.
יצירת מחבר באמצעות Google Cloud CLI
בקטע הזה מפורטות הפקודות של ה-CLI של gcloud שזמינות לסריקת ארטיפקטים של CI/CD, ומוסבר איך להשתמש בהן.
דרישות מוקדמות ל-Google Cloud CLI
- מוודאים שגרסת ה-CLI של gcloud היא 559.0.0 ואילך.
- מגדירים את הפרויקט כפרויקט ההגדרות.
כדי לעשות זאת, מריצים את הפקודות הבאות ב-CLI של gcloud:
gcloud components update --version=559.0.0
gcloud config set project PROJECT_ID
פקודות של Google Cloud CLI
create
gcloud alpha scc artifact-guard connectors create CONNECTOR_ID \ --location=LOCATION \ (--organization=ORGANIZATION_ID | --project=PROJECT_NUMBER) \ --pipeline-type=PIPELINE_TYPE \ [--description=DESCRIPTION] \ [--display-name=DISPLAY_NAME]
- CONNECTOR_ID: המזהה של מחבר שרוצים ליצור.
- PIPELINE_TYPE: סוג הפייפליין של CI/CD. הפורמט חייב להיות אחד מהפורמטים הבאים:
GOOGLE_CLOUD_BUILDGITHUB_ACTIONSJENKINS_PIPELINE
- DESCRIPTION: תיאור טקסט של המחבר.
- DISPLAY_NAME: שם מוצג ידידותי למשתמש עבור המחבר.
get
gcloud alpha scc artifact-guard connectors describe CONNECTOR_ID \ --location=LOCATION \ (--organization=ORGANIZATION_ID | --project=PROJECT_NUMBER)
- CONNECTOR_ID: המזהה של מחבר שרוצים לקבל תיאור שלו.
list
gcloud alpha scc artifact-guard connectors list PARENT
- PARENT: ארגון או פרויקט. הפורמטים הקבילים של משאב האב כוללים:
{organizations/ORGANIZATION_ID/locations/LOCATION}{projects/PROJECT_NUMBER/locations/LOCATION}
delete
gcloud alpha scc artifact-guard connectors delete CONNECTOR_ID \ --location=LOCATION \ (--organization=ORGANIZATION_ID | --project=PROJECT_NUMBER)
- CONNECTOR_ID: המזהה של מחבר שרוצים למחוק.
הרצת הערכה
בדיקת נקודות חולשה נתמכת ב-GitHub Actions ובצינורות Jenkins. כדי לבצע הערכה, צריך לבצע את הפעולות הבאות:
הגדרת סודות
צינורות CI/CD שפועלים מחוץ ל- Google Cloud יכולים לבצע אימות באמצעות מפתחות של חשבון שירות או איחוד שירותי אימות הזהות של עומסי עבודה. הוראות מפורטות ליצירת סודות מופיעות במאמרים הבאים:
מפתחות לחשבונות שירות
איחוד שירותי אימות הזהות של עומסי עבודה (ל-GitHub Actions)
צריך להוסיף סודות לסביבת ה-CI/CD באחת מהשיטות הבאות:
שימוש במפתח של חשבון שירות
סוד אחד:
-
GCP_CREDENTIALS: התוכן של קובץ מפתח ה-JSON של חשבון השירות שהורדתם.
שיטת איחוד שירותי אימות הזהות של עומסי עבודה
שני סודות:
GCP_WORKLOAD_IDENTITY_PROVIDER: שם המשאב המלא של ספק מאגרי זהויות של עומסי עבודה. לדוגמה,projects/12345/locations/global/workloadIdentityPools/my-pool/providers/my-provider.GCP_SERVICE_ACCOUNT: כתובת האימייל של חשבון השירות שרוצים להתחזות אליו.
תבניות לשילוב צינורות עיבוד נתונים
כדי להפעיל הערכה, צריך ליצור קובץ שספציפי לצינור (Cloud Build, GitHub Actions או Jenkins) באמצעות תבניות הדוגמה הבאות:
Cloud Build
במאמר הגדרות של משתנים מוסבר על כל שדה.
steps: # Step 1: Generate auth token - name: 'gcr.io/cloud-builders/gcloud' id: 'Generate Token' entrypoint: 'bash' args: - '-c' - | echo "Starting token generation..." gcloud auth print-access-token > /workspace/gcp_token.txt if [ $? -eq 0 ]; then echo "Token generated successfully." else echo "Failed to generate token." >&2 exit 1 fi # Step 2: Build the image locally - name: 'gcr.io/cloud-builders/docker' id: 'Build Image' entrypoint: 'bash' args: - '-c' - | echo "🚧 Building Docker image from source code..." docker build -t ${_IMAGE_NAME_TO_SCAN}:${_IMAGE_TAG} . if [ $? -ne 0 ]; then echo "❌ Docker build failed." exit 1 fi echo "✅ Docker image built successfully: ${_IMAGE_NAME_TO_SCAN}:${_IMAGE_TAG}" # Step 3: Image scan for vulnerabilities - id: 'Image-Analysis' name: '${_SCANNER_IMAGE}' entrypoint: 'bash' args: - '-c' - | echo "Starting image scan with scanner: ${_SCANNER_IMAGE}" exit_code=0 docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /workspace:/workspace \ -e GCP_PROJECT_ID="${_PROJECT_ID}" \ -e ORGANIZATION_ID="${_ORGANIZATION_ID}" \ -e IMAGE_NAME="${_IMAGE_NAME_TO_SCAN}" \ -e IMAGE_TAG="${_IMAGE_TAG}" \ -e CONNECTOR_ID="${_CONNECTOR_ID}" \ -e TRIGGER_ID="${_TRIGGER_ID}" \ -e IGNORE_ERRORS="${_IGNORE_ERRORS}" \ -e GCP_ACCESS_TOKEN="$(cat /workspace/gcp_token.txt)" \ "${_SCANNER_IMAGE}" || exit_code=$? echo "Docker run finished with exit code: $exit_code" if [ $exit_code -eq 0 ]; then echo "✅ Evaluation succeeded: Conformant image." elif [ $exit_code -eq 1 ]; then echo "❌ Scan failed: Non-conformant image." exit 1 else if [ "${_IGNORE_ERRORS}" = "true" ]; then echo "⚠️ Server/internal error ignored. Continuing." else echo "❌ Server/internal error. Exiting." exit 1 fi fi # Step 4: Configure Docker authentication for Artifact Registry - name: 'gcr.io/cloud-builders/gcloud' id: 'Configure Docker Auth' entrypoint: 'bash' args: - '-c' - | echo "🔐 Configuring Docker authentication for Artifact Registry..." gcloud auth configure-docker us-east1-docker.pkg.dev -q echo "✅ Docker authentication configured." # Step 5: Push image to Artifact Registry - name: 'gcr.io/cloud-builders/docker' id: 'Push Image to Artifact Registry' entrypoint: 'bash' args: - '-c' - | docker tag "${_IMAGE_NAME_TO_SCAN}:${_IMAGE_TAG}" "us-east1-docker.pkg.dev/${_PROJECT_ID}/${_AR_REPOSITORY}/${_IMAGE_NAME_TO_SCAN}:${_IMAGE_TAG}" echo "🚀 Pushing $_FULL_AR_TAG..." docker push "us-east1-docker.pkg.dev/${_PROJECT_ID}/${_AR_REPOSITORY}/${_IMAGE_NAME_TO_SCAN}:${_IMAGE_TAG}" echo "✅ Image pushed successfully." substitutions: _IMAGE_NAME_TO_SCAN: 'checkout-image' _ORGANIZATION_ID: 'orgId' _CONNECTOR_ID: 'connectorId' _SCANNER_IMAGE: 'us-central1-docker.pkg.dev/ci-plugin/ci-images/scc-artifactguard-scan-image:latest' _IMAGE_TAG: 'latest' _TRIGGER_ID: 'cloud-build-job' _PROJECT_ID: 'projectId' _AR_REPOSITORY: 'images' _IGNORE_ERRORS: "false" serviceAccount: "projects/projectId/serviceAccounts/id-compute@developer.gserviceaccount.com" options: logging: CLOUD_LOGGING_ONLY
פעולות GitHub (סודי)
התבנית הזו מיועדת לפעולות GitHub שמשתמשות במפתח סודי.
- מוסיפים את המפתח הסודי של חשבון השירות (
GCP_CREDENTIALS). מידע על שדות נוספים זמין במאמר הגדרות משתנים.
# A workflow to BUILD the app image, RUN the scanner, and PUSH to AR if scan passes name: Build, Scan and Push on: workflow_dispatch: inputs: IMAGE_NAME_TO_SCAN: description: 'The tag for your application image to be built (e.g., my-app:latest)' required: true default: 'checkout-image' GCP_PROJECT_ID: description: 'GCP Project ID for authentication' required: true default: 'projectId' AR_REPOSITORY: description: 'Artifact Registry repository name (e.g., app-repo)' required: false default: 'images' ORGANIZATION_ID: description: 'Your GCP Organization ID' required: true default: 'orgId' CONNECTOR_ID: description: 'The ID for your pipeline connector' required: true default: 'connectorId' SCANNER_IMAGE: description: 'The full registry path for your PRE-BUILT scanner tool' required: true default: 'us-central1-docker.pkg.dev/ci-plugin/ci-images/scc-artifactguard-scan-image:latest' IMAGE_TAG: description: 'The Docker image version (of the app image)' required: true default: 'latest' IGNORE_SERVER_ERRORS: description: 'Ignore server errors' required: false type: boolean default: false VERBOSITY: description: 'Verbosity flag' required: false default: 'HIGH' jobs: build-and-scan: runs-on: ubuntu-latest steps: # 1. Check out repository (for your app's Dockerfile) - name: Check out repository uses: actions/checkout@v4 # 2. Authenticate to Google Cloud - name: Authenticate to GCP id: auth uses: 'google-github-actions/auth@v2' with: credentials_json: '${{ secrets.GCP_CREDENTIALS }}' # 3. Set up the gcloud CLI - name: Set up Cloud SDK uses: 'google-github-actions/setup-gcloud@v2' with: project_id: ${{ inputs.GCP_PROJECT_ID }} # 4. Configure Docker (needed to pull SCANNER_IMAGE and push app image) - name: Configure Docker run: gcloud auth configure-docker us-central1-docker.pkg.dev --quiet # 5. Build Application Image Locally (IMAGE_NAME_TO_SCAN) - name: Build Application Image Locally uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile push: false # <-- Do not push load: true # <-- Load image into the runner's local daemon # Tag the image with the name the scanner will look for tags: | ${{ inputs.IMAGE_NAME_TO_SCAN }}:${{ inputs.IMAGE_TAG }} # 6. Run Image Scan (Using the SCANNER_IMAGE) - name: 'Run Image Analysis Scan' if: steps.auth.outcome == 'success' run: | echo "📦 Pulling scanner image and running scan..." SCANNER_IMAGE="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.SCANNER_IMAGE || env.SCANNER_IMAGE }}" GCP_PROJECT_ID="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.GCP_PROJECT_ID || env.GCP_PROJECT_ID }}" ORGANIZATION_ID="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.ORGANIZATION_ID || env.ORGANIZATION_ID }}" IMAGE_NAME="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.IMAGE_NAME_TO_SCAN || env.IMAGE_NAME_TO_SCAN }}" IMAGE_TAG="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.IMAGE_TAG || env.IMAGE_TAG }}" CONNECTOR_ID="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.CONNECTOR_ID || env.CONNECTOR_ID }}" VERBOSITY="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.VERBOSITY || env.VERBOSITY }}" IGNORE_ERRORS="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.IGNORE_SERVER_ERRORS || (env.IGNORE_SERVER_ERRORS == 'true') }}" exit_code=0 # This 'docker run' pulls the SCANNER_IMAGE from the registry # and passes the name of the locally-built app image (IMAGE_NAME) docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ -v ${{ steps.auth.outputs.credentials_file_path }}:/tmp/scc-key.json \ -e GCLOUD_KEY_PATH=/tmp/scc-key.json \ -e GCP_PROJECT_ID="${GCP_PROJECT_ID}" \ -e ORGANIZATION_ID="${ORGANIZATION_ID}" \ -e IMAGE_NAME="${IMAGE_NAME}" \ -e IMAGE_TAG="${IMAGE_TAG}" \ -e CONNECTOR_ID="${CONNECTOR_ID}" \ -e BUILD_TAG="${{ github.workflow }}" \ -e BUILD_ID="${{ github.run_number }}" \ -e VERBOSITY="${VERBOSITY}" \ "${SCANNER_IMAGE}" \ || exit_code=$? echo "Docker run finished with exit code: $exit_code" # --- Replicate Jenkins Exit Code Logic --- if [ $exit_code -eq 0 ]; then echo "✅ Evaluation succeeded: Conformant image." elif [ $exit_code -eq 1 ]; then echo "❌ Scan failed: Non-conformant image (vulnerabilities found)." exit 1 # Fail the step else if [ "$IGNORE_ERRORS" = "true" ]; then echo "⚠️ Server/internal error occurred (Code: $exit_code), but IGNORE_SERVER_ERRORS=true. Proceeding." else echo "❌ Server/internal error occurred (Code: $exit_code) during evaluation. Set IGNORE_SERVER_ERRORS=true to override." exit 1 # Fail the step fi fi # 8. Push Application Image (ONLY if scan succeeded) # This step only runs if the 'Run Image Analysis Scan' step above exited with 0 - name: Push Application Image to Artifact Registry run: | # Define the local and remote tags LOCAL_IMAGE_NAME="${{ inputs.IMAGE_NAME_TO_SCAN }}:${{ inputs.IMAGE_TAG }}" # This path is based on your 'Configure Docker' step (us-central1) # and the new AR_REPOSITORY input. FULL_AR_TAG="us-central1-docker.pkg.dev/${{ inputs.GCP_PROJECT_ID }}/${{ inputs.AR_REPOSITORY }}/${{ inputs.IMAGE_NAME_TO_SCAN }}:${{ inputs.IMAGE_TAG }}" echo "Tagging local image ${LOCAL_IMAGE_NAME} as ${FULL_AR_TAG}" docker tag "${LOCAL_IMAGE_NAME}" "${FULL_AR_TAG}" echo "Pushing ${FULL_AR_TAG} to Artifact Registry..." docker push "${FULL_AR_TAG}"
פעולות GitHub (WIF)
התבנית הזו מיועדת לפעולות GitHub שמשתמשות באיחוד שירותי אימות הזהות של עומסי עבודה.
- מוסיפים את ספק מאגרי זהויות של עומסי עבודה בסוד של GitHub (
GCP_WORKLOAD_IDENTITY_PROVIDER). - מוסיפים את חשבון השירות בסוד של GitHub (
GCP_SERVICE_ACCOUNT). מידע על שדות נוספים זמין במאמר הגדרות משתנים.
# A workflow to BUILD the app image, RUN the scanner, and PUSH to AR if scan passes name: Build, Scan and Push on: push: branches: - main workflow_dispatch: inputs: IMAGE_NAME_TO_SCAN: description: 'The tag for your application image to be built (e.g., my-app:latest)' required: true default: 'checkout-image' GCP_PROJECT_ID: description: 'GCP Project ID for authentication and configuration' required: true default: 'projectId' ORGANIZATION_ID: description: 'Your GCP Organization ID' required: true default: 'orgId' CONNECTOR_ID: description: 'The ID for your pipeline connector' required: true default: 'connectorId' SCANNER_IMAGE: description: 'The Docker image that contains your scanner script' required: true default: 'us-central1-docker.pkg.dev/ci-plugin/ci-images/scc-artifactguard-scan-image:latest' IMAGE_TAG: description: 'The Docker image version' required: true default: 'latest' IGNORE_SERVER_ERRORS: description: 'If true, the pipeline continues on server/internal scanner errors.' required: false type: boolean default: false jobs: image-analysis-job: runs-on: ubuntu-latest permissions: contents: 'read' id-token: 'write' env: IMAGE_NAME_TO_SCAN: 'webgoat/webgoat' GCP_PROJECT_ID: 'projectId' ORGANIZATION_ID: 'orgId' CONNECTOR_ID: 'connectorId' SCANNER_IMAGE: 'us-central1-docker.pkg.dev/ci-plugin/ci-images/scc-artifactguard-scan-image:latest' IMAGE_TAG: 'imageTag' IGNORE_SERVER_ERRORS: 'false' steps: # Step 1: Authenticate and create credential file - name: 'Authenticate to Google Cloud' id: 'auth' uses: 'google-github-actions/auth@v2' with: workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }} create_credentials_file: true # Step 2: Set up gcloud SDK - name: 'Set up gcloud SDK' uses: 'google-github-actions/setup-gcloud@v2' # Step 3: Configure Docker for registries - name: 'Configure Docker for Artifact Registry' run: | gcloud auth configure-docker us-central1-docker.pkg.dev --quiet # Step 4: Run Image Analysis Scan and Handle Exit Codes - name: 'Run Image Analysis Scan' run: | echo "📦 Running container from scanner image..." # Determine values: Use manual inputs if available (event_name=workflow_dispatch), otherwise use env defaults SCANNER_IMAGE="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.SCANNER_IMAGE || env.SCANNER_IMAGE }}" GCP_PROJECT_ID="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.GCP_PROJECT_ID || env.GCP_PROJECT_ID }}" ORGANIZATION_ID="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.ORGANIZATION_ID || env.ORGANIZATION_ID }}" IMAGE_NAME="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.IMAGE_NAME_TO_SCAN || env.IMAGE_NAME_TO_SCAN }}" IMAGE_TAG="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.IMAGE_TAG || env.IMAGE_TAG }}" CONNECTOR_ID="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.CONNECTOR_ID || env.CONNECTOR_ID }}" IGNORE_ERRORS="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.IGNORE_SERVER_ERRORS || (env.IGNORE_SERVER_ERRORS == 'true') }}" # Variable to store exit code exit_code=0 # Run docker and capture exit code using || trick docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ -v ${{ steps.auth.outputs.credentials_file_path }}:/gcp-creds.json \ -e GOOGLE_APPLICATION_CREDENTIALS=/gcp-creds.json \ -e GCP_PROJECT_ID="${GCP_PROJECT_ID}" \ -e ORGANIZATION_ID="${ORGANIZATION_ID}" \ -e IMAGE_NAME="${IMAGE_NAME}" \ -e IMAGE_TAG="${IMAGE_TAG}" \ -e CONNECTOR_ID="${CONNECTOR_ID}" \ -e RUN_ID="${{ github.run_number }}" \ "${SCANNER_IMAGE}" \ || exit_code=$? echo "Docker run finished with exit code: $exit_code" if [ $exit_code -eq 0 ]; then echo "✅ Evaluation succeeded: Conformant image." elif [ $exit_code -eq 1 ]; then echo "❌ Scan failed: Non-conformant image (vulnerabilities found)." exit 1 # Fail the step else if [ "$IGNORE_ERRORS" = "true" ]; then echo "⚠️ Server/internal error occurred (Code: $exit_code), but IGNORE_SERVER_ERRORS=true. Proceeding." # Do nothing, step passes else echo "❌ Server/internal error occurred (Code: $exit_code) during evaluation. Set IGNORE_SERVER_ERRORS=true to override." exit 1 # Fail the step fi fi
Jenkins (סוד)
- הוספת מפתח סודי לחשבון שירות (
GCP_CREDENTIALS). מידע על שדות נוספים זמין במאמר הגדרות משתנים.
pipeline { agent any parameters { string( name: 'IMAGE_NAME_TO_SCAN', defaultValue: 'checkout-image', description: 'The tag for your application image to be built (e.g., my-app:latest)' ) string( name: 'GCP_PROJECT_ID', defaultValue: 'projectId', description: 'GCP Project ID for authentication' ) string( name: 'AR_REPOSITORY', defaultValue: 'images', description: 'Artifact Registry repository name (e.g., app-repo)' ) string( name: 'ORGANIZATION_ID', defaultValue: 'orgId', description: 'Your GCP Organization ID' ) string( name: 'CONNECTOR_ID', defaultValue: 'connectorId', description: 'The ID for your pipeline connector' ) string( name: 'SCANNER_IMAGE', defaultValue: 'us-central1-docker.pkg.dev/ci-plugin/ci-images/scc-artifactguard-scan-image:latest', description: 'The full registry path for your PRE-BUILT scanner tool' ) string( name: 'IMAGE_TAG', defaultValue: 'latest', description: 'The Docker image version (of the app image)' ) booleanParam( name: 'IGNORE_SERVER_ERRORS', defaultValue: false, description: 'Ignore server errors' ) string( name: 'VERBOSITY', defaultValue: 'HIGH', description: 'Verbosity flag' ) } stages { // Stage 1: Check out the source code stage('Checkout') { steps { echo "Checking out source code..." checkout scm } } // Stage 2: Build application image stage('Build Application Image') { steps { echo "Building application image: ${params.IMAGE_NAME_TO_SCAN}:${params.IMAGE_TAG}" sh "docker build -t ${params.IMAGE_NAME_TO_SCAN}:${params.IMAGE_TAG} -f ./Dockerfile ." } } // Stage 3: Authenticate to Google Cloud and run scanner stage('Scan Image') { steps { script { withCredentials([file(credentialsId: 'GCP_CREDENTIALS', variable: 'GCP_KEY_FILE')]) { // Authenticate sh "gcloud auth activate-service-account --key-file=\"$GCP_KEY_FILE\"" sh 'gcloud auth list' sh 'gcloud auth configure-docker gcr.io --quiet' sh 'gcloud auth configure-docker us-central1-docker.pkg.dev --quiet' // Run scanner container def exitCode = sh( script: """ echo "📦 Running scanner container from image: ${params.SCANNER_IMAGE}" docker run --rm \\ -v /var/run/docker.sock:/var/run/docker.sock \\ -v "$GCP_KEY_FILE":/tmp/scc-key.json \\ -e GCLOUD_KEY_PATH=/tmp/scc-key.json \\ -e GCP_PROJECT_ID="${params.GCP_PROJECT_ID}" \\ -e ORGANIZATION_ID="${params.ORGANIZATION_ID}" \\ -e IMAGE_NAME="${params.IMAGE_NAME_TO_SCAN}" \\ -e IMAGE_TAG="${params.IMAGE_TAG}" \\ -e CONNECTOR_ID="${params.CONNECTOR_ID}" \\ -e BUILD_TAG="${env.JOB_NAME}" \\ -e BUILD_ID="${env.BUILD_NUMBER}" \\ "${params.SCANNER_IMAGE}" """, returnStatus: true ) if (exitCode == 0) { echo "✅ Evaluation succeeded: Conformant image." } else if (exitCode == 1) { error("❌ Scan failed: Non-conformant image (vulnerabilities found).") } else { if (params.IGNORE_SERVER_ERRORS) { echo "⚠️ Server/internal error occurred, but IGNORE_SERVER_ERRORS=true. Proceeding with pipeline." } else { error("❌ Server/internal error occurred during evaluation. Set IGNORE_SERVER_ERRORS=true to override.") } } } } } } // Stage 4: Push Application Image stage('Push Application Image') { steps { script { def localImage = "${params.IMAGE_NAME_TO_SCAN}:${params.IMAGE_TAG}" def remoteTag = "us-central1-docker.pkg.dev/${params.GCP_PROJECT_ID}/${params.AR_REPOSITORY}/${params.IMAGE_NAME_TO_SCAN}:${params.IMAGE_TAG}" echo "Tagging local image ${localImage} as ${remoteTag}" sh "docker tag ${localImage} ${remoteTag}" echo "Pushing ${remoteTag} to Artifact Registry..." sh "docker push ${remoteTag}" } } } }
הגדרות של משתנים
בקטע הזה מפורטים שדות המשתנים שמשמשים בתבניות לשילוב צינורות.
IMAGE_NAME_TO_SCAN (חובה)
- מציין את התג של תמונת האפליקציה שתיבנה.
GCP_PROJECT_ID (חובה)
- מציינת את Google Cloud מזהה הפרויקט שמשמש לאימות ולתצורה.
AR_REPOSITORY (אופציונלי)
- מציין את השם של מאגר Artifact Registry שבו התמונה תפורסם אם הבנייה תצליח.
ORGANIZATION_ID (חובה)
- מזהה הארגון Google Cloud .
CONNECTOR_ID (חובה)
- מציין את מזהה המחבר של צינור עיבוד הנתונים שבו רוצים להשתמש.
SCANNER_IMAGE (חובה)
התמונה של הסורק המובנה מנתחת קוד, מזהה נקודות חולשה על ידי הערכת תמונות בהשוואה למדיניות במהלך הבנייה, ומפיקה תוצאת התאמה כדי לקבוע אם צינור ה-CI/CD עובר או נכשל.
פרטי התמונה:
us-central1-docker.pkg.dev/ci-plugin/ci-images/scc-artifactguard-scan-image:latest
VERBOSITY (אופציונלי)
- הסורק תומך בדגל
VERBOSITYאופציונלי שקובע את רמת הפירוט שמוצגת בפלט הסריקה. הפלט של הסורק משתנה בהתאם לרמת הפירוט ולתוצאת התאימות (עבר או נכשל). אפשר להגדיר את דגל הפירוט לערך
LOWאוHIGH. אם לא מציינים ערך, ברירת המחדל היאLOW.
דרגת מלל נמוכה (תמציתית)
ArtifactGuard Conformance : False
- פרטים על הסיבה לכישלון.
- רשימה של נקודות החולשה הנפוצות (CVE) הספציפיות שגרמו לכשל.
- הפונקציה מספקת סיכום של מספר ה-CVE, שמסווג לפי חומרה.
ArtifactGuard Conformance : Pass
- פרטים על שמות המדיניות.
- מספק רק את הסיכום של מספר ה-CVE לפי חומרה.
רמת פירוט גבוהה
רשימה מקיפה של כל נקודות החולשה שנמצאו.
ArtifactGuard Conformance : False
- כולל את הסיבה לכישלון.
- רשימה של נקודות החולשה הנפוצות (CVE) שגורמות לכשל.
- רשימה של כל ה-CVE שזוהו במדיניות.
- מספקת סיכום של מספר ה-CVE, בפילוח לפי חומרת הבעיה.
- רשימה מקיפה של כל נקודות החולשה שזוהו.
ArtifactGuard Conformance : Pass
- רשימה של כל ה-CVE שזוהו במדיניות.
- מספקת סיכום של מספר ה-CVE, בפילוח לפי חומרת הבעיה.
- רשימה מקיפה של כל נקודות החולשה שזוהו.
IGNORE_SERVER_ERRORS (אופציונלי)
- דגל בוליאני אופציונלי. אם
true, הצינור ממשיך לפעול למרות שגיאות השרת. ברירת המחדל היאfalse.
התחלת הערכה
במהלך תהליך build, שיטה שמבוססת על Docker מעריכה את התמונה בהתאם למדיניות שהוגדרה מראש. הלוגיקה של סריקת נקודות החולשה נמצאת בתוך
us-central1-docker.pkg.dev/ci-plugin/ci-images/scc-artifactguard-scan-image:latest
התמונה.
כדי להפעיל סריקת פגיעויות בצינור עיבוד הנתונים של CI/CD, מריצים את הפקודה הבאה:
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ${{ steps.auth.outputs.credentials_file_path }}:/gcp-creds.json \
-e GOOGLE_APPLICATION_CREDENTIALS=/gcp-creds.json \
-e GCP_PROJECT_ID="${GCP_PROJECT_ID}" \
-e ORGANIZATION_ID="${ORGANIZATION_ID}" \
-e IMAGE_NAME="${IMAGE_NAME}" \
-e IMAGE_TAG="${IMAGE_TAG}" \
-e CONNECTOR_ID="${CONNECTOR_ID}" \
-e RUN_ID="${{ github.run_number }}" \
"${SCANNER_IMAGE}" \
|| exit_code=$?
השילוב של CI/CD מעביר את קודי היציאה של קונטיינר Docker לזמן הריצה של Jenkins או GitHub Actions, שקובע את מצב ההצלחה או הכשל של צינור עיבוד הנתונים.
ביצועים ומגבלות
- הערכת ארטיפקטים: תמונה מוערכת רק אם היא עומדת בקריטריונים הבאים:
- הגודל של אובייקט Package Uniform Resource Locator (pURL) לא יכול לחרוג מ-100MB.
- התמונה צריכה להכיל 500 כתובות pURL או פחות.
- עד 1,200 בקשות API לדקה (20 QPS) לכל פרויקט צרכן לכל השיטות בשירות הגנה על ארטיפקטים.
- SLO: הערכת הארטיפקט נמשכת כשתי דקות.
פתרון בעיות
בקטע הזה מפורטות שגיאות נפוצות ומוסבר איך לפתור אותן.
כשלים ב-CreateConnector
| שדה | חובה/אופציונלי | מגבלות |
|---|---|---|
name |
חובה | פורמט: הערך חייב להתאים לביטוי הרגולרי
[a-zA-Z0-9\\-\\s_]+$ הערך חייב להתאים לאחד או יותר מהערכים הבאים:
אורך מקסימלי: 64 תווים. |
pipeline_type |
חובה | צריך להזין אחד מהערכים הבאים של enum:
|
description |
אופציונלי | האורך המקסימלי הוא 256 תווים. |
display_name |
אופציונלי | האורך המקסימלי הוא 256 תווים. |
שגיאות אחרות
בטבלה הבאה מפורטות כמה שגיאות נפוצות והצעות לפתרונות.
| הודעת השגיאה | הסיבה | פעולה/פתרון |
|---|---|---|
ההרשאה artifactscanguard.connectors.create
נדחתה במשאב |
למשתמש או לחשבון השירות חסרה הרשאת IAM במשאב (פרויקט, תיקייה או ארגון) artifactscanguard.connectors.create
. |
נותנים למשתמש שקורא ל-API תפקיד ב-IAM שכולל את ההרשאה artifactscanguard.connectors.create. |
status.ErrFailedPrecondition |
יכול להיות שתהליך ההצטרפות עדיין מתבצע גם אם Google Cloud המסוף מציג את השירות כמופעל. | דיווח על בעיה לצוות התמיכה. |
status.ErrInvalidArgument |
כשלים באימות השדות | מוודאים שהבקשה CreateConnector עומדת במגבלות שצוינו. |