사용자 네임스페이스

사용자 네임스페이스 (User Namespaces)

기능 상태: Kubernetes v1.36 [stable](기본 활성화)

이 페이지는 사용자 네임스페이스가 Kubernetes pod에서 어떻게 사용되는지 설명해요. 사용자 네임스페이스는 컨테이너 안에서 실행되는 사용자를 호스트의 사용자와 격리해요.

컨테이너 안에서 root로 실행되는 프로세스는 호스트에서는 다른(비-root) 사용자로 실행될 수 있어요. 즉, 그 프로세스는 사용자 네임스페이스 안의 작업에 대해서는 완전한 권한을 갖지만, 네임스페이스 밖의 작업에 대해서는 권한이 없어요.

이 기능을 사용하면 손상된 컨테이너가 호스트나 같은 노드의 다른 pod에 줄 수 있는 피해를 줄일 수 있어요. 사용자 네임스페이스가 활성화되어 있을 때 악용할 수 없었던 HIGH 또는 CRITICAL 등급의 보안 취약점이 여러 개 있어요. 사용자 네임스페이스가 앞으로의 일부 취약점도 완화할 것으로 기대돼요.

출처: Kubernetes 공식 문서 — User Namespaces

시작하기 전에 (Before you begin)

참고: 이 섹션은 Kubernetes가 요구하는 기능을 제공하는 서드파티 프로젝트를 링크해요. 쿠버네티스 프로젝트 작성자는 이 프로젝트들에 대해 책임지지 않으며, 목록은 알파벳순으로 나열돼요. 목록에 프로젝트를 추가하려면 변경을 제출하기 전에 내용 가이드를 읽어보세요. 더 많은 정보.

이 기능은 Linux 전용이며, 사용되는 파일시스템에 idmap 마운트에 대한 Linux 지원이 필요해요. 이는 다음을 의미해요.

  • 노드에서 /var/lib/kubelet/pods/에 사용하는 파일시스템이나, 이것을 위해 구성한 커스텀 디렉터리가 idmap 마운트 지원이 필요해요.
  • pod의 볼륨에 사용되는 모든 파일시스템이 idmap 마운트를 지원해야 해요.

실질적으로 이는 최소한 Linux 6.3이 필요하다는 뜻이에요. tmpfs가 그 버전에서 idmap 마운트를 지원하기 시작했기 때문이에요. 여러 Kubernetes 기능이 tmpfs를 사용하므로(기본적으로 마운트되는 서비스 어카운트 토큰이 tmpfs를 사용하고, Secrets가 tmpfs를 사용하는 등) 보통 이게 필요해요.

Linux 6.3에서 idmap 마운트를 지원하는 널리 쓰이는 파일시스템은 btrfs, ext4, xfs, fat, tmpfs, overlayfs예요.

추가로 컨테이너 런타임과 그 밑에 있는 OCI 런타임이 사용자 네임스페이스를 지원해야 해요. 다음 OCI 런타임이 지원을 제공해요.

  • crun 버전 1.9 이상(1.13+ 권장)
  • runc 버전 1.2 이상

Kubernetes에서 사용자 네임스페이스를 사용하려면 Kubernetes pod와 함께 사용하려면 CRI 컨테이너 런타임도 사용해야 해요.

  • containerd: 버전 2.0(이후)이 컨테이너에 대한 사용자 네임스페이스를 지원해요.
  • CRI-O: 버전 1.25(이후)가 컨테이너에 대한 사용자 네임스페이스를 지원해요.

cri-dockerd의 사용자 네임스페이스 지원 상태는 GitHub의 이슈에서 추적할 수 있어요.

소개 (Introduction)

사용자 네임스페이스는 컨테이너의 사용자를 호스트의 다른 사용자로 매핑할 수 있는 Linux 기능이에요. 게다가 사용자 네임스페이스에서 pod에 부여된 capabilities는 그 네임스페이스 안에서만 유효하고 밖에서는 무효해요.

pod는 pod.spec.hostUsers 필드를 false로 설정해 사용자 네임스페이스를 사용하도록 선택할 수 있어요.

kubelet은 pod가 매핑될 호스트 UID/GID를 선택하며, 같은 노드의 두 pod가 같은 매핑을 사용하지 않도록 보장하는 방식으로 선택해요.

pod.specrunAsUser, runAsGroup, fsGroup 등의 필드는 항상 컨테이너 안의 사용자를 가리켜요. 이 사용자들은 볼륨 마운트(pod.spec.volumes에 지정됨)에 사용되므로, 호스트 UID/GID는 pod가 마운트할 수 있는 볼륨의 쓰기/읽기에 영향을 미치지 않아요. 즉, pod는 (볼륨의 파일 소유권에 영향을 주지 않으면서) 사용자 네임스페이스를 쉽게 활성화·비활성화할 수 있고, 컨테이너 안에 적절한 사용자(RunAsUser, RunAsGroup, fsGroup 등)를 설정하기만 하면 사용자 네임스페이스가 없는 pod와 볼륨을 공유할 수도 있어요. 이는 pod가 사용하는 어떤 볼륨에도 적용돼요.

pod의 사용자 네임스페이스 이해하기

기본 구성의 여러 컨테이너 런타임(예: Docker Engine, containerd, CRI-O)은 격리를 위해 Linux 네임스페이스를 사용해요. 그런 런타임과 함께 사용할 수 있는 다른 기술도 존재해요(예: Kata Containers는 Linux 네임스페이스 대신 VM을 사용해요).

