이 페이지에서는 Google Kubernetes Engine(GKE) 클러스터에서 보안이 안 된 kubelet 읽기 전용 포트를 사용 중지하여 kubelet에 대한 무단 액세스의 위험을 줄이고 애플리케이션을 보다 안전한 포트로 마이그레이션하는 방법을 설명합니다.
GKE를 포함한 Kubernetes 클러스터에서는 노드에서 실행되는 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
명령어를 실행하여 최신 버전을 가져옵니다. 이전 gcloud CLI 버전에서는 이 문서의 명령어를 실행하지 못할 수 있습니다.
- 기존 Autopilot 또는 Standard 클러스터가 있는지 확인합니다. 새 클러스터를 만들려면 Autopilot 클러스터 만들기를 참조하세요.
요구사항
- GKE 버전 1.26.4-gke.500 이상에서만 비보안 kubelet 읽기 전용 포트를 사용 중지할 수 있습니다.
비보안 포트 사용 확인 및 애플리케이션 마이그레이션
비보안 읽기 전용 포트를 사용 중지하려면 먼저 이 포트를 사용하는 실행 중인 애플리케이션을 보다 안전한 읽기 전용 포트로 마이그레이션합니다. 마이그레이션이 필요할 수 있는 워크로드에는 kubelet 엔드포인트에 액세스하는 커스텀 측정항목 파이프라인과 워크로드가 포함됩니다.
- 노드에서 kubelet API로 제공되는 정보에 대해 액세스 권한이 필요한 워크로드의 경우 포트
10250
을 사용합니다. - 노드의 포드 나열과 같이 노드에서 kubelet API를 사용하여 Kubernetes 정보를 가져오는 워크로드의 경우 Kubernetes API를 대신 사용합니다.
애플리케이션이 비보안 kubelet 읽기 전용 포트를 사용하는지 여부 확인
이 섹션에서는 클러스터에서 비보안 포트 사용을 확인하는 방법을 보여줍니다.
Autopilot 모드의 포트 사용 확인
Autopilot 클러스터에서 포트 사용을 확인하려면 클러스터에서 실행 중인 DaemonSet가 아닌 워크로드가 하나 이상 있는지 확인합니다. 빈 Autopilot 클러스터에서 다음 단계를 수행하는 경우 결과가 잘못될 수 있습니다.
다음 매니페스트를
read-only-port-metrics.yaml
로 저장합니다.# Create a namespace for the DaemonSet that checks for port usage. apiVersion: v1 kind: Namespace metadata: name: node-metrics-printer-namespace --- # Grant access to read node metrics in the cluster. 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 # Bind the ClusterRole to the ServiceAccount that the DaemonSet will use. subjects: - kind: ServiceAccount name: node-metrics-printer-sa namespace: node-metrics-printer-namespace --- # Create a ServiceAccount for the DaemonSet. 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: # Assign the ServiceAccount to the DaemonSet. serviceAccountName: node-metrics-printer-sa containers: - name: metrics-printer image: us-docker.pkg.dev/cloud-builders/ga/v1/curl:latest command: ["sh", "-c"] # Call the /metrics endpoint using the insecure kubelet read-only # port. 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: # Provide credentials and the IP address for the command. - 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 역할을 설정합니다.
- 비보안 읽기 전용 포트에 대해 kubelet 측정항목을 확인하는DaemonSet를 배포합니다.
매니페스트를 배포합니다.
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 및 포드와 같은 워크로드의 구성 파일을 확인합니다.
다음 명령어를 실행합니다.
kubectl get pods --all-namespaces -o yaml | grep 10255
kubectl get configmaps --all-namespaces -o yaml | grep 10255
명령어의 출력이 비어 있지 않으면 다음 스크립트를 사용하여 안전하지 않은 포트를 사용 중인 ConfigMap 또는 포드 이름을 확인합니다.
# 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 읽기 전용 포트에서 마이그레이션
일반적으로 보안 포트로 애플리케이션을 마이그레이션하기 위해서는 다음 단계가 수행됩니다.
비보안 읽기 전용 포트를 참조하는 URL 또는 엔드포인트가 보안 읽기 전용 포트를 대신 사용하도록 업데이트합니다. 예를 들어
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 승인을 참조하세요.
/pods
안전하지 않은 kubelet 읽기 전용 포트에서 nodes/proxy
엔드포인트가 워크로드에 사용되는 경우 보안 kubelet 포트에서 엔드포인트에 액세스하도록 RBAC 권한을 부여해야 합니다. nodes/proxy
는 GKE Autopilot 클러스터에서 부여할 수 없고 GKE Standard 클러스터에서 부여하지 않아야 하는 강력한 권한입니다. 대신 노드 이름에 대해 fieldSelector
가 있는 Kubernetes API를 사용하세요.
비보안 kubelet 읽기 전용 포트에 의존하는 서드 파티 애플리케이션을 사용하는 경우 애플리케이션 공급업체에 문의하여 보안 포트 10250
으로 마이그레이션 관련 안내를 확인하세요.
마이그레이션 예시
비보안 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
명령어를 실행합니다.
보안 포트 10250
을 사용하도록 이 포드를 업데이트하려면 다음 단계를 수행합니다.
노드 측정항목에 액세스할 수 있는 권한이 있는 ClusterRole을 만듭니다.
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: curl-authenticated-role rules: # Grant access to read node metrics in the cluster. - apiGroups: - "" resources: - nodes/metrics verbs: - get
ClusterRole을 애플리케이션 ID에 바인딩합니다.
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 # Bind the ClusterRole to the default ServiceAccount in the default # namespace. 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 # Update the command to send a request with the ServiceAccount # credentials in the header. 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'
VPC 방화벽 규칙 수정
포트 10250
을 사용하도록 워크로드를 업데이트하는 경우 클러스터의 포드가 노드 IP 주소 범위의 포트에 연결할 수 있도록 방화벽 규칙을 만듭니다. 방화벽 규칙은 다음을 수행해야 합니다.
- 내부 포드 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
: 기존 Standard 클러스터의 이름입니다.LOCATION
: 기존 Standard 클러스터의 위치입니다.
또한 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
필드에 표시됩니다.
표준 클러스터에서는 또한 kubelet 읽기 전용 포트 상태에 대한 값을 설정하는 nodeConfig
필드가 표시됩니다. nodeConfig
필드는 지원 중단되었고 새로운 표준 모드 클러스터를 만들 때 GKE가 만드는 기본 노드 풀에만 적용됩니다. 지원 중단된 nodeConfig
필드의 포트 상태는 클러스터의 다른 노드 풀에 적용되지 않습니다.
다음 명령어를 실행합니다.
gcloud container clusters describe CLUSTER_NAME \
--location=LOCATION \
--flatten=nodePoolDefaults.nodeConfigDefaults \
--format="value(nodeKubeletConfig)"
다음을 바꿉니다.
CLUSTER_NAME
: 표준 클러스터의 이름입니다.LOCATION
: 표준 클러스터의 위치입니다.
포트가 사용 중지되었으면 출력이 다음과 같습니다.
insecureKubeletReadonlyPortEnabled: false
이 명령어의 출력이 비어 있으면 안전하지 않은 kubelet
읽기 전용 포트가 아직 사용 설정되어 있을 수 있습니다. 포트를 사용 중지하려면 기존 표준 클러스터에서 비보안 읽기 전용 포트 사용 중지 섹션의 명령어를 실행합니다.
표준 노드 풀에서 포트 상태 확인
다음 명령어를 실행합니다.
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
조직 정책으로 안전하지 않은 포트 사용 방지
조직 정책 서비스를 사용하여 조직, 폴더 또는 프로젝트의 클러스터가 비보안 kubelet
읽기 전용 포트를 사용 중지하도록 강제할 수 있습니다. 이 요구사항을 적용하려면 커스텀 제약 조건을 만든 다음 조직 정책에서 해당 제약 조건을 참조합니다. 비보안 kubelet
읽기 전용 포트가 사용 설정된 경우 생성 또는 업데이트 작업을 거부하려면 다음 예를 참고하세요.
다음 맞춤 제약 조건은 보안이 안 된
kubelet
읽기 전용 포트가 사용 설정된 경우 클러스터 생성 또는 업데이트 작업을 거부합니다.name: organizations/ORGANIZATION_ID/customConstraints/custom.disableClusterInsecureKubeletReadOnlyPort resourceTypes: - container.googleapis.com/Cluster methodTypes: - CREATE - UPDATE condition: "resource.NodeKubeletConfig.insecureKubeletReadonlyPortEnabled == true || resource.AutoprovisioningNodePoolDefaults.insecureKubeletReadonlyPortEnabled == true || resource.NodePoolAutoConfig.NodeKubeletConfig.insecureKubeletReadonlyPortEnabled == true" actionType: DENY displayName: Disable insecure kubelet read-only port description: All new and existing clusters must disable the insecure kubelet read-only port.
ORGANIZATION_ID
를 조직 ID로 바꿉니다.안전하지 않은
kubelet
읽기 전용 포트가 사용 설정된 경우 다음 맞춤 제약 조건은 노드 풀 생성 또는 업데이트 작업을 거부합니다.name: organizations/ORGANIZATION_ID/customConstraints/custom.disableNodePoolInsecureKubeletReadOnlyPort resourceTypes: - container.googleapis.com/NodePool methodTypes: - CREATE - UPDATE condition: "resource.NodeConfig.NodeKubeletConfig.insecureKubeletReadonlyPortEnabled == true" actionType: DENY displayName: Disable insecure kubelet read-only port description: All new and existing node pools must disable the insecure kubelet read-only port.
ORGANIZATION_ID
를 조직 ID로 바꿉니다.
커스텀 제약 조건을 만들고 조직 정책에서 제약 조건을 적용하는 방법에 대한 자세한 내용은 커스텀 조직 정책을 사용하여 GKE 리소스에 대한 작업 제한을 참고하세요.