GKE Sandbox로 워크로드 격리 강화


이 페이지에서는 Pod의 컨테이너가 알 수 없는 또는 신뢰할 수 없는 코드를 실행하거나 노드에서 추가 격리가 필요한 경우 GKE Sandbox를 사용하여 노드의 호스트 커널을 보호하는 방법을 설명합니다.

GKE Sandbox 사용 설정

새 클러스터 또는 기존 클러스터에서 GKE Sandbox를 사용 설정할 수 있습니다.

시작하기 전에

시작하기 전에 다음 태스크를 수행했는지 확인합니다.

다음 방법 중 하나를 사용하여 기본 gcloud 설정을 진행합니다.

  • gcloud init를 사용하여 기본값 설정 과정을 진행합니다.
  • gcloud config를 사용하여 프로젝트 ID, 영역, 리전을 개별적으로 설정합니다.

gcloud init 사용

One of [--zone, --region] must be supplied: Please specify location 오류가 표시되면 이 섹션을 완료합니다.

  1. gcloud init를 실행하고 다음 안내를 따르세요.

    gcloud init

    원격 서버에서 SSH를 사용하는 경우 --console-only 플래그를 사용하여 다음 명령어로 브라우저를 실행하지 못하게 할 수 있습니다.

    gcloud init --console-only
  2. 안내를 따라 gcloud에서 Google Cloud 계정을 사용하도록 승인합니다.
  3. 새 구성을 만들거나 기존 구성을 선택합니다.
  4. Google Cloud 프로젝트를 선택합니다.
  5. 영역 클러스터의 기본 Compute Engine 영역이나 리전 또는 Autopilot 클러스터의 리전을 선택합니다.

gcloud config 사용

  • 기본 프로젝트 ID를 설정합니다.
    gcloud config set project PROJECT_ID
  • 영역 클러스터를 사용하는 경우 기본 컴퓨팅 영역을 설정합니다.
    gcloud config set compute/zone COMPUTE_ZONE
  • Autopilot 또는 리전 클러스터를 사용하는 경우 기본 컴퓨팅 리전을 설정합니다.
    gcloud config set compute/region COMPUTE_REGION
  • gcloud를 최신 버전으로 업데이트합니다.
    gcloud components update
  • GKE Sandbox를 사용하려면 클러스터 제어 영역과 노드에 GKE 버전 1.13.5-gke.15 이상이 필요합니다.
  • gcloud 명령어 버전이 243.0.0 이상인지 확인합니다.

새 클러스터

GKE Sandbox를 사용 설정하려면 노드 풀을 구성합니다. 기본 노드 풀(클러스터가 생성될 때 생성되는 클러스터의 첫 번째 노드 풀)은 GKE Sandbox를 사용할 수 없습니다. 클러스터 생성 중에 GKE Sandbox를 사용 설정하려면 클러스터를 만들 때 두 번째 노드 풀을 추가해야 합니다.

Console

클러스터를 보려면 Cloud Console에서 Google Kubernetes Engine 메뉴로 이동합니다.

  1. Cloud Console에서 Google Kubernetes Engine 페이지로 이동합니다.

    Google Kubernetes Engine으로 이동

  2. 만들기를 클릭합니다.

  3. 선택사항이지만 권장됨: 탐색 창의 클러스터 아래에서 기능을 클릭하고 gVisor 메시지가 로깅되도록 Cloud Operations for GKE를 사용 설정합니다.

  4. 노드 풀 추가를 클릭합니다.

  5. 탐색 창의 노드 풀 아래에서 새 노드 풀을 확장하고 노드를 클릭합니다.

  6. 노드 풀에 다음 설정을 구성합니다.

    1. 이미지 유형 드롭다운 목록에서 Containerd를 포함한 Container-Optimized OS(cos_containerd)를 선택합니다.
    2. 머신 구성에서 시리즈머신 유형을 선택합니다.

  7. 탐색 창에서 구성하려는 노드 풀 이름 아래에서 보안을 클릭하고 gVisor가 포함된 샌드박스 사용 설정 체크박스를 선택합니다.

  8. 계속해서 필요에 따라 클러스터 및 노드 풀을 구성합니다.

  9. 만들기를 클릭합니다.

gcloud

