Cloud Tech

k8s node-shell 원리이해

Hanhorang31 2024. 10. 4. 16:52

 

 

 

Node-shell ?

k8s 컨트롤 노드를 통해서 워크 노드에 root 권한으로 접근시킬 수 있는 툴입니다. kubectl krew 확장 도구로 설치가 간단하며, 워크 노드 서버 접근에 자주 사용되는 툴입니다.

다만, k8s api-server만 접근이 가능하게 되면 워크 노드도 접근이 가능하기에 예상치 못한 보안 이슈를 가져올 수 있습니다. 이번 장에서는 해당 툴의 원리를 확인하고 발생할 수 있는 보안 이슈를 확인하겠습니다.

Nodeshell을 통해 워커 노드 root 권한으로 접근
 

원리 이해

구성 원리는 깃 프로젝트 쉘 파일 kubectl-node_shell 에서 확인할 수 있습니다.

핵심 원리는 nsenter 명령을 통한 워크 노드의 네임스페이스(프로세스, 네트워크, 마운트 등) 공유입니다.

kubectl run --image "docker.io/library/alpine" \
           --restart=Never \
           --overrides='{
             "spec": {
               "nodeName": "nodeName", # 입력 노드 변수 이름 
               "hostPID": true,
               "hostNetwork": true,  
               "containers": [
                 {
                   "securityContext": {"privileged": true},
                   "image": "docker.io/library/alpine",
                   "name": "nsenter",
                   "stdin": true,
                   "stdinOnce": true,
                   "tty": true,
                   "command": ["nsenter", "--target", "1", "--mount", "--uts", "--ipc", "--net", "--pid", "--", "bash", "-l"],
                   "resources": {},
                   "volumeMounts": []
                 }
               ],
               "tolerations": [
                 { "key": "CriticalAddonsOnly", "operator": "Exists" },
                 { "effect": "NoExecute", "operator": "Exists" }
               ],
               "volumes": []
             }
           }' \
           --labels="app=node-shell" \
           --pod-running-timeout="1m" \
           -t \
           -i "nsenter-abc123"

입력 노드 변수에 파드를 배치합니다.

파드는 "privileged": true 옵션을 통해 root 권한으로 접근합니다. 그 후 nsenter 를 통해 프로세스 ID 1에 해당하는 네임스페이스를 공유받습니다.

프로세스 1은 리눅스 시스템에서 일반적으로 init 프로세스로 결국 노드의 네임스페이스를 공유받게 됩니다.

nsenter --target 1 --mount --uts --ipc --net --pid -- bash -l

eksctl를 통해 EKS 클러스터를 생성하고 프로세스를 확인하겠습니다.

eks 클러스터를 구성하고 node-shell 설치를 진행하겠습니다.

# eks.yaml 
---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: cluster-1
  region: ap-northeast-2

nodeGroups:
  - name: ng-1
    instanceType: t3.medium
    desiredCapacity: 1

# 클러스터 구성 (약 15분 소요)
eksctl create cluster -f eks.yaml

# node-shell 설치 
kubectl krew index add kvaps https://github.com/kvaps/krew-index
kubectl krew install kvaps/node-shell 
export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH" 

# node-shell 접속 
kubectl node-shell 

 

파드 안에서 프로세스를 확인하면 다음과 같습니다.

위와 같이 파드의 프로세스와 노드의 프로세스가 동일한 것으로 확인됩니다.

 

 

Node-shell 비활성화 방법

원치않은 노드 접근으로 인해 보안 이슈가 생길 수 있기에 해당 툴을 비활성화할 수 있도록 설정하겠습니다.

핵심은 파드 생성시에 "privileged": true 옵션을 비활성화하는 것입니다.

 

 

Pod Security Admission 설정 방법

Pod Security Admission 은 쿠버네티스 버전 1.25 이상에서 제공하는 기능으로 쿠버네티스에서 Pod에 대한 보안 정책을 적용하는 메커니즘입니다. 네임스페이스에 아래 레이블을 추가하여 Pod 보안 정책을 적용할 수 있습니다.

 

 

Pod Security Admission

An overview of the Pod Security Admission Controller, which can enforce the Pod Security Standards.

kubernetes.io

 

 

해당 옵션을 통해 "privileged": true 비활성화하겠습니다.

 

kubectl label namespace default pod-security.kubernetes.io/enforce=restricted

위 명령은 default 네임스페이스에 대해 restricted 보안 프로파일을 적용합니다.

restricted 프로파일에서는 다음과 같은 보안 정책이 적용됩니다:

  • privileged: true 금지
  • runAsNonRoot 사용자로만 실행 허용
  • 호스트 네트워크, 호스트 PID, 호스트 IPC 사용 금지
  • 호스트 경로 마운트 제한

네임스페이스 default 에 보안정책을 지정하고, 다시 node-shell로 접근해보겠습니다.

접근시 restricted 보안 정책 위반으로 파드 생성이 안되는 것을 확인할 수 있습니다.

  • 호스트 네임스페이스 사용: hostNetwork=true 및 hostPID=true 설정이 금지됨.
  • privileged 사용: privileged=true가 금지됨.
  • allowPrivilegeEscalation: allowPrivilegeEscalation=false로 설정해야 함.
  • capabilities.drop: 모든 capabilities를 제거해야 함 (capabilities.drop=["ALL"]).
  • runAsNonRoot: 컨테이너를 루트가 아닌 사용자로 실행해야 함.
  • seccompProfile: RuntimeDefault 또는 Localhost로 설정해야 함.

 

실습 환경 삭제

위 구성한 EKS 삭제는 다음의 명령어를 통해 삭제해주세요.

 eksctl delete cluster -f eks.yaml