CI/CD 整合功能會將 CI/CD 管道連結至構件防護,以便在建構階段偵測容器安全漏洞。
掃描器支援 GitHub Actions、Cloud Build 和 Jenkins。整合至管道後,這項工具會在映像檔推送至登錄檔之前,根據構件防護政策評估容器映像檔。
掃描器功能
持續整合/持續推送軟體更新整合會在持續整合/持續推送軟體更新工作流程中以二進位檔的形式執行,以執行下列工作:
- 建構時政策評估:根據您設定的構件防護政策,掃描新建立的容器映像檔。
- 封鎖建構作業:將結束代碼傳回 CI/CD 執行器 (GitHub Actions、Cloud Build 或 Jenkins),封鎖違反安全政策的建構作業。
- 掃描報告:將安全漏洞掃描結果傳送至 Security Command Center,並以 JSON 或 SARIF 格式輸出本機報告。
目標角色和職責
CI/CD 整合功能適用於下列團隊:
- DevOps 或平台工程團隊:建立管道連接器,並將掃描器執行步驟新增至 CI/CD 工作流程設定。
- 安全管理員:定義掃描工具強制執行的建構階段安全漏洞政策。
- 應用程式開發人員:查看 CI/CD 建構輸出內容中的掃描執行記錄,找出並修正違反政策的情形。
重要詞彙與概念
- 常見安全漏洞與弱點 (CVE):公開揭露的電腦安全漏洞,並指派專屬 ID。
- 軟體物料清單 (SBOM):機器可讀的軟體元件和依附元件清單,用於識別 CVE 和其他安全風險。
- 構件:在構件防護的脈絡中,是指由 CI/CD 管道建構的容器映像檔。
- 連接器:可將 CI/CD 管道連結至構件防護機制的資源。在掃描期間從 CI 管道傳遞時,連接器 ID 會決定評估映像檔的政策。
- CI 政策:定義特定 CVE、嚴重程度和套件規則的安全漏洞政策,會在 CI/CD 建構期間強制執行。
高階工作流程
如要設定及執行 CI/CD 漏洞掃描,請完成下列工作流程:
- 為目標 CI/CD 平台建立 CI 連接器。
- 建立構件防護政策,並在管道範圍中加入連接器 ID。
- 設定 CI/CD 管道,向Google Cloud進行驗證、建構容器映像檔,並執行掃描器容器。
管道執行時,掃描器會根據政策評估容器映像檔。如果圖片違反政策,掃描器會傳回失敗結束代碼,導致建構失敗。開發人員接著可以檢查建構作業記錄、更新有安全漏洞的依附元件,然後重新執行建構作業。
事前準備
如要使用 CI/CD 整合功能,必須啟用構件防護機制。如需操作說明,請參閱構件防護說明文件中的「開始前」。
建立連接器
控制台
如要在 Google Cloud 控制台中建立連結器,請按照下列步驟操作:
- 在 Google Cloud 控制台中,依序點選「Security」>「Settings」。
- 在「構件防護」資訊卡中,按一下「管理設定」。
- 按一下「建立連接器」,然後輸入連接器的下列詳細資料:
- 連接器 ID:新增連接器的 ID。
- 說明:輸入連接器的說明。
- CI/CD 平台:從清單中選取對應的 CI/CD 平台。請只在以所選 CI/CD 平台建構的管道中使用這個連接器。
- 點選「建立」。
系統會顯示通知,確認連接器已成功建立。「連接器」表格會列出可用的連接器。
gcloud CLI
如要使用 gcloud CLI 建立連接器,請執行下列指令:
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:連接器的 ID (例如
my-connector)。 - LOCATION:儲存資料的 Security Command Center 位置。僅支援
global。 - ORGANIZATION_ID:組織 ID。
- PROJECT_NUMBER:專案編號 (數字)。
- PIPELINE_TYPE:CI/CD 管道的類型。必須是下列其中一個值:
GOOGLE_CLOUD_BUILDGITHUB_ACTIONSJENKINS_PIPELINE
- DESCRIPTION:連接器的文字說明。
- DISPLAY_NAME:連接器的好記顯示名稱。
更新連接器
控制台
如要在 Google Cloud 控制台中將政策連結至連接器,請按照下列步驟操作:
- 在 Google Cloud 控制台中,依序點選「Security」>「Settings」。
- 在「構件防護」資訊卡中,按一下「管理設定」。
- 在「連接器」表格中,按一下連接器旁的 ,然後選取「新增政策」。
- 按照步驟建立或更新構件防護政策。詳情請參閱「建立政策」。
gcloud CLI
如要使用 gcloud CLI 查看現有連結器並更新其政策關聯,請使用下列指令:
可列出連接器
gcloud alpha scc artifact-guard connectors list PARENT
更改下列內容:
- PARENT:機構或專案。父項資源可接受的格式包括:
organizations/ORGANIZATION_ID/locations/LOCATIONprojects/PROJECT_NUMBER/locations/LOCATION
描述連接器
gcloud alpha scc artifact-guard connectors describe CONNECTOR_ID \ --location=LOCATION \ (--organization=ORGANIZATION_ID | --project=PROJECT_NUMBER)
更新連接器政策關聯
如要將連接器連結至政策,請在政策定義檔案的管道範圍中加入連接器 ID,並使用 gcloud alpha scc artifact-guard policies update 指令更新政策。詳情請參閱「建立政策」。
刪除連接器
控制台
如要使用 Google Cloud 控制台刪除連接器,請按照下列步驟操作:
- 在 Google Cloud 控制台中,依序點選「Security」>「Settings」。
- 在「構件防護」資訊卡中,按一下「管理設定」。
- 在「連接器」表格中,按一下連接器旁邊的 ,然後選取「刪除連接器」。
- 按照確認提示刪除連接器。按一下「取消」即可中止。
gcloud CLI
如要使用 gcloud CLI 刪除連接器,請執行下列指令:
gcloud alpha scc artifact-guard connectors delete CONNECTOR_ID \ --location=LOCATION \ (--organization=ORGANIZATION_ID | --project=PROJECT_NUMBER)
執行評估作業
GitHub Actions 和 Jenkins 管道支援安全漏洞掃描。 如要執行評估,請完成下列步驟:
密鑰設定
在 Google Cloud 外部執行的 CI/CD 管道可以使用服務帳戶金鑰或 Workload Identity Federation 進行驗證。如需建立密鑰的詳細操作說明,請參閱下列文章:
服務帳戶金鑰
Workload Identity Federation (適用於 GitHub Actions)
在 Google Cloud中設定 OpenID Connect
您必須使用下列其中一種方法,將密鑰新增至 CI/CD 環境:
服務帳戶金鑰方法
一個密鑰:
GCP_CREDENTIALS:您下載的服務帳戶 JSON 金鑰檔案內容。
Workload Identity Federation 方法
兩個密鑰:
GCP_WORKLOAD_IDENTITY_PROVIDER: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 Actions (密鑰)
這個範本適用於使用私密金鑰的 GitHub Actions。
- 新增服務帳戶私密金鑰 (
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 Actions (WIF)
這個範本適用於使用 Workload Identity Federation 的 GitHub Actions。
- 在 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 專案 ID。
AR_REPOSITORY (選填)
- 指定 Artifact Registry 存放區的名稱。如果建構成功,管道會將映像檔發布至該存放區。
ORGANIZATION_ID (必要)
- Google Cloud 組織 ID。
CONNECTOR_ID (必要)
- 指定要使用的管道連接器 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 一致性:通過
- 詳細列出政策名稱。
- 僅提供依嚴重性分類的 CVE 摘要計數。
ArtifactGuard 一致性:失敗
- 詳細說明失敗原因。
- 只列出導致失敗的特定 CVE。
- 提供按嚴重程度分類的 CVE 摘要計數。
高詳細程度 (詳細)
提供發現的所有安全漏洞完整清單。
ArtifactGuard 一致性:通過
- 提供政策偵測到的所有 CVE 清單。
- 提供依嚴重性分類的 CVE 摘要計數。
- 提供偵測到的所有安全漏洞完整清單。
ArtifactGuard 一致性:失敗
- 包括失敗原因。
- 列出導致失敗的 CVE。
- 提供政策偵測到的所有 CVE 清單。
- 提供依嚴重性分類的 CVE 摘要計數。
- 提供偵測到的所有安全漏洞完整清單。
IGNORE_SERVER_ERRORS (選填)
- 選用布林值旗標。如果設為
true,即使發生伺服器錯誤,管道仍會繼續運作。預設值為false。
啟動評估
在建構程序中,以 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=$?
持續整合/持續推送軟體更新整合會將 Docker 容器的結束代碼傳播至 Jenkins 或 GitHub Actions 執行階段,然後判斷管道的通過或失敗狀態。
疑難排解
本節將列出常見錯誤,並說明如何解決。
CreateConnector 失敗
| 欄位 | 必要/選用 | 限制 |
|---|---|---|
name |
必填 | 格式:必須符合規則運算式 [a-zA-Z0-9\\-\\s_]+$ 符合一或多個下列項目:
長度上限:64 個半形字元。 |
pipeline_type |
必填 | 必須是下列其中一個列舉值:
|
description |
選用 | 不得超過 256 個字元。 |
display_name |
選用 | 不得超過 256 個字元。 |
其他錯誤
下表列出一些常見錯誤和解決方法。
| 錯誤訊息 | 原因 | 具體行動/解決方式 |
|---|---|---|
資源「artifactscanguard.connectors.create」的權限遭拒 |
使用者或服務帳戶缺少資源 (專案、資料夾或機構) 的 artifactscanguard.connectors.create IAM 權限。 |
授予呼叫端包含 artifactscanguard.connectors.create 權限的 IAM 角色。 |
status.ErrFailedPrecondition |
即使 Google Cloud 控制台 顯示服務已啟用,上線程序可能仍在進行中。 | 向支援團隊回報問題。 |
status.ErrInvalidArgument |
欄位驗證失敗 | 確認 CreateConnector 要求符合指定限制。 |