通過二進制授權保護您的GKE部署

Google Kubernetes Engine及其底層容器模型為雲中託管的應用程序提供了增強的可伸縮性和可管理性。根據系統的運行時需求,啟動靈活的軟件應用程序比以往任何時候都容易。

但是,這種靈活性可能會帶來新的挑戰。在這樣的環境中,可能難以確保根據您的最佳實踐和標準來構建,測試和發布每個組件,並且僅將授權軟件部署到您的生產環境中。

二進制授權(BinAuthz)是一項服務,旨在通過向Kubernetes Engine集群添加部署時策略實施來減少這些擔憂。可以編寫策略以要求一個或多個受信任方(稱為“證明人”)在部署映像之前批准該映像。對於映像從開發到測試再到生產集群的多階段部署管道,可以使用證明者來確保在軟件進入下一階段之前已完成所有必需的過程。

使用加密的公鑰建立並驗證證明人的身份,並使用相應的私鑰對證明進行數字簽名。這樣可以確保只有受信任方才能授權在您的環境中部署軟件。

在部署時,“二進制授權”通過檢查容器映像是否已通過所有必需的約束(包括所有必需的證明者均已驗證映像已準備就緒)來實施您定義的策略。如果映像通過,則該服務允許對其進行部署。否則,部署將被阻止,並且映像必須經過兼容才能部署。

866ef6a5bf86cf5.png

你會建立什麼

本代碼實驗室描述瞭如何使用二進制授權來保護GKE集群。為此,您將創建一個所有部署都必須遵守的策略,並將其應用於集群。作為策略創建的一部分,您將創建一個證明者,該證明者可以驗證容器映像,並使用它來簽名和運行自定義映像。

本代碼實驗室的目的是簡要概述容器簽名與二進制授權一起工作的方式。有了這些知識,您就可以輕鬆建立由受信任的證明者保護的安全CI / CD管道。

什麼,你會LEA RN

  • 如何在GKE群集上啟用二進制授權
  • 如何定義二進制授權策略
  • 如何創建證明人並將其與策略關聯
  • 如何將圖像作為證明人簽名

您需要什麼

由於二進制授權關係到您的基礎架構的安全性,因此通常由具有不同職責的多個人進行交互。在此代碼實驗室中,您將充當所有人。在開始之前,重要的是要解釋您將要扮演的不同角色:

4426da76922fea23.png部署者

  • 此人/進程負責在集群上運行代碼。
  • 他們並不特別關注如何執行安全保證,這是別人的工作。
  • 可能是軟件工程師或自動化管道。

5b1748abb8d8b699.png策略創建者:

  • 此人負責組織的總體安全策略。
  • 他們的工作是製作容器運行之前必須通過的規則清單。
  • 他們負責建立信任鏈,包括誰需要簽署圖片才能被認為是安全的。
  • 他們不一定關心如何遵守規則的技術細節。他們甚至可能不知道容器中的軟件會做什麼。他們只是知道建立信任之前需要做什麼。

dca98cc118cd9139.png證明人

  • 這個人/過程負責系統信任鏈中的一個鏈接。
  • 他們持有一個加密密鑰,並在通過批准過程後對圖像進行簽名。
  • 在策略創建者以高層抽象方式確定策略的同時,證明人負責具體實施策略的某些方面。
  • 可能是真實的人,例如QA測試人員或經理,或者可能是CI系統中的機器人。
  • 系統的安全性取決於它們的可信賴性,因此保持其私鑰的安全非常重要。

這些角色中的每一個都可以代表組織中的個人或團隊。在生產環境中,這些角色很可能由單獨的Google Cloud Platform(GCP)項目管理,並且可以使用Cloud IAM以有限的方式在它們之間共享對資源的訪問。

a37eb2ed54b9c2eb.png

作為部署者:

搭建環境

可以使用Google Cloud Shell通過您的Web瀏覽器完成此代碼實驗室。單擊以下鏈接打開一個新會話:

開啟Google Cloud Shell

設置項目

我們的第一步是設置要在其下運行代碼實驗室的GCP項目。您可以使用以下命令在您的帳戶下找到項目列表:

gcloud projects list

當您知道要使用哪個項目時,請在環境變量中進行設置,以便將其用於其餘的代碼實驗室:

PROJECT_ID=<YOUR_CHOSEN_PROJECT_ID>
gcloud config set project $PROJECT_ID

創建工作目錄

在本代碼實驗室的整個過程中,您將創建一些配置文件。您可能要創建一個新目錄來進行以下工作:

mkdir binauthz-codelab ; cd binauthz-codelab

啟用API

使用二進制授權之前,必須在GCP項目上啟用相關的API:

