緩解安全性事件


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

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

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

偵測事件

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

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

您應在匯總記錄和指標的位置產生快訊。舉例來說,您可以搭配使用 GKE Audit Logging 和 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

後續步驟