GKE 클러스터에서 kubelet 읽기 전용 포트 사용 중지


이 페이지에서는 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를 실행하여 최신 버전을 가져옵니다.

요구사항

  • GKE 버전 1.26.4-gke.500 이상에서만 비보안 kubelet 읽기 전용 포트를 사용 중지할 수 있습니다.

비보안 포트 사용 확인 및 애플리케이션 마이그레이션

비보안 읽기 전용 포트를 사용 중지하려면 먼저 이 포트를 사용하는 실행 중인 애플리케이션을 보다 안전한 읽기 전용 포트로 마이그레이션합니다. 마이그레이션이 필요할 수 있는 워크로드에는 kubelet 엔드포인트에 액세스하는 커스텀 측정항목 파이프라인과 워크로드가 포함됩니다.

  • 노드에서 kubelet API로 제공되는 정보에 대해 액세스 권한이 필요한 워크로드의 경우 포트 10250을 사용합니다.
  • 노드의 포드 나열과 같이 노드에서 kubelet API를 사용하여 Kubernetes 정보를 가져오는 워크로드의 경우 Kubernetes API를 대신 사용합니다.

애플리케이션이 비보안 kubelet 읽기 전용 포트를 사용하는지 여부 확인

이 섹션에서는 클러스터에서 비보안 포트 사용을 확인하는 방법을 보여줍니다.

Autopilot 모드의 포트 사용 확인

Autopilot 클러스터에서 포트 사용을 확인하려면 클러스터에서 실행 중인 DaemonSet가 아닌 워크로드가 하나 이상 있는지 확인합니다. 빈 Autopilot 클러스터에서 다음 단계를 수행하는 경우 결과가 잘못될 수 있습니다.

  1. 다음 매니페스트를 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
    

    이 매니페스트는 다음을 수행합니다.

    1. 네임스페이스를 만들고 노드 측정항목 읽기를 허용하는 RBAC 역할을 설정합니다.
    2. 비보안 읽기 전용 포트에 대해 kubelet 측정항목을 확인하는DaemonSet를 배포합니다.
  2. 매니페스트를 배포합니다.

    kubectl create -f read-only-port-metrics.yaml
    
  3. 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을 허브 이름으로 바꿉니다.

노드의 워크로드에 비보안 kubelet 읽기 전용 포트가 사용되는 경우 다음 예시와 같은 server_type="readonly" 문자열 항목이 출력에 포함됩니다.

kubelet_http_requests_total{long_running="false",method="GET",path="healthz",server_type="readonly"} 3
kubelet_http_requests_total{long_running="false",method="GET",path="metrics",server_type="readonly"} 2549
kubelet_http_requests_total{long_running="false",method="GET",path="metrics/probes",server_type="readonly"} 2546
kubelet_http_requests_total{long_running="false",method="GET",path="other",server_type="readonly"} 2
kubelet_http_requests_total{long_running="false",method="GET",path="pods",server_type="readonly"} 1
kubelet_http_requests_total{long_running="false",method="GET",path="stats",server_type="readonly"} 2549

출력이 비어 있으면 해당 노드의 애플리케이션에 비보안 읽기 전용 포트가 사용되지 않음을 나타냅니다.

비보안 kubelet 읽기 전용 포트에서 마이그레이션

일반적으로 보안 포트로 애플리케이션을 마이그레이션하기 위해서는 다음 단계가 수행됩니다.

  1. 비보안 읽기 전용 포트를 참조하는 URL 또는 엔드포인트가 보안 읽기 전용 포트를 대신 사용하도록 업데이트합니다. 예를 들어 http://203.0.113.104:10255http://203.0.113.104:10250으로 변경합니다.

  2. HTTP 클라이언트의 인증 기관(CA) 인증서를 클러스터 CA 인증서로 설정합니다. 이 인증서를 찾으려면 다음 명령어를 실행합니다.

    gcloud container clusters describe CLUSTER_NAME \
        --location=LOCATION \
        --format="value(masterAuth.clusterCaCertificate)"
    

    다음을 바꿉니다.

    • CLUSTER_NAME: 클러스터의 이름입니다.
    • LOCATION: 클러스터의 위치입니다.

