本文說明如何因應 Google Kubernetes Engine (GKE) 叢集和容器的潛在安全性事件,並提供常見的緩解措施。
本文適用於尋求 GKE 安全事件應變指南的資安專家。如要進一步瞭解 Google Cloud 內容中提及的常見角色和範例工作,請參閱常見的 GKE Enterprise 使用者角色和工作。
「強化叢集的安全防護」一文中的建議,有助於提升 GKE 工作負載的安全性。不過,即使已採取措施保護工作負載,仍可能發生安全事件。
偵測事件
為偵測潛在事件,建議您設定程序,收集及監控工作負載的記錄。然後根據記錄檔中偵測到的異常事件設定快訊。偵測到異常情況時,快訊會通知您的安全團隊。您的安全團隊隨後可以審查潛在事件。
您可以根據特定指標或動作自訂快訊。舉例來說,如果 GKE 節點的 CPU 使用率偏高,可能表示節點遭到入侵,用於加密貨幣挖礦。
您應在匯總記錄和指標的位置產生快訊。舉例來說,您可以搭配使用 GKE 稽核記錄和 Cloud Logging 中的以記錄為準的快訊。
如要進一步瞭解與安全性相關的查詢,請參閱「稽核記錄」說明文件。
回應安全事件
收到事件警報後,請採取行動。如果可以,請修正安全漏洞。如果您不知道安全漏洞的根本原因,或尚未準備好修正問題,請採取緩解措施。
您可能採取的緩解措施取決於事件的嚴重程度,以及您是否確定已找出問題。
本指南說明在 GKE 上執行的工作負載偵測到事件後,您可以採取的行動。您可以依嚴重程度依序採取下列措施:
- 為主機 VM 的磁碟建立快照。工作負載重新部署或刪除後,您可以使用快照對異常狀況發生時的 VM 狀態執行一些鑑識作業。
在工作負載持續執行的情況下檢查 VM。 連線至主機 VM 或工作負載容器,即可取得攻擊者行為的相關資訊。建議您先減少存取權,再檢查即時 VM。
重新部署容器。重新部署會終止受影響容器中目前執行的程序,並重新啟動這些程序。
刪除工作負載。刪除工作負載會終止受影響容器中目前執行的程序,但不會重新啟動。
以下各節將說明這些緩解措施。
事前準備
本主題中使用的方法會用到下列資訊:
- 您認為遭入侵的 Pod 名稱,或
POD_NAME
。 - 執行容器或 Pod 的主機 VM 名稱,或
NODE_NAME
。
此外,採取任何行動前,請先考慮攻擊者發現後是否會採取負面反應。攻擊者可能會決定刪除資料或破壞工作負載。如果風險過高,請考慮採取更激烈的緩解措施,例如在進一步調查前刪除工作負載。
為 VM 磁碟建立快照
建立 VM 磁碟的快照,可在重新部署或刪除工作負載後,進行鑑識調查。即使磁碟已連結到執行中的執行個體,您仍可建立快照。
如要為永久磁碟建立快照,請先找出連結至 VM 的磁碟。執行下列指令,並查看
source
欄位:gcloud compute instances describe NODE_NAME --zone COMPUTE_ZONE \ --format="flattened([disks])"
找出包含
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
。如要完成快照,請執行下列指令:
gcloud compute disks snapshot DISK_NAME
詳情請參閱 Compute Engine 說明文件中的「建立永久磁碟快照」。
檢查 VM
採取行動前,請先考量攻擊者可能擁有的存取權。如果懷疑容器遭到入侵,但擔心通知攻擊者,可以連線至容器並檢查,不會中斷工作負載。檢查功能有助於在採取更具破壞性的行動前,快速進行調查。檢查也是對工作負載干擾最少的做法,但無法停止事件。
或者,如要避免使用具備權限的憑證登入機器,您可以設定即時鑑識 (例如 GRR Rapid Response)、節點代理程式或網路篩選,藉此分析工作負載。
檢查即時 VM 前,請先減少存取權
您可以封鎖、排空及限制網路存取權,只允許存取代管遭入侵容器的 VM,藉此部分隔離遭入侵的容器,避免影響叢集中的其他容器。限制 VM 的存取權可降低風險,但如果攻擊者利用重大安全漏洞,仍可在您的環境中橫向移動。
封鎖節點,並從中排空其他工作負載
封鎖及排空節點會將與遭入侵容器共置的工作負載,移至叢集中的其他 VM。封鎖和排空可降低攻擊者影響同一節點上其他工作負載的能力。但這不一定能防止他們檢查工作負載的持續性狀態 (例如檢查容器映像檔內容)。
使用
kubectl
封鎖節點,確保沒有其他 Pod 排程到該節點上:kubectl cordon NODE_NAME
封鎖節點後,請清空節點上的其他 Pod。
為要隔離的 Pod 加上標籤:
kubectl label pods POD_NAME quarantine=true
將
POD_NAME
替換為要隔離的 Pod 名稱。從未標示
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 的節點,按照下列步驟操作:
為執行個體加上標記,以便套用新的防火牆規則。
gcloud compute instances add-tags NODE_NAME \ --zone COMPUTE_ZONE \ --tags quarantine
建立防火牆規則,拒絕來自具有
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
建立防火牆規則,拒絕所有輸入 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 位址會中斷虛擬私有雲外部的任何現有網路連線。
如要移除虛擬機的外部位址,請按照下列步驟操作:
找出並刪除將外部 IP 與 VM 建立關聯的存取設定。首先,請說明 VM,找出存取設定:
gcloud compute instances describe NODE_NAME \ --zone COMPUTE_ZONE --format="flattened([networkInterfaces])"
尋找包含
name
和natIP
的行。如下所示:networkInterfaces[0].accessConfigs[0].name: ACCESS_CONFIG_NAME networkInterfaces[0].accessConfigs[0].natIP: EXTERNAL_IP_ADDRESS
找出與要移除的外部 IP 相符的
natIP
值。記下存取設定的名稱。如要移除外部 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。詳情請參閱 Compute Engine 說明文件中的「新增及移除 SSH 金鑰」。
為中繼 VM 新增標記。
gcloud compute instances add-tags INTERMEDIATE_NODE_NAME \ --zone COMPUTE_ZONE \ --tags intermediate
新增 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
使用內部 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 stop
或 docker 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