保護容器建構作業

1. 簡介

ead1609267034bf7.png

軟體安全漏洞是指可能導致意外系統故障,或讓不肖人士入侵軟體的弱點。Container Analysis 提供兩種 OS 掃描功能,用於找出容器中的安全漏洞:

  • On-Demand Scanning API 可讓您透過本機電腦或在 Container Registry 或 Artifact Registry 中,手動掃描容器映像檔,檢查是否有 OS 安全漏洞。
  • Container Scanning API 可讓您自動執行 OS 安全漏洞的偵測功能,並在每次將映像檔推送至 Container Registry 或 Artifact Registry 時掃描。啟用這個 API 後,語言套件也會掃描,檢查 Go 和 Java 的安全漏洞。

On-Demand Scanning API 可讓您掃描儲存在本機電腦上,或遠端儲存在 Container Registry 或 Artifact Registry 中的映像檔。這樣一來,您就能精確控管要掃描容器安全漏洞的容器。您可以先使用隨選掃描功能掃描 CI/CD 管道中的映像檔,再決定是否要將映像檔儲存在登錄檔中。

課程內容

本研究室將說明:

  • 透過 Cloud Build 建立映像檔
  • 使用 Artifact Registry for Containers
  • 運用自動安全漏洞掃描功能
  • 設定隨選掃描
  • 在 Cloud Build 的 CICD 中新增映像檔掃描功能

2. 設定和需求

自學環境設定

  1. 登入 Google Cloud 控制台,建立新專案或重複使用現有專案。如果您還沒有 Gmail 或 Google Workspace 帳戶,請先建立帳戶

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 「專案名稱」是這項專案參與者的顯示名稱。這是 Google API 不會使用的字元字串。您隨時可以更新。
  • 所有 Google Cloud 專案的專案 ID 均不得重複,而且設定後即無法變更。Cloud 控制台會自動產生一個不重複的字串。但通常是在乎它何在在大部分的程式碼研究室中,您必須參照專案 ID (通常為 PROJECT_ID)。如果您對產生的 ID 不滿意,可以隨機產生一個 ID。或者,您也可以自行嘗試,看看是否可用。這項設定在這個步驟後即無法變更,且會在專案期間維持不變。
  • 資訊中的第三個值是專案編號,部分 API 會使用這個編號。如要進一步瞭解這三個值,請參閱說明文件
  1. 接下來,您需要在 Cloud 控制台中啟用計費功能,才能使用 Cloud 資源/API。執行本程式碼研究室時,費用應該不會太高,甚至可能不收費。如要關閉資源,以免系統產生本教學課程結束後產生的費用,您可以刪除自己建立的資源,或刪除整個專案。Google Cloud 新使用者可享有 $300 美元的免費試用期

環境設定

在 Cloud Shell 中,設定專案的專案 ID 和專案編號。分別儲存為 PROJECT_IDPROJECT_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 

3. 使用 Cloud 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"

建立並變更至工作目錄

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

建立 Cloud Build 管道

下列指令會在目錄中建立要用於自動化程序的 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: ['-']


EOF

執行持續整合管道

提交版本以供處理

gcloud builds submit

查看建構詳細資料

建構程序開始後,請在 Cloud Build 資訊主頁中查看進度。

  1. 在 Cloud 控制台中開啟 Cloud Build
  2. 按一下建構作業即可查看內容

4. 適用於容器的 Artifact Registry

建立 Artifact Registry 存放區

在這個研究室中,您將使用 Artifact Registry 儲存及掃描圖片。使用下列指令建立存放區。

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

設定 Docker,讓其在存取 Artifact Registry 時使用 gcloud 憑證。

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

更新 Cloud Build 管道

請修改建構管道,將產生的映像檔推送至 Artifact Registry

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: ['-']

# push 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']

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

執行持續整合管道

提交版本進行處理

gcloud builds submit

5. 自動安全漏洞掃描

每次將新映像檔推送至 Artifact Registry 或 Container Registry 時,系統都會自動觸發容器掃描作業。當我們發現新的安全漏洞時,就會持續更新安全漏洞資訊。在本節中,您將查看剛剛建構並推送至 Artifact Registry 的映像檔,並瞭解安全漏洞結果。

查看圖片詳細資料

上一個建構程序完成後,請在 Artifact Registry 資訊主頁中查看映像檔和安全漏洞掃描結果。

  1. 在 Cloud Console 中開啟 Artifact Registry
  2. 按一下「artifact-scanning-repo」檢視內容
  3. 點進圖片詳細資料
  4. 點選圖片的最新摘要
  5. 掃描完成後,請按一下映像檔的「安全漏洞」分頁

在「安全漏洞」分頁中,您可以查看剛剛建構的映像檔自動掃描結果。

361be7b3bf293fca.png

自動掃描功能預設為啟用。探索 Artifact Registry 設定,瞭解如何關閉/開啟自動掃描功能。

6. 隨選掃描

在某些情況下,您可能需要執行掃描,才能將映像檔推送至存放區。舉例來說,容器開發人員可能會先掃描映像檔並修正問題,再將程式碼推送至來源控管。在以下範例中,您將先在本機建構並分析圖片,再對結果採取行動。

建構映像檔

在這個步驟中,您將使用本機 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

7. 使用 Cloud Build 在 CICD 中進行掃描

為 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 檔案,用於自動化程序。在本範例中,步驟僅限於容器建構程序。不過,在實際操作中,您除了容器步驟外,還應加入應用程式專屬的操作說明和測試。

使用下列指令建立檔案。

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

執行持續整合管道

請將版本提交給系統處理,在發現「嚴重」嚴重性安全漏洞時驗證建構作業是否會中斷。

gcloud builds submit

查看建構失敗

由於映像檔含有重大安全漏洞,因此您剛提交的版本會失敗。

在「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 程序

提交建構項目進行處理,確認在未發現重大嚴重性安全漏洞的情況下,建構作業會成功。

gcloud builds submit

查看建構作業是否成功

您剛提交的版本會成功,因為更新後的映像檔不含任何重大漏洞。

Cloud Build 記錄頁面中查看建構作業是否成功

查看掃描結果

查看 Artifact Registry 中的正確映像檔

  1. 在 Cloud 控制台中開啟 Artifact Registry
  2. 按一下「artifact-scanning-repo」檢視內容
  3. 點進圖片詳細資料
  4. 點選圖片的最新摘要
  5. 按一下映像檔的「安全漏洞」分頁

8. 恭喜!

恭喜,您已完成程式碼研究室!

本文涵蓋的內容:

  • 使用 Cloud Build 建構映像檔
  • 容器專用的 Artifact Registry
  • 自動掃描安全漏洞
  • 隨選掃描
  • 使用 Cloud Build 在 CICD 中掃描

下一步:

清除所用資源

如要避免系統向您的 Google Cloud 帳戶收取本教學課程所用資源的費用,請刪除含有相關資源的專案,或者保留專案但刪除個別資源。

刪除專案

如要避免付費,最簡單的方法就是刪除您為了本教學課程建立的專案。

上次更新時間:2023 年 3 月 21 日