緩解安全性事件


本文說明如何因應 Google Kubernetes Engine (GKE) 叢集和容器的潛在安全性事件,並提供常見的緩解措施。

本文適用於尋求 GKE 安全事件應變指南的資安專家。如要進一步瞭解 Google Cloud 內容中提及的常見角色和範例工作,請參閱常見的 GKE Enterprise 使用者角色和工作

強化叢集的安全防護」一文中的建議,有助於提升 GKE 工作負載的安全性。不過,即使已採取措施保護工作負載,仍可能發生安全事件。

偵測事件

為偵測潛在事件,建議您設定程序,收集及監控工作負載的記錄。然後根據記錄檔中偵測到的異常事件設定快訊。偵測到異常情況時,快訊會通知您的安全團隊。您的安全團隊隨後可以審查潛在事件。

您可以根據特定指標或動作自訂快訊。舉例來說,如果 GKE 節點的 CPU 使用率偏高,可能表示節點遭到入侵,用於加密貨幣挖礦。

您應在匯總記錄和指標的位置產生快訊。舉例來說,您可以搭配使用 GKE 稽核記錄和 Cloud Logging 中的以記錄為準的快訊

如要進一步瞭解與安全性相關的查詢,請參閱「稽核記錄」說明文件。

回應安全事件

收到事件警報後,請採取行動。如果可以,請修正安全漏洞。如果您不知道安全漏洞的根本原因,或尚未準備好修正問題,請採取緩解措施。

您可能採取的緩解措施取決於事件的嚴重程度,以及您是否確定已找出問題。

本指南說明在 GKE 上執行的工作負載偵測到事件後,您可以採取的行動。您可以依嚴重程度依序採取下列措施:

以下各節將說明這些緩解措施。

事前準備

本主題中使用的方法會用到下列資訊:

  • 您認為遭入侵的 Pod 名稱,或 POD_NAME
  • 執行容器或 Pod 的主機 VM 名稱,或 NODE_NAME

此外,採取任何行動前,請先考慮攻擊者發現後是否會採取負面反應。攻擊者可能會決定刪除資料或破壞工作負載。如果風險過高,請考慮採取更激烈的緩解措施,例如在進一步調查前刪除工作負載。

為 VM 磁碟建立快照

建立 VM 磁碟的快照,可在重新部署或刪除工作負載後,進行鑑識調查。即使磁碟已連結到執行中的執行個體,您仍可建立快照。

  1. 如要為永久磁碟建立快照,請先找出連結至 VM 的磁碟。執行下列指令,並查看 source 欄位:

    gcloud compute instances describe NODE_NAME --zone COMPUTE_ZONE \
        --format="flattened([disks])"
    
  2. 找出包含 disks[NUMBER].source 的行。輸出內容會類似以下內容:

    disks[0].source: https://www.googleapis.com/compute/v1/projects/PROJECT_NAME/zones/COMPUTE_ZONE/disks/DISK_NAME
    

    磁碟名稱是來源名稱中最後一個斜線後的部分。舉例來說,磁碟名稱為 gke-cluster-pool-1-abcdeffff-zgt8

  3. 如要完成快照,請執行下列指令:

    gcloud compute disks snapshot DISK_NAME
    

詳情請參閱 Compute Engine 說明文件中的「建立永久磁碟快照」。

檢查 VM

採取行動前,請先考量攻擊者可能擁有的存取權。如果懷疑容器遭到入侵,但擔心通知攻擊者,可以連線至容器並檢查,不會中斷工作負載。檢查功能有助於在採取更具破壞性的行動前,快速進行調查。檢查也是對工作負載干擾最少的做法,但無法停止事件。

或者,如要避免使用具備權限的憑證登入機器,您可以設定即時鑑識 (例如 GRR Rapid Response)、節點代理程式或網路篩選,藉此分析工作負載。

檢查即時 VM 前,請先減少存取權

您可以封鎖排空及限制網路存取權,只允許存取代管遭入侵容器的 VM,藉此部分隔離遭入侵的容器,避免影響叢集中的其他容器。限制 VM 的存取權可降低風險,但如果攻擊者利用重大安全漏洞,仍可在您的環境中橫向移動。

封鎖節點,並從中排空其他工作負載

封鎖及排空節點會將與遭入侵容器共置的工作負載,移至叢集中的其他 VM。封鎖和排空可降低攻擊者影響同一節點上其他工作負載的能力。但這不一定能防止他們檢查工作負載的持續性狀態 (例如檢查容器映像檔內容)。

  1. 使用 kubectl 封鎖節點,確保沒有其他 Pod 排程到該節點上:

    kubectl cordon NODE_NAME
    

    封鎖節點後,請清空節點上的其他 Pod。

  2. 為要隔離的 Pod 加上標籤:

    kubectl label pods POD_NAME quarantine=true
    

    POD_NAME 替換為要隔離的 Pod 名稱。

  3. 從未標示 quarantine 的節點排空 Pod:

    kubectl drain NODE_NAME --pod-selector='!quarantine'
    