pod를 만들 때 기본적으로 여러 새 네임스페이스가 격리를 위해 사용돼요: 컨테이너의 네트워크를 격리하는 네트워크 네임스페이스, 프로세스의 뷰를 격리하는 PID 네임스페이스 등이요. 사용자 네임스페이스가 사용되면 컨테이너의 사용자를 노드의 사용자와 격리해요.

  • CAP_SYS_MODULE은 사용자 네임스페이스를 사용하는 pod에 부여돼도 어떤 효과도 없어요. pod는 커널 모듈을 로드할 수 없어요.
  • CAP_SYS_ADMIN은 pod의 사용자 네임스페이스로 제한되며 그 밖에서는 무효해요.

사용자 네임스페이스를 사용하지 않으면 root로 실행되는 컨테이너는 컨테이너 탈출(breakout)의 경우 노드에서 root 권한을 가져요. 그리고 컨테이너에 어떤 capability가 부여되면 그 capabilities는 호스트에서도 유효해요. 사용자 네임스페이스를 사용하면 이 중 그 어떤 것도 사실이 아니에요.

사용자 네임스페이스 지원을 위한 노드 설정

기본적으로 kubelet은 호스트의 파일과 프로세스가 이 범위 안의 UID/GID를 사용한다는 가정(대부분의 Linux 배포판에 표준)에 기반해, pod에 0-65535 범위 위의 UID/GID를 할당해요. 이 접근 방식은 pod UID/GID가 호스트의 파일 소유자/그룹과 일치하지 않도록 함으로써 pod가 할 수 있는 일을 제한해요.

  • kubelet 사용자의 하위 UID/GID 구성(man 5 subuidman 5 subgid 참고)

  • Pod의 UID 범위를 시작하는 하위 사용자 ID(subordinate user ID)는 반드시 65536의 배수여야 하고 65536 이상이어야 해요. 즉, Pod에 0-65535 범위의 어떤 ID도 사용할 수 없어요. kubelet이 우연히 안전하지 않은 구성을 만들기 어렵게 하기 위해 이 제한을 부과해요.

  • 하위 ID 개수는 65536의 배수여야 해요.

  • 하위 ID 개수는 최소 65536 x <maxPods>여야 해요. 여기서 <maxPods>는 노드에서 실행할 수 있는 최대 pod 수예요.

  • 사용자 ID와 그룹 ID 모두에 같은 범위를 할당해야 해요. 다른 사용자가 그룹 ID 범위와 정렬되지 않는 사용자 ID 범위를 가져도 상관없어요.

  • 할당된 범위 중 어떤 것이든 다른 할당과 겹쳐서는 안 돼요.

  • 하위 구성은 한 줄만이어야 해요.

예를 들어 /etc/subuid/etc/subgid 둘 다에 kubelet 사용자에 대해 이 항목들을 정의할 수 있어요.

# 형식은
#   name:firstID:count of IDs
# 다음 중
# - firstID는 65536 (가능한 최소값)
# - count of IDs는 110 * 65536
#   (110은 노드의 기본 pod 수 제한)

kubelet:65536:7208960

노드를 재구성할 때 참고

사용자 네임스페이스를 사용하는 pod가 실행 중일 수 없는 이유는, 그 pod가 새로 구성된 범위 밖일 수 있는 어떤 범위를 사용할 수 있기 때문이에요. kubelet은 노드의 기존 pod에 대해 새 구성을 존중할 수 없으면 시작에 실패해요.

Pod마다의 ID 개수

Kubernetes v1.33부터 Pod마다의 ID 개수를 KubeletConfiguration에서 설정할 수 있어요.

apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
userNamespaces:
  idsPerPod: 1048576

idsPerPod(uint32)의 값은 65536의 배수여야 해요. 기본값은 65536이에요.

이 값은 kubelet이 이 KubeletConfiguration으로 시작된 후 생성된 컨테이너에만 적용돼요. 실행 중인 컨테이너는 이 구성의 영향을 받지 않아요.

Kubernetes v1.33 이전에는 Pod마다의 ID 개수가 65536으로 하드코딩되어 있었어요.

제한 사항 (Limitations)

pod에 사용자 네임스페이스를 사용할 때는 다른 호스트 네임스페이스를 사용하는 것이 허용되지 않아요. 특히 hostUsers: false를 설정하면 다음 중 어떤 것도 설정할 수 없어요.

  • hostNetwork: true
  • hostIPC: true
  • hostPID: true

어떤 컨테이너도 volumeDevices(원시 블록 볼륨, /dev/sda 같은 것)를 사용할 수 없어요. 여기에는 pod 스펙의 모든 컨테이너 배열이 포함돼요.

  • containers
  • initContainers
  • ephemeralContainers

파일시스템 지원

사용자 네임스페이스를 사용하는 Pod는 파일시스템이 idmap 마운트를 지원해야 해요. 일부 파일시스템은 idmap 마운트를 지원하지 않으므로 사용자 네임스페이스와 함께 사용할 수 없어요. 그런 경우 다음 이벤트가 생성돼요. 경고 세부 사항은 사용 중인 컨테이너 런타임에 따라 다르다는 점을 유의하세요.

NFS 볼륨은 Linux NFS 클라이언트가 아직 idmap 마운트를 지원하지 않기 때문에 사용자 네임스페이스 pod에서 마운트할 수 없어요.

지원되는 파일시스템의 현재 목록은 Linux 커널의 mount_setattr(2) man page를 참고하세요.

메트릭과 관측 가능성 (Metrics and observability)

kubelet은 사용자 네임스페이스에 특화된 두 개의 Prometheus 메트릭을 내보내요.

  • started_user_namespaced_pods_total: 생성이 시도된 사용자 네임스페이스 pod 수를 추적하는 카운터
  • started_user_namespaced_pods_errors_total: 사용자 네임스페이스 pod 생성 중 오류 수를 추적하는 카운터