Kubernetes v1.35: 세밀한 보조 그룹 제어가 GA로 승격

발행: (2025년 12월 24일 오전 03:30 GMT+9)
9 min read

Source: Kubernetes Blog

졸업 알림

Kubernetes SIG Node를 대표하여, fine‑grained supplemental groups controlKubernetes v1.35에서 General Availability (GA) 로 졸업하게 되었음을 알려드립니다!

  • 새로운 pod 필드 supplementalGroupsPolicyv1.31에서 opt‑in alpha 기능으로 도입되었으며, v1.33에서 beta 로 졸업했고, 이제 GA 입니다.
  • 이 기능은 Linux 컨테이너의 supplemental groups에 대한 정밀한 제어를 제공하여 보안을 강화합니다—특히 볼륨에 접근할 때.
  • 또한 컨테이너 내부의 UID/GID 세부 정보를 투명하게 하여 보안 관리가 향상됩니다.

업그레이드 참고v1.32 이하 버전에서 업그레이드하는 경우, 베타(v1.33) 이후 도입된 동작상의 호환성 깨짐을 유의하시기 바랍니다. 자세한 내용은 이전 블로그의 behavioral changesupgrade considerations 섹션을 참고하십시오.

Motivation: Implicit group memberships defined in /etc/group

많은 클러스터 관리자/사용자는 눈치채지 못할 수도 있지만, Kubernetes는 기본적으로 파드의 그룹 정보를 컨테이너 이미지 내부의 /etc/group 파일과 병합합니다.

Example manifest

apiVersion: v1
kind: Pod
metadata:
  name: implicit-groups-example
spec:
  securityContext:
    runAsUser: 1000          # UID
    runAsGroup: 3000         # primary GID
    supplementalGroups: [4000]
  containers:
  - name: example-container
    image: registry.k8s.io/e2e-test-images/agnhost:2.45
    command: ["sh", "-c", "sleep 1h"]
    securityContext:
      allowPrivilegeEscalation: false

What does id show inside the container?

uid=1000 gid=3000 groups=3000,4000,50000

50000 GID는 파드 매니페스트에 정의되어 있지 않음에도 나타납니다.

이는 컨테이너 이미지의 /etc/group 파일에서 온 것입니다:

user-defined-in-image:x:1000:
group-defined-in-image:x:50000:user-defined-in-image

주 사용자(UID 1000)는 그룹 50000에 속해 있으므로, Kubernetes는 해당 그룹을 컨테이너의 보조 그룹에 암묵적으로 병합합니다.

