保護建構(&S)使用 Cloud Build、Artifact Registry 和 GKE 部署

1. 簡介

Container Analysis 提供適用於容器的安全漏洞掃描功能,以及中繼資料儲存空間。掃描服務會對 Artifact Registry 和 Container Registry 中的映像檔執行安全漏洞掃描,然後儲存產生的中繼資料,並透過 API 提供使用。中繼資料儲存空間可讓您儲存不同來源的資訊,包括安全漏洞掃描、Google Cloud 服務和第三方供應商。

安全漏洞掃描功能可自動或隨選進行:

  • 啟用自動掃描功能後,每當您將新映像檔推送至 Artifact Registry 或 Container Registry 時,系統就會自動執行掃描功能。如果發現新的安全漏洞,系統會持續更新安全漏洞資訊。
  • 啟用隨選掃描功能後,您必須執行指令來掃描 Artifact Registry 或 Container Registry 中的本機映像檔或映像檔。隨選掃描功能可讓您在掃描容器時靈活運用。舉例來說,您可以掃描本機建構的映像檔,並修復安全漏洞,再將該映像檔儲存在登錄檔中。掃描結果最久可維持 48 小時,而且掃描完成後不會更新安全漏洞資訊。

容器分析整合至 CI/CD 管道後,您就能依據該中繼資料製定決策。舉例來說,您可以使用二進位授權建立部署政策,僅允許從可信任的登錄檔部署符合規定的映像檔。

課程內容

  • 如何啟用自動掃描
  • 如何執行隨選掃描
  • 如何在建構管道中整合掃描功能
  • 如何簽署已核准的圖片
  • 如何使用 GKE Admission 控制器封鎖映像檔
  • 如何將 GKE 設為僅允許已簽署的映像檔

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 編輯器

本研究室專為與 Google Cloud Shell 編輯器搭配使用而設計和測試。如要存取編輯器

  1. 前往 https://console.cloud.google.com 存取您的 Google 專案。
  2. 按一下右上角的「Cloud Shell 編輯器」圖示

8560cc8d45e8c112.png

  1. 視窗底部隨即會開啟新的窗格

環境設定

在 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 

建立 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

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

建構映像檔並推送至 AR

使用 Cloud Build 建構容器,並自動推送至 Artifact Registry。記下映像檔上的 bad 標記。方便你在後續步驟中辨識該名稱。

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

查看圖片詳細資料

建構程序完成審查後,Artifact Registry 資訊主頁中的映像檔和安全漏洞結果。

  1. 在 Cloud 控制台中開啟 Artifact Registry
  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

查看輸出檔案

請花一點時間查看先前步驟 (儲存在 Scanner_id.txt 檔案) 的輸出內容。您可以在中繼資料伺服器中留意掃描結果的報表位置。

cat scan_id.txt

查看詳細掃描結果

如要查看實際掃描結果,請在輸出檔案中註明的報表位置使用 list-vulnerabilities 指令。

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

輸出內容包含映像檔中所有安全漏洞的大量資料。

標記重大問題

人類很少直接使用報表中儲存的資料。一般來說,結果會由自動化程序使用。使用以下指令查看報表詳細資料,並記錄發現任何 CRITICAL 安全漏洞

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. 建構管道掃描作業

在本節中,您將建立自動化建構管道來建構容器映像檔,然後掃描並評估結果。如果沒有發現重大安全漏洞,就會將映像檔推送至存放區。如果我們發現重大安全漏洞,版本就會失敗並結束。

為 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

查看建構作業失敗

您剛剛提交的建構作業會失敗,因為映像檔含有 CRITICAL 安全漏洞。

在「Cloud Build History」頁面中查看建構失敗情形

修正安全漏洞

更新 Dockerfile,以便使用不含 CRITICAL 安全漏洞的基本映像檔。

使用下列指令覆寫 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 History」頁面中查看建構成功

查看掃描結果

查看 Artifact Registry 中的合適映像檔

  1. 在 Cloud 控制台中開啟 Artifact Registry
  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_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 驗證者。因此,上述指令會傳回兩個驗證者:vulnz-attestorbuilt-by-cloud-build。成功建構映像檔後,Cloud Build 會自動簽署這些映像檔並建立認證。

新增 IAM 角色

您必須具備二進位授權服務帳戶的權限,才能查看認證附註。使用下列 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"

Google Cloud 控制台的 KMS 頁面中應該會顯示您的金鑰。

現在,請透過 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

建立已簽署的認證

到目前為止,您已經設定可簽署圖片的功能。使用您先前建立的驗證者簽署目前使用的容器映像檔

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}"

在「容器分析」條款中,這會建立新的出現記錄,並附加至驗證者的附註中。如要確保一切運作正常,可以列出認證

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

7. 使用 Cloud Build 簽署

您已啟用映像檔簽署功能,並使用驗證者簽署範例映像檔。實際上,您會在 CI/CD 管道等自動化程序期間套用認證。

在本節中,您會將 Cloud Build 設定為自動認證映像檔

角色

將二進位授權驗證者檢視者角色新增至 Cloud Build 服務帳戶:

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

將 Cloud KMS CryptoKey 簽署者/驗證者角色新增至 Cloud Build 服務帳戶 (以 KMS 為基礎的簽署):

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

將容器分析附註附加者角色新增至 Cloud Build 服務帳戶:

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

準備自訂建構 Cloud Build 步驟

您將在 Cloud Build 中使用自訂建構步驟來簡化認證程序。Google 提供這個「自訂建構」步驟,其中包含輔助函式來簡化流程。使用前,自訂建構步驟的程式碼必須內建於容器中,並推送至 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

執行版本

gcloud builds submit

在 Cloud Build 記錄中查看建構作業

開啟 Cloud 控制台前往 Cloud Build 記錄頁面,查看目前版本和成功執行建構步驟。

8. 許可控管政策

二進位授權是 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. 部署範例,確認您能部署任何內容
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. 開啟終端機並套用新政策,然後等待幾秒,讓變更生效
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 中的安全漏洞

在本節中,您將透過 Cloud Build 實作 CI/CD 管道來掃描映像檔,並在簽署映像檔前檢查是否有安全漏洞,藉此整合您到目前為止學到的內容。GKE 會在允許執行映像檔之前,使用二進位授權驗證映像檔含有安全漏洞掃描功能的簽章。

d5c41bb89e22fd61.png

更新 GKE 政策以要求認證

將 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 許可控制器需要瞭解要部署的確切映像檔,才能持續驗證簽章。如要完成這項作業,您需要使用映像檔摘要和簡單的標記。

取得不佳映像檔的映像檔摘要

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)')

使用 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)')

使用 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. 恭喜!

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

本文涵蓋的內容:

  • 如何啟用自動掃描
  • 如何執行隨選掃描
  • 如何在建構管道中整合掃描功能
  • 如何簽署已核准的圖片
  • 如何使用 GKE Admission 控制器封鎖映像檔
  • 如何將 GKE 設為僅允許已簽署的映像檔

下一步:

清除所用資源

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

刪除專案

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