限制節點的網路存取權

建議您封鎖內部和外部流量,禁止存取主機 VM。接著,允許網路或虛擬私有雲中的特定 VM 連線至隔離的 VM。

第一步是從擁有該 VM 的代管執行個體群組中捨棄 VM。放棄 VM 可避免節點在調查完成前標示為不良,並自動修復 (重新建立)。

如要捨棄 VM,請執行下列指令:

gcloud compute instance-groups managed abandon-instances INSTANCE_GROUP_NAME \
    --instances=NODE_NAME

為 VM 設定防火牆

在受影響的容器和同一網路中的其他工作負載之間建立防火牆,有助於防止攻擊者在您進一步分析時,轉移到環境的其他部分。由於您已排空 VM 中的其他容器,因此這項作業只會影響隔離的容器。

按照下列 VM 防火牆設定說明操作,可避免發生下列情況:

  • 的輸出連線,使用輸出規則連線至叢集中的其他 VM。
  • 使用輸入規則連入遭入侵的 VM。

如要透過防火牆將 VM 與其他執行個體隔離,請針對代管要隔離 Pod 的節點,按照下列步驟操作:

  1. 為執行個體加上標記,以便套用新的防火牆規則。

    gcloud compute instances add-tags NODE_NAME \
        --zone COMPUTE_ZONE \
        --tags quarantine
    
  2. 建立防火牆規則,拒絕來自具有 quarantine 標記執行個體的所有輸出 TCP 流量:

    gcloud compute firewall-rules create quarantine-egress-deny \
        --network NETWORK_NAME \
        --action deny \
        --direction egress \
        --rules tcp \
        --destination-ranges 0.0.0.0/0 \
        --priority 0 \
        --target-tags quarantine
    
  3. 建立防火牆規則,拒絕所有輸入 TCP 流量傳送到具有 quarantine 標記的執行個體。將這項輸入規則的 priority 設為 1,這樣您就能使用其他規則覆寫這項規則,允許從指定 VM 進行 SSH 連線。

    gcloud compute firewall-rules create quarantine-ingress-deny \
        --network NETWORK_NAME \
        --action deny \
        --direction ingress \
        --rules tcp \
        --source-ranges 0.0.0.0/0 \
        --priority 1 \
        --target-tags quarantine
    

移除 VM 的外部 IP 位址

移除 VM 的外部 IP 位址會中斷虛擬私有雲外部的任何現有網路連線。

如要移除虛擬機的外部位址,請按照下列步驟操作:

  1. 找出並刪除將外部 IP 與 VM 建立關聯的存取設定。首先,請說明 VM,找出存取設定:

    gcloud compute instances describe NODE_NAME \
        --zone COMPUTE_ZONE --format="flattened([networkInterfaces])"
    

    尋找包含 namenatIP 的行。如下所示:

    networkInterfaces[0].accessConfigs[0].name:              ACCESS_CONFIG_NAME
    networkInterfaces[0].accessConfigs[0].natIP:             EXTERNAL_IP_ADDRESS
    
  2. 找出與要移除的外部 IP 相符的 natIP 值。記下存取設定的名稱。

  3. 如要移除外部 IP,請執行下列指令:

    gcloud compute instances delete-access-config NODE_NAME \
        --access-config-name "ACCESS_CONFIG_NAME"
    

透過中繼 VM 透過 SSH 連線至主機 VM

移除主機 VM 的外部 IP 後,您就無法從 VPC 外部進行 SSH 連線。您可從同一個網路中的其他 VM 存取。在本節的其餘部分,我們會將此稱為中繼 VM

必要條件

  • 可存取主機 VM 子網路的中繼 VM。如果沒有,請建立 VM
  • 中繼 VM 的內部 IP 位址。
  • 中繼 VM 的 SSH 公開金鑰。詳情請參閱管理 SSH 金鑰