인증 포트 10250을 사용하려면 특정 리소스에 액세스하도록 주체에 적합한 RBAC 역할을 부여해야 합니다. 자세한 내용은 Kubernetes 문서에서 kubelet 승인을 참조하세요.

비보안 kubelet 읽기 전용 포트에서 /pods 엔드포인트가 워크로드에 사용되는 경우 보안 kubelet 포트에서 엔드포인트에 액세스하도록 nodes/proxy 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을 사용하도록 이 포드를 업데이트하려면 다음 단계를 수행합니다.

  1. 노드 측정항목에 액세스할 수 있는 권한이 있는 ClusterRole을 만듭니다.

    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: curl-authenticated-role
    rules:
    - apiGroups:
      - ""
      resources:
      - nodes/metrics
      verbs:
      - get
    
  2. 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
    subjects:
    - kind: ServiceAccount
      name: default
      namespace: default
    
  3. 해당 승인 헤더로 보안 포트 엔드포인트를 사용하도록 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'
    

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 클러스터에서 비보안 읽기 전용 포트 사용 중지

새 Autopilot 클러스터를 만들 때 비보안 kubelet 읽기 전용 포트를 사용 중지하려면 다음 명령어에서와 같이 --no-autoprovisioning-enable-insecure-kubelet-readonly-port 플래그를 사용합니다.

gcloud container clusters create-auto CLUSTER_NAME \
    --location=LOCATION \
    --no-autoprovisioning-enable-insecure-kubelet-readonly-port

다음을 바꿉니다.

  • CLUSTER_NAME: 새 Autopilot 클러스터의 이름입니다.
  • LOCATION: 새 Autopilot 클러스터의 위치입니다.

기존 Autopilot 클러스터에서 비보안 읽기 전용 포트 사용 중지

기존 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: 기존 클러스터의 위치입니다.

표준 클러스터에서 비보안 읽기 전용 포트 사용 중지

전체 표준 클러스터에 대해 또는 개별 노드 풀에 대해 비보안 kubelet 읽기 전용 포트를 사용 중지할 수 있습니다. 전체 클러스터에 대해 포트를 사용 중지하는 것이 좋습니다.

노드 자동 프로비저닝을 사용하는 경우 자동으로 프로비저닝된 노드 풀은 클러스터 레벨에서 지정된 포트 설정을 상속합니다. 선택적으로 자동 프로비저닝된 노드 풀에 대해 다른 설정을 지정할 수 있지만 클러스터의 모든 노드 간에 포트를 사용 중지하는 것이 좋습니다.

또한 노드 시스템 구성 파일을 사용하여 비보안 kubelet 읽기 전용 포트를 선언적으로 사용 중지할 수 있습니다. 이 파일을 사용하는 경우 다음 섹션의 명령어를 사용하여 kubelet 설정을 제어할 수 없습니다.

새로운 표준 클러스터에서 비보안 읽기 전용 포트 사용 중지

새로운 표준 클러스터에서 비보안 kubelet 읽기 전용 포트를 사용 중지하려면 다음 명령어에서와 같이 --no-enable-insecure-kubelet-readonly-port 플래그를 사용합니다.

gcloud container clusters create CLUSTER_NAME \
    --location=LOCATION \
    --no-enable-insecure-kubelet-readonly-port

다음을 바꿉니다.

  • CLUSTER_NAME: 새 Standard 클러스터의 이름입니다.
  • LOCATION: 새 Standard 클러스터의 위치입니다.

선택적으로 --no-autoprovisioning-enable-insure-kubelet-readonly-port 플래그를 추가하여 노드 자동 프로비저닝 설정을 개별적으로 제어할 수 있지만, 이렇게 하지 않는 것이 좋습니다. 이 플래그는 자동 프로비저닝된 노드 풀의 순차적 업데이트를 시작하므로, 실행 중인 워크로드에 중단이 발생할 수 있습니다.

기존 표준 클러스터에서 비보안 읽기 전용 포트 사용 중지

기존 표준 클러스터에서 비보안 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 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

표준 노드 풀에서 포트 상태 확인

다음 명령어를 실행합니다.

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