//enable GKE to create and manage your cluster
gcloud services enable container.googleapis.com
//enable BinAuthz to manage a policy on the cluster
gcloud services enable binaryauthorization.googleapis.com
//enable KMS to manage cryptographic signing keys
gcloud services enable cloudkms.googleapis.com

或者,您可以通過Google Cloud Platform API庫為您的項目啟用API

設置集群

接下來,通過Kubernetes Engine為您的項目設置一個Kubernetes集群。以下命令將在啟用二進制授權的us-central1-a區域中創建一個名為“ binauthz-codelab”的新集群:

gcloud beta container clusters create \
    --enable-binauthz \
    --zone us-central1-a \
    binauthz-codelab

創建集群後,將其添加到本地環境中,以便您可以使用kubectl在本地與之交互:

gcloud container clusters get-credentials binauthz-codelab --zone us-central1-a

運行一個豆莢

現在,讓我們向新集群添加一個容器。以下命令將創建一個可以使用的簡單Dockerfile:

cat << EOF > Dockerfile
   FROM alpine
   CMD tail -f /dev/null
EOF

除了運行“ tail -f / dev / null”命令外,該容器將什麼也不做,這將使其永遠等待。它不是一個特別有用的容器,但是它將允許您測試群集的安全性。

構建容器並將其推送到Google Container Registry(GCR)

#set the GCR path you will use to host the container image
CONTAINER_PATH=us.gcr.io/${PROJECT_ID}/hello-world

#build container
docker build -t $CONTAINER_PATH ./

#push to GCR
gcloud auth configure-docker --quiet
docker push $CONTAINER_PATH

現在,您應該能夠在Container Registry Web界面中看到新創建的容器。

8d95f439df5fedb2.png

現在,在您的集群上運行容器:

kubectl create deployment hello-world --image=$CONTAINER_PATH

如果一切正常,則您的容器應以靜默方式運行。

您可以通過列出正在運行的Pod來驗證這一點:

kubectl get pods

a1724f9d39373710.png

作為策略創建者:

新增政策

現在,您已經建立了一個集群並運行您的代碼。現在,使用策略保護群集。

第一步是創建一個策略文件:

cat > ./policy.yaml << EOM
    globalPolicyEvaluationMode: ENABLE
    defaultAdmissionRule:
      evaluationMode: ALWAYS_DENY
      enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
EOM

這項政策相對簡單。 globalPolicyEvaluationMode行聲明此策略擴展了Google定義的全局策略。這允許所有正式的GKE容器默認運行。此外,該策略還聲明了defaultAdmissionRule ,該狀態規定所有其他pod都將被拒絕。准入規則包括一個ImplementationMode行,該行指出應禁止所有不符合此規則的Pod在群集上運行。

有關如何構建更複雜的策略的說明,請查閱 二進制授權文檔

ce424657bce1501f.png

現在,您可以將策略應用於您的項目:

gcloud container binauthz policy import policy.yaml

或者,也可以通過Google Cloud Console UI設置策略。

作為部署者:

測試政策

您的新策略應防止在群集上部署任何自定義容器映像。您可以通過刪除pod並嘗試再次運行它來驗證這一點:

kubectl delete deployment --all
kubectl delete event --all
kubectl create deployment hello-world --image=$CONTAINER_PATH

如果檢查群集中的Pod,則應注意這次沒有Pod在運行:

kubectl get pods

您可能需要再次運行該命令才能看到吊艙消失。 kubectl對照策略檢查了吊艙,發現它不符合規則,因此拒絕了。

您可以看到拒絕被列為kubectl事件:

kubectl get event --template \
  '{{range.items}}{{"\033[0;36m"}}{{.reason}}:{{"\033[0m"}}{{.message}}{{"\n"}}{{end}}'

d57096ad40933ded.png

二進制授權中的證明者是在Cloud Container Analysis API的基礎上實現的,因此在繼續之前描述它的工作原理非常重要。容器分析API旨在允許您將元數據與特定的容器圖像相關聯。

例如,可能會創建一個註釋來跟踪Heartbleed漏洞。然後,安全供應商將創建掃描程序以測試容器圖像中的漏洞,並創建與每個受感染容器相關的事件。

208aa5ebc53ff2b3.png

除跟踪漏洞外,容器分析還被設計為通用的元數據API。二進制授權利用容器分析將簽名與它們正在驗證的容器圖像相關聯**。**容器分析註釋用於表示單個證明者,並且出現次數與證明者已批准的每個容器相關聯。

二進制授權API使用“證明人”和“證明”的概念,但是這些是使用Container Analysis API中的相應註釋和出現來實現的。

63a701bd0057ea17.png

當前,集群將對所有不在官方存儲庫中的映像執行全面拒絕。下一步是創建證明者,以便可以有選擇地允許使用受信任的容器。

作為證明人:

創建容器分析註釋

