返回文章列表

Kubernetes 安全性評估與滲透測試

深入探討 Kubernetes 叢集安全性評估方法論與滲透測試技術,涵蓋攻擊面分析、身份驗證機制弱點、etcd 資料儲存安全、網路暴露風險評估,以及企業級防禦策略與加固實踐指南。

資安 容器技術

Kubernetes 作為現代雲端原生應用程式的核心基礎設施,其安全性直接影響整個組織的資訊安全態勢。隨著越來越多的企業將關鍵業務系統遷移到 Kubernetes 平台,針對這個複雜系統的安全性評估和滲透測試變得至關重要。與傳統的網路滲透測試不同,Kubernetes 環境的安全評估需要深入理解其分散式架構、身份驗證機制、授權模型,以及各元件之間的信任關係。

根據資安研究機構 Atredis Partners 的研究報告,當 Kubernetes 叢集按照官方文件的最佳實踐進行部署時,攻擊者很難找到可行的攻擊向量。這是因為 Kubernetes 的設計從一開始就考慮了安全性:各個網路服務都受到適當的身份驗證和授權機制保護,避免了傳統系統常見的弱密碼或預設密碼問題;細粒度的授權控制可以在憑證洩露時降低未授權存取的風險;後端資料儲存使用 TLS 進行保護,確保傳輸中的資料被加密。

然而,這並不意味著 Kubernetes 環境是無懈可擊的。實際部署中的錯誤配置、過度寬鬆的權限設定、未經加固的元件,以及第三方工具的引入,都可能為攻擊者提供可乘之機。本文將從安全評估人員和滲透測試人員的角度,系統性地探討 Kubernetes 的攻擊面、常見弱點,以及相應的防禦措施。透過建立完整的方法論和實務技術,協助組織有效評估和提升其 Kubernetes 叢集的安全性。

Kubernetes 安全評估方法論

進行 Kubernetes 安全性評估需要一套系統化的方法論,這套方法論必須涵蓋從資訊蒐集到漏洞利用的完整流程。與傳統網路滲透測試相比,Kubernetes 環境的評估需要特別關注其獨特的架構特性和安全機制。

Kubernetes 安全評估的核心方法論包含四個主要階段。第一階段是識別暴露的網路服務,包括 kube-apiserver、kubelet、etcd 等關鍵元件。這些服務可能因為配置錯誤而暴露在不應該存取的網路區段中。第二階段是識別認證憑證,包括 Bearer Tokens、TLS 憑證、ServiceAccount Tokens 等。這些憑證可能存在於配置檔案、環境變數、掛載的 Volume 中,或者可以透過其他漏洞取得。第三階段是列舉授權配置和權限,理解當前憑證所擁有的權限,並評估是否存在權限提升的可能性。第四階段是利用取得的存取權限執行惡意操作,包括敏感資訊洩露、持久化存取、橫向移動等。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

title Kubernetes 安全評估方法論流程

start

:偵察與資訊蒐集;
note right
  - 網路掃描
  - 服務識別
  - 版本偵測
end note

:識別暴露的網路服務;
if (發現 Kubernetes 服務?) then (是)
  :記錄暴露的端點;
  note right
    - kube-apiserver (6443)
    - kubelet (10250/10255)
    - etcd (2379/2380)
  end note
else (否)
  :擴展偵察範圍;
endif

:識別認證憑證;
note right
  - Bearer Tokens
  - TLS 憑證
  - ServiceAccount Tokens
  - kubeconfig 檔案
end note

if (取得有效憑證?) then (是)
  :驗證憑證有效性;
else (否)
  :嘗試匿名存取;
endif

:列舉授權配置與權限;
note right
  - RBAC 角色綁定
  - Namespace 權限
  - Cluster 權限
end note

if (存在權限提升路徑?) then (是)
  :執行權限提升;
else (否)
  :評估現有權限影響;
endif

:漏洞利用與後續滲透;
note right
  - 敏感資訊洩露
  - 持久化存取
  - 橫向移動
  - 容器逃逸
end note

:產出評估報告;

stop

@enduml

理解 Kubernetes 的架構是進行有效安全評估的基礎。一個典型的 Kubernetes 叢集由控制平面節點和工作節點組成。控制平面節點運行著叢集的管理元件,包括 kube-apiserver、kube-controller-manager、kube-scheduler 和 etcd。工作節點則運行實際的應用程式工作負載,主要元件包括 kubelet 和 kube-proxy。每個元件都有其特定的功能和潛在的攻擊面,安全評估人員需要對這些元件有深入的理解。