GKE Sandbox는 기본 노드 풀에 대해 사용 설정할 수 없습니다. 또한 gcloud 명령어를 실행하여 새 클러스터를 만드는 것과 동시에 추가 노드 풀을 만들 수는 없습니다. 대신 평소와 같이 클러스터를 만듭니다. 선택사항이지만 --enable-stackdriver-kubernetes 플래그를 추가하여 Stackdriver Logging 및 Stackdriver Monitoring을 사용 설정하는 것이 좋습니다. gVisor 메시지가 로깅됩니다.

그 다음 gcloud container node-pools create 명령어를 사용하고 --sandbox 플래그를 type=gvisor로 설정합니다. 대괄호 안의 값을 사용자의 고유 값으로 바꿉니다.

gcloud container node-pools create node-pool-name \
  --cluster=cluster-name \
  --node-version=node-version \
  --machine-type=machine-type \
  --image-type=cos_containerd \
  --sandbox type=gvisor \

1.18.4-gke.1300 전에는 gvisor RuntimeClass가 노드 생성 중 인스턴스화됩니다. 워크로드가 노드에 예약되기 전 다음 명령어를 사용하여 gvisor RuntimeClass가 존재하는지 확인합니다.

kubectl get runtimeclasses
NAME     AGE
gvisor   19s

1.17.9-gke.1500 이전 버전 또는 1.18.6-gke.600 이전의 1.18 버전을 실행하는 경우 gvisor.config.common-webhooks.networking.gke.io가 인스턴스화될 때까지 기다려야 합니다. 확인하려면 다음 명령어를 사용합니다.

kubectl get mutatingwebhookconfiguration gvisor.config.common-webhooks.networking.gke.io
NAME                                              CREATED AT
gvisor.config.common-webhooks.networking.gke.io   2020-04-06T17:07:17Z

기존 클러스터에서

새 노드 풀을 추가하고 해당 노드 풀에 대해 기능을 사용 설정하여 기존 클러스터에서 GKE Sandbox를 사용 설정할 수 있습니다.

Console

GKE Sandbox가 사용 설정된 새 노드 풀을 만들려면 다음 안내를 따르세요.

  1. Cloud Console에서 Google Kubernetes Engine 메뉴로 이동합니다.

    Google Kubernetes Engine 메뉴로 이동

  2. 수정할 클러스터의 이름을 클릭합니다.

  3. 노드 풀 추가를 클릭합니다.

  4. 필요에 따라 노드 풀 세부정보 페이지를 구성합니다.

  5. 탐색 창에서 노드를 클릭하고 다음 설정을 구성합니다.

    1. 이미지 유형 드롭다운 목록에서 Containerd를 포함한 Container-Optimized OS(cos_containerd)를 선택합니다.
    2. 머신 구성에서 시리즈머신 유형을 선택합니다.

  6. 탐색 창에서 보안을 클릭하고 gVisor가 포함된 샌드박스 사용 설정 체크박스를 선택합니다.

  7. 만들기를 클릭합니다.

gcloud

GKE Sandbox가 사용 설정된 새 노드 풀을 만들려면 다음과 같은 명령어를 사용합니다.

gcloud container node-pools create node-pool-name \
  --cluster=cluster-name \
  --machine-type=machine-type \
  --image-type=cos_containerd \
  --sandbox type=gvisor

1.18.4-gke.1300 전에는 gvisor RuntimeClass가 노드 생성 중 인스턴스화됩니다. 워크로드가 노드에 예약되기 전 다음 명령어를 사용하여 gvisor RuntimeClass가 존재하는지 확인합니다.

kubectl get runtimeclasses
NAME     AGE
gvisor   19s

1.17.9-gke.1500 이전 버전 또는 1.18.6-gke.600 이전의 1.18 버전을 실행하는 경우 gvisor.config.common-webhooks.networking.gke.io가 인스턴스화될 때까지 기다려야 합니다. 확인하려면 다음 명령어를 사용합니다.

kubectl get mutatingwebhookconfiguration gvisor.config.common-webhooks.networking.gke.io
NAME                                              CREATED AT
gvisor.config.common-webhooks.networking.gke.io   2020-04-06T17:07:17Z

선택사항: Cloud Operations for GKE 사용 설정

선택사항이지만 gVisor 메시지가 로깅되도록 클러스터에서 Cloud Operations for GKE를 사용 설정하는 것이 좋습니다. Cloud Operations for GKE는 기본적으로 새 클러스터에 대해 사용 설정됩니다.

