本頁說明如何在 Google Kubernetes Engine (GKE) 叢集中停用不安全的 kubelet 唯讀埠,降低未經授權存取 kubelet 的風險,以及如何將應用程式遷移至更安全的埠。
在 Kubernetes 叢集 (包括 GKE) 中,節點上執行的 kubelet
程序會使用不安全的 10255
連接埠,提供唯讀 API。Kubernetes 不會對這個連接埠執行任何驗證或授權檢查。kubelet 會在更安全的已驗證通訊埠 10250
上提供相同的端點。
停用 kubelet 唯讀通訊埠,並將使用通訊埠 10255
的任何工作負載,改為使用更安全的通訊埠 10250
。
事前準備
開始之前,請確認你已完成下列工作:
- 啟用 Google Kubernetes Engine API。 啟用 Google Kubernetes Engine API
- 如要使用 Google Cloud CLI 執行這項工作,請安裝並初始化 gcloud CLI。如果您先前已安裝 gcloud CLI,請執行
gcloud components update
,取得最新版本。
- 確認您有現有的 Autopilot 或 Standard 叢集。如要建立新叢集,請參閱「建立 Autopilot 叢集」。
需求條件
- 只有在 GKE 1.26.4-gke.500 以上版本中,才能停用不安全的 kubelet 唯讀通訊埠。
檢查是否使用不安全的通訊埠,並遷移應用程式
停用不安全的唯讀通訊埠前,請先將使用該通訊埠的所有執行中應用程式,遷移至更安全的唯讀通訊埠。可能需要遷移的工作負載包括自訂指標管道,以及存取 kubelet 端點的工作負載。
- 如要存取節點上 kubelet API 提供的資訊 (例如指標),請使用通訊埠
10250
。 - 如果工作負載是透過節點上的 kubelet API 取得 Kubernetes 資訊 (例如列出節點上的 Pod),請改用 Kubernetes API。
檢查應用程式是否使用不安全的 kubelet 唯讀通訊埠
本節說明如何檢查叢集是否使用不安全的通訊埠。
檢查 Autopilot 模式的通訊埠用量
如要檢查 Autopilot 叢集中的通訊埠使用情形,請確保叢集中至少有一個不是 DaemonSet 的工作負載正在執行。如果您在空白的 Autopilot 叢集上執行下列步驟,結果可能無效。
將下列資訊清單儲存為
read-only-port-metrics.yaml
:apiVersion: v1 kind: Namespace metadata: name: node-metrics-printer-namespace --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: node-metrics-printer-role rules: - apiGroups: - "" resources: - nodes/metrics verbs: - get --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: node-metrics-printer-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: node-metrics-printer-role subjects: - kind: ServiceAccount name: node-metrics-printer-sa namespace: node-metrics-printer-namespace --- apiVersion: v1 kind: ServiceAccount metadata: name: node-metrics-printer-sa namespace: node-metrics-printer-namespace --- apiVersion: apps/v1 kind: DaemonSet metadata: name: node-metrics-printer namespace: node-metrics-printer-namespace spec: selector: matchLabels: app: node-metrics-printer template: metadata: labels: app: node-metrics-printer spec: serviceAccountName: node-metrics-printer-sa containers: - name: metrics-printer image: us-docker.pkg.dev/cloud-builders/ga/v1/curl:latest command: ["sh", "-c"] args: - 'while true; do curl -s --cacert "${CA_CERT}" -H "Authorization: Bearer $(cat ${TOKEN_FILE})" "https://${NODE_ADDRESS}:10250/metrics"|grep kubelet_http_requests_total; sleep 20; done' env: - name: CA_CERT value: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt - name: TOKEN_FILE value: /var/run/secrets/kubernetes.io/serviceaccount/token - name: NODE_ADDRESS valueFrom: fieldRef: fieldPath: status.hostIP
這個資訊清單會執行下列操作:
- 建立命名空間並設定 RBAC 角色,允許讀取節點指標。
- 部署 DaemonSet,檢查 kubelet 指標是否有不安全的唯讀通訊埠。
部署資訊清單:
kubectl create -f read-only-port-metrics.yaml
檢查 DaemonSet 記錄:
kubectl logs --namespace=node-metrics-printer-namespace \ --all-containers --prefix \ --selector=app=node-metrics-printer
如果輸出內容有任何結果包含
server_type=readonly
字串,表示應用程式正在使用不安全的唯讀通訊埠。
檢查標準模式的通訊埠使用情況
在叢集中的每個節點集區,至少有一個節點執行下列指令:
kubectl get --raw /api/v1/nodes/NODE_NAME/proxy/metrics | grep http_requests_total | grep readonly
將 NODE_NAME
替換為節點名稱。
如果輸出內容包含 server_type="readonly"
字串的項目,則可能發生下列情況:
- 節點上的工作負載使用不安全的 kubelet 唯讀通訊埠。
- 停用不安全的連接埠後,指令仍會傳回
server_type="readonly"
字串。這是因為kubelet_http_requests_total
指標代表 kubelet 伺服器自上次重新啟動以來收到的 HTTP 要求累計數量。 停用不安全的連接埠時,系統不會重設這個號碼。GKE 重新啟動 kubelet 伺服器後 (例如在節點升級期間),這個數字就會重設。詳情請參閱 Kubernetes 指標參考資料。
如果輸出內容為空白,表示該節點上沒有任何工作負載使用不安全的唯讀通訊埠。
找出使用不安全 kubelet 唯讀通訊埠的工作負載
如要找出使用不安全連接埠的工作負載,請檢查工作負載的設定檔,例如 ConfigMap 和 Pod。
執行下列指令:
kubectl get pods --all-namespaces -o yaml | grep 10255
kubectl get configmaps --all-namespaces -o yaml | grep 10255
如果指令輸出內容不為空白,請使用下列指令碼找出使用不安全通訊埠的 ConfigMap 或 Pod 名稱:
# This function checks if a Kubernetes resource is using the insecure port 10255.
#
# Arguments:
# $1 - Resource type (e.g., pod, configmap, )
# $2 - Resource name
# $3 - Namespace
#
# Output:
# Prints a message indicating whether the resource is using the insecure port.
isUsingInsecurePort() {
resource_type=$1
resource_name=$2
namespace=$3
config=$(kubectl get $resource_type $resource_name -n $namespace -o yaml)
# Check if kubectl output is empty
if [[ -z "$config" ]]; then
echo "No configuration file detected for $resource_type: $resource_name (Namespace: $namespace)"
return
fi
if echo "$config" | grep -q "10255"; then
echo "Warning: The configuration file ($resource_type: $namespace/$resource_name) is using insecure port 10255. It is recommended to migrate to port 10250 for enhanced security."
else
echo "Info: The configuration file ($resource_type: $namespace/$resource_name) is not using insecure port 10255."
fi
}
# Get the list of ConfigMaps with their namespaces
configmaps=$(kubectl get configmaps -A -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name | tail -n +2 | awk '{print $1"/"$2}')
# Iterate over each ConfigMap
for configmap in $configmaps; do
namespace=$(echo $configmap | cut -d/ -f1)
configmap_name=$(echo $configmap | cut -d/ -f2)
isUsingInsecurePort "configmap" "$configmap_name" "$namespace"
done
# Get the list of Pods with their namespaces
pods=$(kubectl get pods -A -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name | tail -n +2 | awk '{print $1"/"$2}')
# Iterate over each Pod
for pod in $pods; do
namespace=$(echo $pod | cut -d/ -f1)
pod_name=$(echo $pod | cut -d/ -f2)
isUsingInsecurePort "pod" "$pod_name" "$namespace"
done
找出相關工作負載後,請完成下一節的步驟,將這些工作負載遷移至安全連接埠 10250。
從不安全的 kubelet 唯讀連接埠遷移
通常將應用程式遷移至安全通訊埠的步驟如下:
更新參照不安全唯讀通訊埠的網址或端點,改為使用安全唯讀通訊埠。例如,將
http://203.0.113.104:10255
變更為http://203.0.113.104:10250
。將 HTTP 用戶端的憑證授權單位 (CA) 憑證設為叢集 CA 憑證。如要尋找這項憑證,請執行下列指令:
gcloud container clusters describe CLUSTER_NAME \ --location=LOCATION \ --format="value(masterAuth.clusterCaCertificate)"
更改下列內容:
CLUSTER_NAME
:叢集名稱。LOCATION
:叢集位置。
經過驗證的連接埠 10250
需要您授予主體適當的 RBAC 角色,才能存取特定資源。詳情請參閱 Kubernetes 說明文件中的 kubelet 授權。
如果工作負載使用不安全 kubelet 唯讀通訊埠上的 /pods
端點,您需要授予 nodes/proxy
RBAC 權限,才能存取安全 kubelet 通訊埠上的端點。nodes/proxy
是強大的權限,您無法在 GKE Autopilot 叢集中授予,也不應在 GKE Standard 叢集中授予。請使用 Kubernetes API,並為節點名稱加上 fieldSelector
。
如果您使用依附於不安全 kubelet 唯讀連接埠的第三方應用程式,請向應用程式供應商索取操作說明,瞭解如何遷移至安全連接埠 10250
。
遷移範例
假設有個 Pod 會從不安全的 kubelet 唯讀埠查詢指標。
apiVersion: v1
kind: Pod
metadata:
name: kubelet-readonly-example
spec:
restartPolicy: Never
containers:
- name: kubelet-readonly-example
image: us-docker.pkg.dev/cloud-builders/ga/v1/curl:latest
command:
- curl
- http://$(NODE_ADDRESS):10255/metrics
env:
- name: NODE_ADDRESS
valueFrom:
fieldRef:
fieldPath: status.hostIP
這個應用程式會執行下列作業:
- 使用
default
命名空間中的default
ServiceAccount - 針對節點上的
/metrics
端點執行curl
指令。
如要更新這個 Pod 以使用安全通訊埠 10250
,請按照下列步驟操作:
建立有權取得節點指標的 ClusterRole:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: curl-authenticated-role rules: - apiGroups: - "" resources: - nodes/metrics verbs: - get
將 ClusterRole 繫結至應用程式的身分:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: curl-authenticated-role-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: curl-authenticated-role subjects: - kind: ServiceAccount name: default namespace: default
更新
curl
指令,使用安全通訊埠端點和相應的授權標頭:apiVersion: v1 kind: Pod metadata: name: kubelet-authenticated-example spec: restartPolicy: Never containers: - name: kubelet-readonly-example image: us-docker.pkg.dev/cloud-builders/ga/v1/curl:latest env: - name: NODE_ADDRESS valueFrom: fieldRef: fieldPath: status.hostIP command: - sh - -c - 'curl -s --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://${NODE_ADDRESS}:10250/metrics'
修改虛擬私有雲防火牆規則
如果更新工作負載以使用通訊埠 10250
,請建立防火牆規則,讓叢集中的 Pod 可以存取節點 IP 位址範圍內的通訊埠。防火牆規則應執行下列操作:
- 允許來自內部 Pod IP 位址範圍的連入流量,進入節點 IP 位址範圍的 TCP 通訊埠
10250
- 拒絕從公開網際網路傳入節點 IP 位址範圍的 TCP 通訊埠
10250
流量。
您可以將下列預設 GKE 防火牆規則做為範本,在新規則中指定參數:
gke-[cluster-name]-[cluster-hash]-inkubelet
gke-[cluster-name]-[cluster-hash]-exkubelet
在 Autopilot 叢集上停用不安全的唯讀埠
您可以為新舊 Autopilot 叢集停用不安全的 kubelet 唯讀連接埠。
如要在 Autopilot 叢集上停用不安全的 kubelet 唯讀通訊埠,請使用 --no-autoprovisioning-enable-insecure-kubelet-readonly-port
旗標,如下列指令所示。叢集中的所有新舊節點都會停止使用該連接埠。
gcloud container clusters update CLUSTER_NAME \
--location=LOCATION \
--no-autoprovisioning-enable-insecure-kubelet-readonly-port
更改下列內容:
CLUSTER_NAME
:現有叢集的名稱。LOCATION
:現有叢集的位置。
使用 gcloud container clusters create-auto 指令建立新叢集時,也可以使用 --no-autoprovisioning-enable-insecure-kubelet-readonly-port
標記。
在標準叢集上停用不安全的唯讀通訊埠
您可以為整個標準叢集或個別節點集區停用不安全的 kubelet 唯讀埠。建議您為整個叢集停用該連接埠。
如果您使用節點自動佈建功能,系統會自動佈建節點集區,並沿用您在叢集層級指定的連接埠設定。您可以選擇為自動佈建的節點集區指定不同設定,但建議您在叢集的所有節點中停用該連接埠。
您也可以使用節點系統設定檔,以宣告方式停用不安全的 kubelet 唯讀埠。如果您使用這個檔案,就無法使用下列章節中的指令控制 kubelet 設定。
在現有標準叢集上停用不安全的唯讀埠
如要在現有標準叢集上停用不安全的 kubelet 唯讀通訊埠,請使用 --no-enable-insecure-kubelet-readonly-port
標記,如下列指令所示。任何新節點集區都不會使用不安全的通訊埠。GKE 不會自動更新現有節點集區。
gcloud container clusters update CLUSTER_NAME \
--location=LOCATION \
--no-enable-insecure-kubelet-readonly-port
更改下列內容:
CLUSTER_NAME
:現有標準叢集的名稱。LOCATION
:現有標準叢集的位置。
使用 gcloud container clusters create 指令建立新叢集時,也可以使用 --no-autoprovisioning-enable-insecure-kubelet-readonly-port
標記。
在標準節點集區中停用不安全的唯讀通訊埠
建議您一律在叢集層級設定唯讀埠。如果您在現有叢集上停用了唯讀埠,而該叢集已執行節點集區,請使用下列指令停用這些節點集區上的埠。
這可能會導致執行中的工作負載中斷。gcloud container node-pools update NODE_POOL_NAME \
--cluster=CLUSTER_NAME \
--location=LOCATION \
--no-enable-insecure-kubelet-readonly-port
更改下列內容:
NODE_POOL_NAME
:節點集區的名稱。CLUSTER_NAME
:叢集名稱。LOCATION
:叢集位置。
確認通訊埠已停用
如要確認不安全的 kubelet 唯讀埠已停用,請說明 GKE 資源。
檢查 Autopilot 叢集中的連接埠狀態
執行下列指令:
gcloud container clusters describe CLUSTER_NAME \
--location=LOCATION \
--flatten=nodePoolAutoConfig \
--format="value(nodeKubeletConfig)"
更改下列內容:
CLUSTER_NAME
:Autopilot 叢集名稱。LOCATION
:Autopilot 叢集的位置。
如果連接埠已停用,輸出內容如下:
insecureKubeletReadonlyPortEnabled: false
檢查標準叢集中的連接埠狀態
使用 GKE API 說明叢集時,nodePoolDefaults.nodeConfigDefaults.nodeKubeletConfig
欄位會顯示連接埠狀態。
在標準叢集中,您也會看到 nodeConfig
欄位,可為 kubelet 唯讀連接埠狀態設定值。nodeConfig
欄位已淘汰,僅適用於您建立新標準模式叢集時,GKE 建立的預設節點集區。已淘汰的 nodeConfig
欄位中顯示的連接埠狀態,不適用於叢集中的其他節點集區。
執行下列指令:
gcloud container clusters describe CLUSTER_NAME \
--location=LOCATION \
--flatten=nodePoolDefaults.nodeConfigDefaults \
--format="value(nodeKubeletConfig)"
更改下列內容:
CLUSTER_NAME
:標準叢集名稱。LOCATION
:標準叢集的位置。
如果連接埠已停用,輸出內容如下:
insecureKubeletReadonlyPortEnabled: false
檢查標準節點集區中的通訊埠狀態
執行下列指令:
gcloud container node-pools describe NODE_POOL_NAME \
--cluster=CLUSTER_NAME \
--location=LOCATION \
--flatten=config \
--format="value(kubeletConfig)"
更改下列內容:
NODE_POOL_NAME
:節點集區的名稱。CLUSTER_NAME
:叢集名稱。LOCATION
:叢集位置。
如果連接埠已停用,輸出內容如下:
insecureKubeletReadonlyPortEnabled: false