連線至主機 VM

  1. 將中繼 VM 的公開金鑰新增至主機 VM。詳情請參閱 Compute Engine 說明文件中的「新增及移除 SSH 金鑰」。
  2. 為中繼 VM 新增標記。

    gcloud compute instances add-tags INTERMEDIATE_NODE_NAME \
      --zone COMPUTE_ZONE \
      --tags intermediate
    
  3. 新增 Ingress 允許規則,覆寫先前新增的拒絕規則。如要新增規則,請執行下列指令。

    gcloud compute firewall-rules create quarantine-ingress-allow \
        --network NETWORK_NAME \
        --action allow \
        --direction ingress \
        --rules tcp:22 \
        --source-tags intermediate \
        --priority 0 \
        --target-tags quarantine
    

    這項規則允許來自網路中具有 intermediate 標記的 VM,透過通訊埠 22 (SSH) 傳入流量。這會以 priority 覆寫拒絕規則。 0

  4. 使用內部 IP 連線至隔離的 VM:

    ssh -i KEY_PATH USER@QUARANTINED_VM_INTERNAL_IP
    

    更改下列內容:

    • KEY_PATH:安全殼層私密金鑰的路徑。
    • USER:您 Google Cloud 帳戶的電子郵件地址。
    • QUARANTINED_VM_INTERNAL_IP:內部 IP 位址。

重新部署容器

重新部署容器後,系統會啟動容器的全新副本,並刪除遭入侵的容器。

如要重新部署容器,請刪除代管容器的 Pod。如果 Pod 由較高層級的 Kubernetes 建構體 (例如 Deployment 或 DaemonSet) 管理,刪除 Pod 會排定新的 Pod。這個 Pod 會執行新容器。

在下列情況下,重新部署是合理的做法:

  • 您已瞭解安全漏洞的原因。
  • 您認為攻擊者需要花費大量心力或時間,才能再次入侵容器。
  • 您認為容器可能很快就會再次遭到入侵,而且您不想將容器下線,因此打算將容器放在沙箱中,以限制影響範圍。

重新部署工作負載時,如果發生其他安全漏洞的可能性很高,請考慮將工作負載放在沙箱環境中,例如 GKE Sandbox。如果攻擊者再次入侵容器,沙箱機制會限制存取主機節點核心。

如要在 Kubernetes 中重新部署容器,請刪除包含該容器的 Pod:

kubectl delete pods POD_NAME --grace-period=10

如果已刪除 Pod 中的容器繼續執行,您可以刪除工作負載

如要在沙箱中重新部署容器,請按照「使用 GKE Sandbox 強化工作負載隔離」一文中的說明操作。

刪除工作負載

刪除 Deployment 或 DaemonSet 等工作負載時,所有成員 Pod 也會一併刪除。這些 Pod 內的所有容器都會停止執行。在下列情況下,刪除工作負載可能很合理:

  • 您想停止進行中的攻擊。
  • 您願意離線處理工作負載。
  • 比起應用程式正常運作時間或鑑識分析,立即停止攻擊更為重要。

如要刪除工作負載,請使用 kubectl delete CONTROLLER_TYPE。 舉例來說,如要刪除 Deployment,請執行下列指令:

kubectl delete deployments DEPLOYMENT

如果刪除工作負載後,系統並未刪除所有相關聯的 Pod 或容器,您可以使用容器執行階段的 CLI 工具 (通常是 docker),手動刪除容器。如果節點執行 containerd,請使用 crictl

Docker

如要使用 Docker 容器執行階段停止容器,可以使用 docker stopdocker kill

docker stop 會將 SIGTERM 信號傳送至根程序,藉此停止容器,並預設等待 10 秒讓程序結束。如果程序未在該時間範圍內結束,則會傳送 SIGKILL 信號。你可以使用 --time 選項指定這段寬限期。

docker stop --time TIME_IN_SECONDS CONTAINER

docker kill 是停止容器最快的方法。並立即傳送 SIGKILL 訊號。

docker kill CONTAINER

您也可以使用 docker rm -f,透過一個指令停止及移除容器:

docker rm -f CONTAINER

containerd

如果您在 GKE 中使用 containerd 執行階段,請使用 crictl 停止或移除容器。

如要在 containerd 中停止容器,請執行下列指令:

crictl stop CONTAINER

如要在 containerd 中移除容器,請執行下列指令:

crictl rm -f CONTAINER

刪除主機 VM

如果無法刪除或移除容器,可以刪除裝載受影響容器的虛擬機器。

如果 Pod 仍可見,您可以使用下列指令找出主機 VM 的名稱:

kubectl get pods --all-namespaces \
  -o=custom-columns=POD_NAME:.metadata.name,INSTANCE_NAME:.spec.nodeName \
  --field-selector=metadata.name=POD_NAME

如要刪除主機 VM,請執行下列 gcloud 指令:

gcloud compute instance-groups managed delete-instances INSTANCE_GROUP_NAME \
    --instances=NODE_NAME

從代管執行個體群組中捨棄執行個體,會使群組大小減少一個 VM。您可以使用下列指令,手動將一個執行個體加回群組:

gcloud compute instance-groups managed resize INSTANCE_GROUP_NAME \
    --size=SIZE

後續步驟