Google Cloud Console을 사용하면 기존 클러스터에서 이 기능을 사용 설정할 수 있습니다.

  1. Cloud Console에서 Google Kubernetes Engine 메뉴로 이동합니다.

    Google Kubernetes Engine 메뉴로 이동

  2. 수정할 클러스터의 이름을 클릭합니다.

  3. 기능 아래의 Cloud Operations for GKE 필드에서 Cloud Operations for GKE 수정을 클릭합니다.

  4. Cloud Operations for GKE 사용 설정 체크박스를 선택합니다.

  5. 드롭다운 목록에서 시스템 및 워크로드 로깅 및 모니터링을 선택합니다.

  6. 변경사항 저장을 클릭합니다.

GKE Sandbox 작업

샌드박스에서 애플리케이션 실행

GKE Sandbox가 사용 설정된 노드에서 배포 실행을 강제하려면 배포에 대한 이 매니페스트에서 볼 수 있듯이 노드의 spec.template.spec.runtimeClassNamegvisor로 설정합니다.

# httpd.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd
  labels:
    app: httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpd
  template:
    metadata:
      labels:
        app: httpd
    spec:
      runtimeClassName: gvisor
      containers:
      - name: httpd
        image: httpd

배포를 생성하려면 kubectl create 명령어를 사용합니다.

kubectl create -f httpd.yaml

Pod는 GKE Sandbox가 사용 설정된 노드 풀의 노드에 배포됩니다. 배포를 확인하려면 다음 명령어를 사용하여 Pod가 배포되는 노드를 찾습니다.

kubectl get pods

출력은 다음과 비슷합니다.

NAME                    READY   STATUS    RESTARTS   AGE
httpd-db5899bc9-dk7lk   1/1     Running   0          24s

출력에서 Pod 이름을 찾은 후 다음 명령어를 실행하여 RuntimeClass 값을 확인합니다.

kubectl get pods pod-name -o jsonpath='{.spec.runtimeClassName}'

출력은 다음과 같습니다.

gvisor

또는 각 Pod의 RuntimeClass를 나열하고 gvisor로 설정된 RuntimeClass를 찾을 수 있습니다.

kubectl get pods -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.runtimeClassName}\n{end}'

출력은 다음과 같습니다.

pod-name: gvisor

Pod가 샌드박스에서 실행 중인지 확인하는 이 방법은 샌드박스 자체의 데이터에 의존하지 않으므로 신뢰할 수 있습니다. 샌드박스 내에서 보고되는 내용은 결함이 있거나 악성일 수 있으므로 신뢰할 수 없습니다.

샌드박스 처리된 Pod와 일반 Pod 함께 실행

노드 풀에서 GKE Sandbox를 사용 설정한 후에는 노드 taint 및 내결함성을 사용하여 샌드박스를 사용하지 않고도 이러한 노드에서 신뢰할 수 있는 애플리케이션을 실행할 수 있습니다. 샌드박스 처리된 Pod와 구분하기 위해 이러한 Pod를 '일반 Pod'라고 합니다.

일반 Pod는 샌드박스 처리된 Pod와 마찬가지로 다른 Google Cloud 서비스나 클러스터 메타데이터에 액세스할 수 없습니다. 이러한 액세스 차단은 노드 구성의 일부입니다. 일반 Pod 또는 샌드박스 처리된 Pod에서 Google Cloud 서비스에 액세스해야 하는 경우 워크로드 아이덴티티를 사용합니다.

GKE Sandbox는 샌드박스 처리된 Pod를 실행할 수 있는 노드에 다음 라벨과 taint를 추가합니다.

labels:
  sandbox.gke.io/runtime: gvisor
taints:
- effect: NoSchedule
  key: sandbox.gke.io/runtime
  value: gvisor

Pod 매니페스트의 노드 어피니티 및 내결함성 설정 외에, GKE Sandbox는 다음 노드 어피니티 및 내결함성을 RuntimeClassgvisor로 설정된 모든 Pod에 적용합니다.

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: sandbox.gke.io/runtime
          operator: In
          values:
          - gvisor
tolerations:
  - effect: NoSchedule
    key: sandbox.gke.io/runtime
    operator: Equal
    value: gvisor

GKE Sandbox가 사용 설정된 노드에서 일반 Pod를 예약하려면 위의 노드 어피니티 및 내결함성을 Pod 매니페스트에 수동으로 적용합니다.

  • GKE Sandbox가 사용 설정된 노드에서 Pod를 실행할 수 있는 경우 내결함성을 추가합니다.
  • GKE Sandbox가 사용 설정된 노드에서 Pod를 실행해야 하는 경우 노드 어피니티와 내결함성을 모두 추가합니다.