36f8f5ade32507f7.png

首先創建一個JSON文件,其中包含Note的必要數據。此命令將在本地創建一個包含您的Note的JSON文件:

cat > ./create_note_request.json << EOM
{
  "attestation": {
    "hint": {
      "human_readable_name": "This note represents an attestation authority"
    }
  }
}
EOM

現在,使用Container Analysis API將註釋提交到您的項目:

NOTE_ID=my-attestor-note

curl -vvv -X POST \
    -H "Content-Type: application/json"  \
    -H "Authorization: Bearer $(gcloud auth print-access-token)"  \
    --data-binary @./create_note_request.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}"

在二進制授權中創建證明人

af0267ab7f7757f9.png

您的註釋現在保存在Container Analysis API中。要使用您的證明人,您還必須在二進制授權中註冊註釋:

ATTESTOR_ID=my-binauthz-attestor

gcloud container binauthz attestors create $ATTESTOR_ID \
    --attestation-authority-note=$NOTE_ID \
    --attestation-authority-note-project=${PROJECT_ID}

要驗證一切正常,請打印出註冊機構的列表:

gcloud container binauthz attestors list

9ef5aba66d1b06d3.png

您還應該能夠通過Google Cloud Console UI看到新的證明人。

添加IAM角色

在使用此證明者之前,必須授予“二進制授權”適當的權限,以查看您創建的“容器分析註釋”。這將允許二進制授權查詢Container Analysis API,以確保每個Pod已簽名並被批准運行。

二進制授權中的權限是通過自動生成的服務帳戶來處理的。

首先,找到服務帳戶的電子郵件地址:

PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}"  --format="value(projectNumber)")
BINAUTHZ_SA_EMAIL="service-${PROJECT_NUMBER}@gcp-sa-binaryauthorization.iam.gserviceaccount.com"

現在,使用它來創建一個容器分析IAM JSON請求:

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密鑰

1e3af7c177f7a311.png

在使用此證明者之前,您的權限需要創建可用於對容器圖像進行簽名的加密密鑰對。這可以通過Google Cloud Key Management Service(KMS)來完成

首先,添加一些環境變量來描述新密鑰

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 Console的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

c5ad61fbf14f1885.png

請注意,可以為每個授權機構註冊多個密鑰。如果授權機構代表一個團隊,這可能會很有用。例如,質量檢查團隊中的任何人都可以充當質量檢查證明人,並使用自己的私鑰簽名。

作為證明人:

現在您已經建立了權限並可以使用,可以使用它來對以前構建的容器映像進行簽名。

創建簽名證明

858d7e6feeb6f159.png

證明必須包含加密簽名,以表明證明者已驗證了特定的容器映像,並且可以在您的群集上安全地運行。要指定要證明的容器映像,您需要確定其摘要。您可以通過運行以下命令找到容器註冊表中託管的特定容器標記的摘要:

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}

現在,當您嘗試運行該容器映像時,二進制授權將能夠確定該映像已由證明者簽名並驗證,並且可以安全運行

現在,您已經由證明者安全地驗證了圖像,讓我們使其在群集上運行。

作為策略創建者:

更新政策

當前,您的集群運行的策略只有一個規則:允許來自官方存儲庫的容器,而拒絕所有其他容器。

更改它以允許證明者驗證的任何圖像:

cat << EOF > updated_policy.yaml
    globalPolicyEvaluationMode: ENABLE
    defaultAdmissionRule:
      evaluationMode: REQUIRE_ATTESTATION
      enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
      requireAttestationsBy:
      - projects/${PROJECT_ID}/attestors/${ATTESTOR_ID}
EOF

現在,您應該在磁盤上有一個名為updated_policy.yaml的新文件。現在,它取代默認規則拒絕所有圖像,而是首先檢查您的證明者以進行驗證。

822240fc0b02408e.png

將新策略上傳到二進制授權:

gcloud container binauthz policy import updated_policy.yaml

作為部署者:

運行已驗證的圖像

接下來,您將運行簽名的圖像,並使用以下命令驗證Pod正在運行:

kubectl create deployment hello-world-signed --image="${CONTAINER_PATH}@${DIGEST}"

現在檢查您的Pod是否正在運行:

kubectl get pods

您應該看到您的pod已通過該策略並且正在集群上運行。

恭喜你!現在,您可以通過向策略添加更複雜的規則來為群集提供特定的安全保證。

刪除集群:

gcloud container clusters delete binauthz-codelab --zone us-central1-a

刪除容器映像:

gcloud container images delete $CONTAINER_PATH@$DIGEST --force-delete-tags

刪除證明人:

gcloud container binauthz attestors delete my-binauthz-attestor

刪除容器分析資源:

curl -vvv -X DELETE  \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/${NOTE_ID}"