kube-apiserver 是整個叢集的核心入口點,所有的管理操作都必須透過它進行。它負責驗證和授權所有的 API 請求,並將叢集狀態資料持久化到 etcd 中。由於其核心地位,kube-apiserver 通常是攻擊者的首要目標。etcd 是叢集的後端資料儲存,包含所有的配置資料、Secrets、服務帳戶憑證等敏感資訊。如果攻擊者能夠直接存取 etcd,就等於擁有了叢集的完全控制權。kubelet 運行在每個節點上,負責管理該節點上的容器。它提供了一個 API,允許遠端執行命令、查看日誌等操作,如果未經適當保護,可能成為攻擊者取得節點控制權的途徑。

測試環境建置與工具準備

建立一個可控的測試環境是進行 Kubernetes 安全評估學習和實踐的基礎。在生產環境中直接進行滲透測試不僅風險高,而且可能違反法規要求。透過建立獨立的測試環境,安全評估人員可以安全地練習各種攻擊技術,並深入理解 Kubernetes 的安全機制。

kind(Kubernetes in Docker)是建立本地測試環境的理想工具。它使用 Docker 容器來運行 Kubernetes 叢集節點,每個節點都是一個獨立的容器。這種方法的優點包括快速部署、低資源需求、易於重置,以及可以輕鬆模擬多節點叢集。對於安全評估學習來說,kind 提供了一個接近真實環境但完全可控的平台。

在開始建立測試環境之前,需要準備一些基礎工具。首先是 Docker,它是運行 kind 的基礎。其次是 kubectl,這是與 Kubernetes 叢集互動的標準命令列工具。最後是 kind 本身,可以透過 Go 語言環境安裝,或者直接下載預編譯的二進位檔案。

#!/bin/bash
# kubernetes-test-env-setup.sh
# 此腳本用於建立 Kubernetes 安全測試環境
# 包含 kind、kubectl 和相關安全評估工具的安裝

# 設定顏色輸出
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'  # 無顏色

echo -e "${GREEN}開始安裝 Kubernetes 安全測試環境${NC}"

# 檢查 Docker 是否已安裝
if ! command -v docker &> /dev/null; then
    echo -e "${RED}錯誤:Docker 未安裝,請先安裝 Docker${NC}"
    exit 1
fi

# 安裝 kubectl
echo "正在安裝 kubectl..."
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/
echo -e "${GREEN}kubectl 安裝完成${NC}"

# 安裝 kind
echo "正在安裝 kind..."
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind
echo -e "${GREEN}kind 安裝完成${NC}"

# 驗證安裝
echo "驗證安裝..."
kubectl version --client
kind version

echo -e "${GREEN}測試環境基礎工具安裝完成${NC}"

建立測試叢集需要一個配置檔案來定義叢集的結構。以下是一個適合安全測試的叢集配置範例,它包含一個控制平面節點和兩個工作節點,並且暴露了一些用於測試的端口:

# kind-security-test-cluster.yaml
# 用於安全評估測試的 kind 叢集配置
# 此配置建立一個三節點叢集,並暴露相關端口供測試使用

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: security-test  # 叢集名稱
networking:
  apiServerAddress: "127.0.0.1"  # API Server 綁定地址
  apiServerPort: 6443  # API Server 端口
nodes:
# 控制平面節點配置
- role: control-plane
  kubeadmConfigPatches:
  - |
    kind: InitConfiguration
    nodeRegistration:
      kubeletExtraArgs:
        # 啟用匿名存取以便測試(生產環境不應啟用)
        anonymous-auth: "true"
  extraPortMappings:
  # 映射 API Server 端口到主機
  - containerPort: 6443
    hostPort: 6443
    protocol: TCP
  # 映射 NodePort 範圍供服務測試
  - containerPort: 30000
    hostPort: 30000
    protocol: TCP
  - containerPort: 30001
    hostPort: 30001
    protocol: TCP

# 工作節點配置
- role: worker
  kubeadmConfigPatches:
  - |
    kind: JoinConfiguration
    nodeRegistration:
      kubeletExtraArgs:
        anonymous-auth: "true"

- role: worker
  kubeadmConfigPatches:
  - |
    kind: JoinConfiguration
    nodeRegistration:
      kubeletExtraArgs:
        anonymous-auth: "true"

使用此配置檔案建立叢集的命令如下:

# 建立測試叢集
kind create cluster --config kind-security-test-cluster.yaml

# 設定 kubectl 使用新建立的叢集
kubectl cluster-info --context kind-security-test

# 驗證叢集狀態
kubectl get nodes
kubectl get pods --all-namespaces

建立叢集後,可以使用 docker exec 命令進入節點容器進行進一步的探索和測試。這對於理解節點內部的檔案結構、運行的程序,以及各種配置檔案的位置非常有幫助:

# 進入控制平面節點
docker exec -it security-test-control-plane /bin/bash

# 在節點內部查看運行的 Kubernetes 元件
ps aux | grep kube

# 查看 kubelet 配置
cat /var/lib/kubelet/config.yaml