Why is this a problem?

  • 암묵적인 GID는 정책 엔진에 보이지 않으며, 파드 스펙에 나타나지 않습니다.
  • 특히 볼륨에 접근할 때 예기치 않은 접근 제어 문제를 일으킬 수 있습니다(see kubernetes/kubernetes#112879).

세분화된 보조 그룹 제어 – supplementalGroupsPolicy

Pod의 .spec.securityContext에 이제 supplementalGroupsPolicy 필드가 포함됩니다. 이 필드는 Kubernetes가 컨테이너 프로세스에 대한 보조 그룹을 어떻게 계산할지 결정합니다.

정책설명
Merge (기본)기존 동작을 유지합니다 – 기본 사용자의 /etc/group 에서 가져온 그룹 멤버십이 병합되어 Pod에 정의된 그룹과 함께 적용됩니다.
StrictfsGroup, supplementalGroups, runAsGroup 에 명시된 GID만 적용됩니다. /etc/group 에서 가져온 그룹 멤버십은 무시됩니다.

Strict 정책 예시

apiVersion: v1
kind: Pod
metadata:
  name: strict-supplementalgroups-policy-example
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    supplementalGroups: [4000]
    supplementalGroupsPolicy: Strict
  containers:
  - name: example-container
    image: registry.k8s.io/e2e-test-images/agnhost:2.45
    command: ["sh", "-c", "sleep 1h"]
    securityContext:
      allowPrivilegeEscalation: false

컨테이너 내부에서 id 명령을 실행하면 다음과 같이 표시됩니다:

uid=1000 gid=3000 groups=3000,4000

원하지 않는 그룹 50000이 더 이상 나타나지 않습니다.

supplementalGroupsPolicy: Strict 를 적용하면(예: 정책 엔진을 통해) 암묵적인 보조 그룹이 Pod에 추가되는 것을 방지할 수 있습니다.

Note: 충분한 권한을 가진 컨테이너는 시작 후에도 프로세스 ID를 변경할 수 있습니다. supplementalGroupsPolicy초기 프로세스 ID에만 영향을 미칩니다.

Pod 상태에서 연결된 프로세스 ID 노출

이 기능은 초기 프로세스 ID를 pod 상태에 추가합니다:

status:
  containerStatuses:
  - name: ctr
    user:
      linux:
        uid: 1000
        gid: 3000
        supplementalGroups:
        - 3000
        - 4000

Important: status.containerStatuses[].user.linux에 있는 값은 첫 번째 연결된 ID를 나타냅니다. 컨테이너가 setuid(2), setgid(2), setgroups(2) 등을 호출할 수 있다면, 이후에 ID를 변경할 수 있어 실제 런타임 ID가 동적으로 변할 수 있습니다.

특권 상승 완화

컨테이너가 ID를 변경하는 능력을 제한하려면 다음과 같은 간단한 완화 방안을 고려하십시오:

  1. 컨테이너의 securityContext에서 privilege: falseallowPrivilegeEscalation: false설정합니다.
  2. Pod Security StandardsRestricted 정책에 맞추어 pod를 구성합니다.

TL;DR

  • supplementalGroupsPolicy (v1.35에서 GA) 는 기존 Merge 동작과 숨겨진 그룹 멤버십을 제거하는 Strict 모드 중 하나를 선택할 수 있게 합니다.
  • Strict(또는 정책을 통해 강제 적용) 를 사용하여 /etc/group 에서 암시적으로 포함되는 그룹으로 인한 보안 예기치 못한 상황을 방지하세요.
  • 초기 ID가 이제 pod 상태에 표시되어 그룹 할당을 감사하고 검증하는 데 도움이 됩니다.

개요

  • kubelet은 NRI 플러그인이나 컨테이너 런타임의 내부 작동을 볼 수 없습니다.
  • 클러스터 관리자(또는 로컬‑admin 권한을 가진 고권한 워크로드)는 모든 파드의 보조 그룹을 변경할 수 있습니다.
  • 이는 Kubernetes 제어 범위를 벗어나며 보안 강화된 노드에서는 고려할 필요가 없습니다.

Strict Policy Requires Up‑to‑Date Container Runtimes

고수준 컨테이너 런타임(예: containerd, CRI‑O)은 컨테이너에 연결될 보조 그룹 ID를 계산하는 역할을 담당합니다. 따라서 supplementalGroupsPolicy: Strict는 이 기능을 지원하는 CRI 런타임이 필요합니다.

  • 이전 동작(supplementalGroupsPolicy: Merge)은 해당 기능을 지원하지 않는 런타임에서도 작동합니다. 이는 완전히 이전 버전과 호환되기 때문입니다.

Supported CRI Runtimes

RuntimeMinimum Version
containerdv2.0 or later
CRI‑Ov1.31 or later

기능 지원 확인

노드에서 해당 기능이 활성화되어 있는지 확인하려면 status.features.supplementalGroupsPolicy 필드를 사용합니다 (KEP‑5328: Node Declared Features에서 도입된 status.declaredFeatures와는 다릅니다).

apiVersion: v1
kind: Node
...
status:
  features:
    supplementalGroupsPolicy: true

모범 사례

  • 컨테이너 런타임이 이 기능을 보편적으로 채택함에 따라, 많은 보안 정책이 더 강력한 보안을 위해 Strict 동작을 적용하기 시작할 것입니다.
  • 이미지에 내장된 기본값에 의존하지 말고 Pod 사양에 모든 보조 그룹을 명시적으로 선언하여 이 적용에 대비하십시오.

참여하기

이 개선은 SIG Node 커뮤니티에 의해 주도되었습니다.
토론에 참여하고, 아이디어를 공유하며, 이 기능 및 관련 주제에 대한 피드백을 제공해 주세요. 커뮤니티는 여러분의 의견을 기다리고 있습니다!


자세히 알아보기

  • Pod 또는 컨테이너에 대한 보안 컨텍스트 구성supplementalGroupsPolicy에 대한 자세한 안내.
  • KEP‑3619세분화된 SupplementalGroups 제어.
Back to Blog

관련 글

더 보기 »

Kubernetes v1.35: Job Managed By가 GA

외부 Job 컨트롤러가 Kubernetes v1.35에서 GA에 도달했습니다. Kubernetes v1.35에서는 spec.managedBy 필드를 통해 외부 Job 컨트롤러를 지정할 수 있는 기능이 g...