예를 들어 다음 매니페스트는 runtimeClass를 제거하고 위의 taint와 내결함성을 모두 추가하여 샌드박스에서 애플리케이션 실행에 사용된 매니페스트를 수정하여 샌드박스 처리된 Pod가 있는 노드에서 일반 Pod로 실행됩니다.

# httpd-no-sandbox.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd-no-sandbox
  labels:
    app: httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpd
  template:
    metadata:
      labels:
        app: httpd
    spec:
      containers:
      - name: httpd
        image: httpd
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: sandbox.gke.io/runtime
                operator: In
                values:
                - gvisor
      tolerations:
        - effect: NoSchedule
          key: sandbox.gke.io/runtime
          operator: Equal
          value: gvisor

먼저 샌드박스에서 배포가 실행되고 있지 않은지 확인합니다.

kubectl get pods -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.runtimeClassName}\n{end}'

출력은 다음과 비슷합니다.

httpd-db5899bc9-dk7lk: gvisor
httpd-no-sandbox-5bf87996c6-cfmmd:

runtimeClass가 gvisor이므로 이전에 생성된 httpd 배포는 샌드박스에서 실행 중입니다. httpd-no-sandbox 배포에는 runtimeClass의 값이 없으므로 샌드박스에서 실행 중이 아닙니다.

다음 명령어를 실행하여 GKE Sandbox가 있는 노드에서 샌드박스 처리되지 않은 배포가 실행 중인지 확인합니다.

kubectl get pod -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.nodeName}\n{end}'

노드 풀의 이름은 nodeName 값에 삽입됩니다. Pod가 GKE Sandbox가 사용 설정된 노드 풀의 노드에서 실행 중인지 확인합니다.

메타데이터 보호 확인

샌드박스 처리된 Pod를 실행할 수 있는 노드에서 메타데이터가 보호된다는 어설션을 검증하려면 테스트를 실행합니다.

  1. kubectl apply -f를 사용하여 다음 매니페스트에서 샌드박스 처리된 배포를 만듭니다. 여기서는 curl 명령어가 포함된 fedora 이미지를 사용합니다. Pod는 /bin/sleep 명령어를 실행하여 배포가 10000초 동안 실행되는지 확인합니다.

    # sandbox-metadata-test.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: fedora
      labels:
        app: fedora
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: fedora
      template:
        metadata:
          labels:
            app: fedora
        spec:
          runtimeClassName: gvisor
          containers:
          - name: fedora
            image: fedora
            command: ["/bin/sleep","10000"]
    
  2. kubectl get pods를 사용하여 Pod 이름을 가져온 다음 kubectl exec를 사용하여 대화형으로 Pod에 연결합니다.

    kubectl exec -it pod-name /bin/sh
    

    /bin/sh 세션에서 Pod에서 실행 중인 컨테이너에 연결됩니다.

  3. 대화형 세션 내에서 다음과 같이 클러스터 메타데이터를 반환하는 URL에 액세스를 시도합니다.

    curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/kube-env" -H "Metadata-Flavor: Google"
    

    아무런 표시 없이 패킷이 누락되므로 명령어 실행이 멈추고 결국 타임아웃됩니다.

  4. Ctrl+C를 눌러 curl 명령어를 종료하고 exit를 입력하여 Pod 연결을 해제합니다.

  5. YAML 매니페스트에서 RuntimeClass 줄을 삭제하고 kubectl apply -f filename을 사용하여 Pod를 다시 배포합니다. 샌드박스 처리된 Pod가 종료되고 GKE Sandbox가 없는 노드에서 다시 생성됩니다.

  6. 새 Pod 이름을 가져오고 kubectl exec를 사용하여 연결하고 curl 명령어를 다시 실행합니다. 이번에는 결과가 반환됩니다. 이 예시 출력은 잘립니다.

    ALLOCATE_NODE_CIDRS: "true"
    API_SERVER_TEST_LOG_LEVEL: --v=3
    AUTOSCALER_ENV_VARS: kube_reserved=cpu=60m,memory=960Mi,ephemeral-storage=41Gi;...
    ...
    

    exit를 입력하여 Pod 연결을 해제합니다.

  7. 배포를 삭제합니다.

    kubectl delete deployment fedora
    

GKE Sandbox 사용 중지

현재 노드 풀을 업데이트하여 GKE Sandbox를 사용 중지할 수 없습니다. 기존 노드 풀에서 GKE Sandbox를 사용 중지하려면 다음 중 하나를 수행합니다.

다음 단계