# 查看 API Server 的 TLS 憑證
ls -la /etc/kubernetes/pki/

# 退出節點
exit

為了進行更深入的安全測試,還需要安裝一些額外的工具。這些工具包括用於網路分析的 tcpdump、用於 etcd 操作的 etcdctl,以及各種 Kubernetes 安全評估專用工具:

# 在測試節點上安裝額外工具
docker exec -it security-test-control-plane bash -c "
apt-get update && apt-get install -y \
  tcpdump \
  net-tools \
  curl \
  jq \
  vim
"

# 下載 etcdctl 工具
ETCD_VER=v3.5.9
docker exec -it security-test-control-plane bash -c "
curl -L https://github.com/etcd-io/etcd/releases/download/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd.tar.gz
tar xzf /tmp/etcd.tar.gz -C /tmp
mv /tmp/etcd-${ETCD_VER}-linux-amd64/etcdctl /usr/local/bin/
"

身份驗證機制安全分析

Kubernetes 支援多種身份驗證機制,每種機制都有其特定的使用場景和安全考量。理解這些機制的運作方式和潛在弱點,是進行安全評估的核心技能之一。

X.509 用戶端憑證是 Kubernetes 最常用的身份驗證方式之一。叢集會設定一個憑證授權機構(CA),任何由這個 CA 簽發的憑證都會被接受。憑證中的 Common Name(CN)會被用作使用者名稱,Organization(O)欄位則會被用作群組資訊。這種身份驗證方式的優點是安全性高,但缺點是憑證一旦簽發就無法撤銷(除非重新簽發 CA 憑證),這意味著如果憑證洩露,除了等待其過期外沒有有效的處理方式。

# certificate-signing-request.yaml
# 示範如何建立憑證簽署請求(CSR)
# 此請求用於取得新的使用者憑證

apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: security-tester  # CSR 名稱
spec:
  request: |  # Base64 編碼的 CSR 內容
    LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K...
  signerName: kubernetes.io/kube-apiserver-client
  expirationSeconds: 86400  # 憑證有效期(秒)
  usages:
  - client auth  # 用於客戶端認證

Bearer Tokens 是另一種常見的身份驗證方式,包括 Static Token Files 和 ServiceAccount Tokens。Static Token Files 是在 API Server 啟動時載入的靜態 Token 清單,這種方式因為安全性問題已不建議使用。ServiceAccount Tokens 則是 Kubernetes 自動為每個 ServiceAccount 產生的 JWT 格式 Token,它們會自動掛載到 Pod 中,供應用程式與 API Server 進行互動。

從安全評估的角度來看,ServiceAccount Tokens 是重要的攻擊目標。當攻擊者能夠存取 Pod 時,通常可以在 /var/run/secrets/kubernetes.io/serviceaccount/ 目錄下找到 Token。如果這個 ServiceAccount 被授予過多的權限,攻擊者就能利用這個 Token 進行權限提升或橫向移動。

#!/bin/bash
# extract-serviceaccount-token.sh
# 示範如何從 Pod 中提取 ServiceAccount Token
# 此腳本用於安全評估,展示 Token 洩露的風險

# Token 預設掛載位置
TOKEN_PATH="/var/run/secrets/kubernetes.io/serviceaccount/token"
CA_CERT_PATH="/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
NAMESPACE_PATH="/var/run/secrets/kubernetes.io/serviceaccount/namespace"

# 讀取 Token 和相關資訊
if [ -f "$TOKEN_PATH" ]; then
    echo "發現 ServiceAccount Token"
    TOKEN=$(cat $TOKEN_PATH)
    NAMESPACE=$(cat $NAMESPACE_PATH)

    # 解碼 JWT Token 以檢視其內容
    echo "Token 內容(Payload 部分):"
    echo $TOKEN | cut -d '.' -f 2 | base64 -d 2>/dev/null | jq .

    echo ""
    echo "Namespace: $NAMESPACE"

    # 嘗試使用此 Token 呼叫 API Server
    echo ""
    echo "測試 Token 權限..."
    curl -s --cacert $CA_CERT_PATH \
         -H "Authorization: Bearer $TOKEN" \
         https://kubernetes.default.svc/api/v1/namespaces/$NAMESPACE/pods
else
    echo "未找到 ServiceAccount Token"
fi

OpenID Connect(OIDC)是企業環境中常用的身份驗證整合方式,它允許 Kubernetes 與外部身份提供者(如 Azure AD、Okta、Keycloak)進行整合。這種方式的優點是可以利用組織現有的身份管理基礎設施,實現單一登入和集中式的使用者管理。然而,OIDC 整合的配置錯誤也可能引入新的安全風險,例如過於寬鬆的群組映射或不當的 Token 有效期設定。

身份驗證繞過是安全評估中需要特別關注的問題。kube-apiserver 支援匿名存取,這意味著未經身份驗證的請求會被賦予 system:anonymous 使用者身份和 system:unauthenticated 群組。雖然預設情況下這些身份的權限非常有限,但錯誤的 RBAC 配置可能會授予它們不應該擁有的權限。在評估過程中,應該檢查是否存在對 system:anonymoussystem:unauthenticated 的不當授權。

# 檢查匿名存取權限
# 此命令列出所有綁定到匿名使用者或未認證群組的角色

kubectl get clusterrolebindings -o json | jq -r '
  .items[] |
  select(
    .subjects[]? |
    select(
      (.kind == "User" and .name == "system:anonymous") or
      (.kind == "Group" and .name == "system:unauthenticated")
    )
  ) |
  .metadata.name
'

# 檢查特定角色的權限
kubectl describe clusterrolebinding system:public-info-viewer

授權機制與權限評估

Kubernetes 的授權機制決定了經過身份驗證的請求是否被允許執行特定操作。理解這些機制的運作方式,對於評估權限配置的安全性和識別權限提升路徑至關重要。

RBAC(Role-Based Access Control)是 Kubernetes 中最主要的授權機制。它定義了四種主要資源:Role 和 ClusterRole 定義權限集合,RoleBinding 和 ClusterRoleBinding 則將這些權限授予使用者、群組或 ServiceAccount。Role 和 RoleBinding 是 Namespace 範圍的,而 ClusterRole 和 ClusterRoleBinding 則是叢集範圍的。

在進行權限評估時,需要理解 RBAC 規則的組成元素。每條規則包含 apiGroups(API 群組,如 "" 代表核心 API、“apps” 代表 Deployment 等)、resources(資源類型,如 pods、secrets、configmaps)、verbs(操作動詞,如 get、list、create、delete)。規則也可以指定特定的 resourceNames 來限制對特定資源實例的存取。

# dangerous-rbac-examples.yaml
# 示範幾種危險的 RBAC 配置
# 這些配置在安全評估中應特別注意

---
# 危險配置 1:過度寬鬆的叢集管理員權限
# 此配置授予所有資源的完全控制權
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: dangerous-admin-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin  # 授予完全控制權
subjects:
- kind: ServiceAccount
  name: monitoring-sa
  namespace: monitoring

---
# 危險配置 2:可存取 Secrets 的權限
# Secrets 可能包含敏感資訊如密碼、憑證
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "list", "watch"]  # 可讀取所有 Secrets

---
# 危險配置 3:可建立 Pod 的權限
# 可能被利用來執行任意程式碼
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: development
  name: pod-creator
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["create", "delete"]  # 可建立和刪除 Pod
- apiGroups: [""]
  resources: ["pods/exec"]
  verbs: ["create"]  # 可在 Pod 中執行命令

識別權限提升路徑是 Kubernetes 安全評估的核心任務之一。以下是一些常見的權限提升向量:

首先是 Secrets 存取權限。如果攻擊者可以讀取 Secrets,就可能取得其他 ServiceAccount 的 Token、資料庫密碼、API 金鑰等敏感資訊。這些資訊可以用於進一步的攻擊。

其次是 Pod 建立權限。能夠建立 Pod 的攻擊者可以透過多種方式提升權限:掛載節點檔案系統、使用特權容器、掛載 ServiceAccount Token 等。即使沒有直接的管理員權限,Pod 建立權限也可能導致叢集被完全控制。

第三是 Role/ClusterRole 修改權限。如果攻擊者可以修改 RBAC 配置,就可以直接授予自己更高的權限。

#!/bin/bash
# rbac-audit.sh
# RBAC 權限審計腳本
# 識別危險的權限配置

echo "===== RBAC 安全審計 ====="
echo ""

# 檢查具有 cluster-admin 權限的綁定
echo "[!] 具有 cluster-admin 權限的主體:"
kubectl get clusterrolebindings -o json | jq -r '
  .items[] |
  select(.roleRef.name == "cluster-admin") |
  "  - " + .metadata.name + ": " +
  (.subjects[]? | .kind + "/" + .name + " (" + (.namespace // "cluster-wide") + ")")
'

echo ""

# 檢查可存取 Secrets 的角色
echo "[!] 可存取 Secrets 的角色:"
kubectl get roles,clusterroles -A -o json | jq -r '
  .items[] |
  select(.rules[]?.resources[]? == "secrets") |
  "  - " + .kind + "/" + .metadata.name +
  " (namespace: " + (.metadata.namespace // "cluster-wide") + ")"
'

echo ""

# 檢查可建立 Pod 的角色
echo "[!] 可建立 Pod 的角色:"
kubectl get roles,clusterroles -A -o json | jq -r '
  .items[] |
  select(
    .rules[]? |
    select(.resources[]? == "pods") |
    select(.verbs[]? == "create" or .verbs[]? == "*")
  ) |
  "  - " + .kind + "/" + .metadata.name
'

echo ""

# 檢查可修改 RBAC 的角色
echo "[!] 可修改 RBAC 配置的角色:"
kubectl get clusterroles -o json | jq -r '
  .items[] |
  select(
    .rules[]? |
    select(.apiGroups[]? == "rbac.authorization.k8s.io") |
    select(.verbs[]? == "create" or .verbs[]? == "update" or .verbs[]? == "*")
  ) |
  "  - " + .metadata.name
'

網路暴露與攻擊面分析

Kubernetes 叢集中的各個元件會透過網路提供服務,這些網路服務的暴露情況直接決定了攻擊者可以接觸到的攻擊面大小。從安全評估的角度,需要全面了解哪些服務被暴露、暴露給誰、以及存取這些服務需要什麼樣的憑證。

控制平面節點上運行著幾個關鍵的網路服務。kube-apiserver 是最重要的服務,預設監聽 TCP 端口 6443,提供 TLS 加密的 RESTful API。這是整個叢集的管理入口,對它的存取受到身份驗證和授權機制的保護。在某些配置中,kube-apiserver 還會監聽一個「不安全」的端口(預設 8080),這個端口不需要身份驗證,但通常只綁定到 localhost。值得注意的是,這個不安全端口已在 Kubernetes 1.20 版本中被棄用,並在後續版本中移除。

etcd 是 Kubernetes 的後端資料儲存,預設監聽 TCP 端口 2379(用戶端通訊)和 2380(節點間通訊)。etcd 儲存了所有叢集資料,包括 Secrets、ConfigMaps、RBAC 配置等。如果攻擊者能夠直接存取 etcd,就等於擁有了對叢集的完全控制權。因此,etcd 通常應該只允許 kube-apiserver 存取,並使用 TLS 憑證進行雙向認證。

kube-controller-manager 和 kube-scheduler 也在控制平面上運行,它們提供健康檢查端點和 metrics 端點。這些服務的預設配置是只綁定到 localhost,但錯誤的配置可能會將它們暴露到網路上。

@startuml
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

title Kubernetes 網路暴露與攻擊面

package "外部網路" {
  actor "攻擊者" as Attacker
}

package "內部網路" {
  package "控制平面節點" {
    component "kube-apiserver\n:6443" as API
    component "etcd\n:2379/:2380" as ETCD
    component "kube-controller-manager\n:10257" as CM
    component "kube-scheduler\n:10259" as SCHED
  }

  package "工作節點" {
    component "kubelet\n:10250/:10255" as KUBELET
    component "kube-proxy\n:10249" as PROXY
    component "應用 Pod" as PODS
  }
}

Attacker --> API : TLS + Auth
note on link
  主要攻擊目標
  需要有效憑證
API --> ETCD : TLS mTLS
note on link
  儲存所有叢集資料
  應嚴格限制存取
API --> KUBELET : TLS
note on link
  可執行 Pod 命令
  可讀取 Pod 日誌
KUBELET --> PODS : 管理

Attacker ..> KUBELET : 若暴露且未認證
note on link
  高風險!
  可直接執行命令
Attacker ..> ETCD : 若暴露
note on link
  極高風險!
  等同叢集 root
@enduml

工作節點上的 kubelet 是另一個重要的攻擊面。kubelet 預設監聽 TCP 端口 10250(HTTPS)和 10255(HTTP,唯讀)。端口 10250 提供完整的 kubelet API,包括在容器中執行命令的能力。如果這個端口未經適當保護就暴露到網路上,攻擊者可以直接在節點上的任何容器中執行任意命令。端口 10255 是唯讀端口,可以用於獲取節點資訊和 Pod 資訊,雖然不能執行命令,但洩露的資訊可能對攻擊者有價值。

kubelet 的身份驗證配置由幾個重要參數控制:--anonymous-auth 控制是否允許匿名存取,預設為 true;--client-ca-file 用於啟用 TLS 用戶端憑證認證;--authentication-token-webhook 用於啟用 Bearer Token 認證。如果 --anonymous-auth 設為 true 且沒有配置其他認證機制,kubelet API 就會完全開放。

#!/bin/bash
# kubelet-security-check.sh
# kubelet 安全配置檢查腳本
# 評估 kubelet 的身份驗證和授權設定

KUBELET_CONFIG="/var/lib/kubelet/config.yaml"

echo "===== Kubelet 安全配置檢查 ====="
echo ""

# 檢查配置檔案是否存在
if [ ! -f "$KUBELET_CONFIG" ]; then
    echo "錯誤:找不到 kubelet 配置檔案"
    exit 1
fi

# 檢查匿名存取設定
ANON_AUTH=$(grep -A 2 "authentication:" $KUBELET_CONFIG | grep "anonymous:" -A 1 | grep "enabled:" | awk '{print $2}')
if [ "$ANON_AUTH" == "true" ]; then
    echo "[警告] 匿名存取已啟用"
else
    echo "[良好] 匿名存取已停用"
fi

# 檢查 Webhook 認證
WEBHOOK_AUTH=$(grep -A 5 "authentication:" $KUBELET_CONFIG | grep "webhook:" -A 1 | grep "enabled:" | awk '{print $2}')
if [ "$WEBHOOK_AUTH" == "true" ]; then
    echo "[良好] Webhook 認證已啟用"
else
    echo "[警告] Webhook 認證未啟用"
fi

# 檢查授權模式
AUTH_MODE=$(grep "authorization:" -A 2 $KUBELET_CONFIG | grep "mode:" | awk '{print $2}')
echo "[資訊] 授權模式: $AUTH_MODE"
if [ "$AUTH_MODE" == "Webhook" ]; then
    echo "  - Webhook 模式:由 API Server 進行授權檢查"
elif [ "$AUTH_MODE" == "AlwaysAllow" ]; then
    echo "  [警告] AlwaysAllow 模式:所有請求都被允許"
fi

# 檢查 TLS 配置
TLS_CERT=$(grep "tlsCertFile:" $KUBELET_CONFIG | awk '{print $2}')
TLS_KEY=$(grep "tlsPrivateKeyFile:" $KUBELET_CONFIG | awk '{print $2}')
if [ -n "$TLS_CERT" ] && [ -n "$TLS_KEY" ]; then
    echo "[良好] TLS 已配置"
    echo "  - 憑證: $TLS_CERT"
    echo "  - 私鑰: $TLS_KEY"
else
    echo "[警告] TLS 未配置"
fi

# 檢查唯讀端口
READONLY_PORT=$(grep "readOnlyPort:" $KUBELET_CONFIG | awk '{print $2}')
if [ "$READONLY_PORT" == "0" ]; then
    echo "[良好] 唯讀端口已停用"
else
    echo "[警告] 唯讀端口已啟用: $READONLY_PORT"
fi

kubectl 命令列工具提供了 proxyport-forward 命令,這些命令可能會意外地將服務暴露到網路上。kubectl proxy 會在本地啟動一個 HTTP 代理,將請求轉發到 kube-apiserver,而且不需要額外的身份驗證。如果這個代理綁定到非 localhost 的地址,就會成為一個未經認證的叢集入口點。類似地,kubectl port-forward 可以將叢集內的服務暴露到本地端口,如果綁定地址設定不當,也可能造成安全風險。

etcd 攻擊面深入分析

etcd 作為 Kubernetes 的後端資料儲存,包含了叢集的所有狀態資料,包括 Secrets、ConfigMaps、ServiceAccount Tokens、RBAC 配置等。從攻擊者的角度來看,直接存取 etcd 等同於擁有叢集的完全控制權,因此 etcd 的安全性需要特別重視。

在標準的 Kubernetes 部署中,etcd 應該只允許 kube-apiserver 存取,並使用 TLS 憑證進行雙向認證。kube-apiserver 使用專門的用戶端憑證與 etcd 通訊,這些憑證通常存放在 /etc/kubernetes/pki/apiserver-etcd-client.crt/etc/kubernetes/pki/apiserver-etcd-client.key。如果攻擊者能夠取得這些憑證,就可以直接連接到 etcd。

識別 etcd 端點的方法有多種。可以檢查 kube-apiserver 的啟動參數,其中會包含 etcd 的連接資訊:

# 從 kube-apiserver Pod 的配置中取得 etcd 連接資訊
kubectl get pod kube-apiserver-<node-name> -n kube-system -o yaml | \
  grep -A 5 "etcd"

# 或者直接查看 kube-apiserver 的 manifest
cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep etcd

etcdctl 是與 etcd 互動的標準命令列工具。使用 etcdctl 需要提供適當的憑證:

#!/bin/bash
# etcd-enumeration.sh
# etcd 資料列舉腳本
# 用於安全評估,展示可從 etcd 取得的敏感資訊

# 設定 etcd 連接參數
export ETCDCTL_API=3
ETCD_ENDPOINTS="https://127.0.0.1:2379"
ETCD_CACERT="/etc/kubernetes/pki/etcd/ca.crt"
ETCD_CERT="/etc/kubernetes/pki/apiserver-etcd-client.crt"
ETCD_KEY="/etc/kubernetes/pki/apiserver-etcd-client.key"

# 定義便利函數
etcd_cmd() {
    etcdctl --endpoints=$ETCD_ENDPOINTS \
            --cacert=$ETCD_CACERT \
            --cert=$ETCD_CERT \
            --key=$ETCD_KEY \
            "$@"
}

echo "===== etcd 資料列舉 ====="
echo ""

# 檢查 etcd 健康狀態
echo "[*] etcd 健康狀態:"
etcd_cmd endpoint health
echo ""

# 列出所有 key 的前綴
echo "[*] 主要資料類別:"
etcd_cmd get /registry --prefix --keys-only | \
  cut -d '/' -f 1-3 | sort | uniq -c | sort -rn | head -20
echo ""

# 列舉所有 Secrets
echo "[*] 所有 Secrets:"
etcd_cmd get /registry/secrets --prefix --keys-only | \
  sed 's|/registry/secrets/||'
echo ""

# 讀取特定 Secret(示例)
echo "[*] 讀取 default namespace 的 Secrets:"
etcd_cmd get /registry/secrets/default --prefix --keys-only
echo ""

# 列舉 ServiceAccount Tokens
echo "[*] ServiceAccount Tokens:"
etcd_cmd get /registry/secrets --prefix --keys-only | \
  grep "token"
echo ""

# 列舉 RBAC 配置
echo "[*] ClusterRoleBindings:"
etcd_cmd get /registry/clusterrolebindings --prefix --keys-only

etcd 中的資料使用 Protocol Buffers 格式序列化,這意味著直接讀取 etcd 的輸出會看到二進位資料。需要使用專門的工具來解碼這些資料。Auger 是一個開源工具,可以將 etcd 中的 Kubernetes 物件解碼為可讀的格式:

# 使用 auger 解碼 etcd 資料
# 首先從 etcd 讀取原始資料
etcd_cmd get /registry/secrets/kube-system/default-token-xxxxx --print-value-only > /tmp/secret.bin

# 使用 auger 解碼
auger decode -f /tmp/secret.bin

對於 etcd 的防禦措施,首要的是確保只有 kube-apiserver 可以存取 etcd。這可以透過網路層面的限制(如防火牆規則、Network Policy)和 TLS 用戶端憑證認證來實現。其次,應該啟用 etcd 的資料加密功能,特別是對 Secrets 進行加密。Kubernetes 支援使用 EncryptionConfiguration 來配置 Secrets 的加密:

# encryption-config.yaml
# etcd Secrets 加密配置
# 此配置啟用 AES-CBC 加密保護 Secrets

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
    - secrets  # 對 Secrets 進行加密
    providers:
    # 使用 AES-CBC 加密
    - aescbc:
        keys:
        - name: key1
          # 32 bytes 的加密金鑰(base64 編碼)
          secret: <base64-encoded-32-byte-key>
    # 允許讀取未加密的 Secrets(用於遷移)
    - identity: {}

除了加密之外,還應該定期備份 etcd 資料,並將備份存放在安全的位置。備份也應該加密,以防止備份資料洩露導致的安全問題。

防禦策略與加固實踐

在完成安全評估後,需要根據發現的問題制定和實施相應的防禦措施。以下是針對 Kubernetes 各個安全面向的加固實踐建議。

網路隔離是 Kubernetes 安全的第一道防線。應該使用 Network Policy 來限制 Pod 之間的網路通訊,只允許必要的流量。對於控制平面元件,應該將 etcd 與其他網路隔離,只允許 kube-apiserver 存取。kubelet 的 10250 端口不應該暴露給非必要的網路區段。

# deny-all-network-policy.yaml
# 預設拒絕所有流量的 Network Policy
# 這是建立零信任網路的基礎

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}  # 選擇所有 Pod
  policyTypes:
  - Ingress
  - Egress
  # 未定義任何規則,表示拒絕所有流量

---
# allow-specific-traffic.yaml
# 只允許特定流量的 Network Policy 範例

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-web-traffic
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: web-server
  policyTypes:
  - Ingress
  - Egress
  ingress:
  # 允許來自 Ingress Controller 的流量
  - from:
    - namespaceSelector:
        matchLabels:
          name: ingress-nginx
    ports:
    - protocol: TCP
      port: 8080
  egress:
  # 允許存取資料庫
  - to:
    - podSelector:
        matchLabels:
          app: database
    ports:
    - protocol: TCP
      port: 5432
  # 允許 DNS 查詢
  - to:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53

RBAC 配置應該遵循最小權限原則。避免使用 cluster-admin 等過度寬鬆的內建角色,而是建立符合實際需求的自定義角色。ServiceAccount 也應該遵循相同的原則,為每個應用程式建立專用的 ServiceAccount,並只授予必要的權限。

# minimal-rbac.yaml
# 最小權限原則的 RBAC 配置範例

---
# 自定義角色:只允許讀取 Deployment 狀態
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production
  name: deployment-viewer
rules:
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch"]  # 只有讀取權限
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]
  # 注意:不包含 pods/exec 和 pods/log

---
# 為特定 ServiceAccount 綁定角色
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: deployment-viewer-binding
  namespace: production
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: deployment-viewer
subjects:
- kind: ServiceAccount
  name: monitoring-app
  namespace: production

Pod 安全性也是重要的防禦面向。應該配置 Pod Security Standards 或使用 Pod Security Admission 來限制 Pod 的安全配置。關鍵的安全設定包括:不使用特權容器、以非 root 使用者運行、使用唯讀根檔案系統、停用服務帳戶 Token 自動掛載等。

# secure-pod.yaml
# 安全加固的 Pod 配置範例

apiVersion: v1
kind: Pod
metadata:
  name: secure-app
  namespace: production
spec:
  # 停用 ServiceAccount Token 自動掛載
  automountServiceAccountToken: false

  # 使用專用的 ServiceAccount
  serviceAccountName: secure-app-sa

  # 設定 Pod 層級的安全上下文
  securityContext:
    runAsNonRoot: true  # 強制以非 root 運行
    runAsUser: 10000  # 指定 UID
    runAsGroup: 10000  # 指定 GID
    fsGroup: 10000  # 檔案系統群組
    seccompProfile:
      type: RuntimeDefault  # 使用預設的 seccomp 設定檔

  containers:
  - name: app
    image: secure-app:latest

    # 容器層級的安全上下文
    securityContext:
      allowPrivilegeEscalation: false  # 禁止權限提升
      readOnlyRootFilesystem: true  # 唯讀根檔案系統
      capabilities:
        drop:
        - ALL  # 移除所有 Linux capabilities

    # 資源限制
    resources:
      limits:
        cpu: "500m"
        memory: "256Mi"
      requests:
        cpu: "100m"
        memory: "128Mi"

    # 使用 tmpfs 作為可寫入目錄
    volumeMounts:
    - name: tmp
      mountPath: /tmp
    - name: cache
      mountPath: /var/cache

  volumes:
  - name: tmp
    emptyDir: {}
  - name: cache
    emptyDir: {}

監控和審計是安全防禦的重要組成部分。應該啟用 Kubernetes 的審計日誌功能,記錄所有對 API Server 的請求。這些日誌可以用於偵測異常行為、事件調查和合規性報告。

# audit-policy.yaml
# Kubernetes API Server 審計策略
# 記錄敏感操作以便安全監控

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# 不記錄對健康檢查端點的請求
- level: None
  nonResourceURLs:
  - /healthz*
  - /livez*
  - /readyz*

# 不記錄對 kube-system 的 configmaps 的 watch 請求
- level: None
  resources:
  - group: ""
    resources: ["configmaps"]
  namespaces: ["kube-system"]
  verbs: ["watch"]

# 記錄對 Secrets 的所有操作,包含完整請求和回應
- level: RequestResponse
  resources:
  - group: ""
    resources: ["secrets"]

# 記錄對 RBAC 資源的修改操作
- level: RequestResponse
  resources:
  - group: "rbac.authorization.k8s.io"
    resources: ["*"]
  verbs: ["create", "update", "patch", "delete"]

# 記錄對 pods/exec 的請求
- level: RequestResponse
  resources:
  - group: ""
    resources: ["pods/exec", "pods/attach"]

# 記錄認證失敗
- level: Metadata
  omitStages:
  - RequestReceived

# 預設記錄所有其他請求的元資料
- level: Metadata

結語

Kubernetes 安全性評估與滲透測試是一個需要深入技術知識和系統化方法論的專業領域。透過本文的探討,我們從攻擊者的視角分析了 Kubernetes 的各個攻擊面,包括身份驗證機制、授權配置、網路暴露,以及 etcd 等關鍵元件的安全風險。同時,也提供了相應的防禦策略和加固實踐建議。

Kubernetes 的安全性是一個持續演進的過程。隨著新版本的發布,新的安全功能會被引入,但也可能出現新的漏洞。組織需要建立持續的安全評估機制,定期檢查叢集配置、更新安全策略、以及對新的威脅保持警覺。自動化工具可以幫助進行常規的安全檢查,但深入的滲透測試仍然需要經驗豐富的安全專業人員來執行。

值得強調的是,本文討論的技術和工具應該只在授權的環境中使用。未經授權對他人的 Kubernetes 叢集進行滲透測試是違法的行為。在進行任何安全評估之前,必須取得明確的書面授權,並確保評估活動在約定的範圍內進行。

對於希望提升 Kubernetes 安全技能的專業人員,建議從建立本地測試環境開始,逐步實踐各種攻擊和防禦技術。同時,也應該關注 Kubernetes 社群的安全公告和最佳實踐指南,了解最新的安全威脅和防護措施。透過理論學習和實務練習的結合,才能建立全面的 Kubernetes 安全評估能力,有效保護組織的雲端原生基礎設施。