해당 문서의 쿠버네티스 버전: v1.22

Kubernetes v1.22 문서는 더 이상 적극적으로 관리되지 않음. 현재 보고있는 문서는 정적 스냅샷임. 최신 문서를 위해서는, 다음을 참고. 최신 버전.

윈도우 파드와 컨테이너용 GMSA 구성

FEATURE STATE: Kubernetes v1.18 [stable]

이 페이지는 윈도우 노드에서 실행되는 파드와 컨테이너용으로 그룹 관리 서비스 어카운트(Group Managed Service Accounts, GMSA)를 구성하는 방법을 소개한다. 그룹 관리 서비스 어카운트는 자동 암호 관리, 단순화된 서비스 사용자 이름(service principal name, SPN) 관리, 여러 서버에 걸쳐 다른 관리자에게 관리를 위임하는 기능을 제공하는 특정한 유형의 액티브 디렉터리(Active Directory) 계정이다.

쿠버네티스에서 GMSA 자격 증명 사양은 쿠버네티스 클러스터 전체 범위에서 사용자 정의 리소스(Custom Resources)로 구성된다. 윈도우 파드 및 파드 내의 개별 컨테이너들은 다른 윈도우 서비스와 상호 작용할 때 도메인 기반 기능(예: Kerberos 인증)에 GMSA를 사용하도록 구성할 수 있다. v1.16부터 도커 런타임은 윈도우 워크로드용 GMSA를 지원한다.

시작하기 전에

쿠버네티스 클러스터가 있어야 하며 클러스터와 통신하도록 kubectl 커맨드라인 툴을 구성해야 한다. 클러스터에는 윈도우 워커 노드가 있어야 한다. 이 섹션에서는 각 클러스터에 대해 한 번씩 필요한 일련의 초기 단계를 다룬다.

GMSACredentialSpec CRD 설치

GMSA 자격 증명 사양 리소스에 대한 커스텀리소스데피니션(CustomResourceDefinition, CRD)을 클러스터에서 구성하여 사용자 정의 리소스 유형 GMSACredentialSpec을 정의해야 한다. GMSA CRD YAML을 다운로드하고 gmsa-crd.yaml로 저장한다. 다음, kubectl apply -f gmsa-crd.yaml 로 CRD를 설치한다.

GMSA 사용자를 검증하기 위해 웹훅 설치

쿠버네티스 클러스터에서 두 개의 웹훅을 구성하여 파드 또는 컨테이너 수준에서 GMSA 자격 증명 사양 참조를 채우고 검증한다.

  1. 변형(mutating) 웹훅은 (파드 사양의 이름별로) GMSA에 대한 참조를 파드 사양 내 JSON 형식의 전체 자격 증명 사양으로 확장한다.

  2. 검증(validating) 웹훅은 GMSA에 대한 모든 참조가 파드 서비스 어카운트에서 사용하도록 승인되었는지 확인한다.

위의 웹훅 및 관련 오브젝트를 설치하려면 다음 단계가 필요하다.

  1. 인증서 키 쌍 생성 (웹훅 컨테이너가 클러스터와 통신할 수 있도록 하는데 사용됨)

  2. 위의 인증서로 시크릿을 설치

  3. 핵심 웹훅 로직에 대한 디플로이먼트(deployment)를 생성

  4. 디플로이먼트를 참조하여 검증 및 변경 웹훅 구성을 생성

스크립트를 사용하여 GMSA 웹훅과 위에서 언급한 관련 오브젝트를 배포 및 구성할 수 있다. 스크립트는 --dry-run=server 옵션으로 실행되어 클러스터에 대한 변경 사항을 검토할 수 있다.

스크립트에서 사용하는 YAML 템플릿을 사용하여 웹훅 및 (파라미터를 적절히 대체하여) 관련 오브젝트를 수동으로 배포할 수도 있다.

액티브 디렉터리에서 GMSA 및 윈도우 노드 구성

쿠버네티스의 파드가 GMSA를 사용하도록 구성되기 전에 윈도우 GMSA 문서에 설명된 대로 액티브 디렉터리에서 원하는 GMSA를 프로비저닝해야 한다. 윈도우 GMSA 문서에 설명된 대로 원하는 GMSA와 연결된 시크릿 자격 증명에 접근하려면 (쿠버네티스 클러스터의 일부인) 윈도우 워커 노드를 액티브 디렉터리에서 구성해야 한다.

GMSA 자격 증명 사양 리소스 생성

(앞에서 설명한 대로) GMSACredentialSpec CRD를 설치하면 GMSA 자격 증명 사양이 포함된 사용자 정의 리소스를 구성할 수 있다. GMSA 자격 증명 사양에는 시크릿 또는 민감한 데이터가 포함되어 있지 않다. 이것은 컨테이너 런타임이 원하는 윈도우 컨테이너 GMSA를 설명하는 데 사용할 수 있는 정보이다. GMSA 자격 증명 사양은 PowerShell 스크립트 유틸리티를 사용하여 YAML 형식으로 생성할 수 있다.

다음은 JSON 형식으로 GMSA 자격 증명 사양 YAML을 수동으로 생성한 다음 변환하는 단계이다.

  1. CredentialSpec 모듈 가져오기(import): ipmo CredentialSpec.psm1

  2. New-CredentialSpec을 사용하여 JSON 형식의 자격 증명 사양을 만든다. WebApp1이라는 GMSA 자격 증명 사양을 만들려면 New-CredentialSpec -Name WebApp1 -AccountName WebApp1 -Domain $(Get-ADDomain -Current LocalComputer)를 호출한다.

  3. Get-CredentialSpec을 사용하여 JSON 파일의 경로를 표시한다.

  4. credspec 파일을 JSON에서 YAML 형식으로 변환하고 필요한 헤더 필드 apiVersion, kind, metadata, credspec을 적용하여 쿠버네티스에서 구성할 수 있는 GMSACredentialSpec 사용자 정의 리소스로 만든다.

다음 YAML 구성은 gmsa-WebApp1이라는 GMSA 자격 증명 사양을 설명한다.

apiVersion: windows.k8s.io/v1alpha1
kind: GMSACredentialSpec
metadata:
  name: gmsa-WebApp1  #임의의 이름이지만 참조로 사용된다.
credspec:
  ActiveDirectoryConfig:
    GroupManagedServiceAccounts:
    - Name: WebApp1   #GMSA 계정의 사용자 이름
      Scope: CONTOSO  #NETBIOS 도메인 명
    - Name: WebApp1   #GMSA 계정의 사용자 이름
      Scope: contoso.com #DNS 도메인 명
  CmsPlugins:
  - ActiveDirectory
  DomainJoinConfig:
    DnsName: contoso.com  #DNS 도메인 명
    DnsTreeName: contoso.com #DNS 도메인 명 루트
    Guid: 244818ae-87ac-4fcd-92ec-e79e5252348a  #GUID
    MachineAccountName: WebApp1 #GMSA 계정의 사용자 이름
    NetBiosName: CONTOSO  #NETBIOS 도메인 명
    Sid: S-1-5-21-2126449477-2524075714-3094792973 #SID of GMSA

위의 자격 증명 사양 리소스는 gmsa-Webapp1-credspec.yaml로 저장되고 kubectl apply -f gmsa-Webapp1-credspec.yml을 사용하여 클러스터에 적용될 수 있다.

특정 GMSA 자격 증명 사양에서 RBAC를 활성화하도록 cluster role 구성

각 GMSA 자격 증명 사양 리소스에 대해 cluster role을 정의해야 한다. 이것은 일반적으로 서비스 어카운트인 주체에 의해 특정 GMSA 리소스에 대한 use 동사를 승인한다. 다음 예는 위에서 gmsa-WebApp1 자격 증명 사양의 사용을 승인하는 클러스터 롤(cluster role)을 보여준다. 파일을 gmsa-webapp1-role.yaml로 저장하고 kubectl apply -f gmsa-webapp1-role.yaml을 사용하여 적용한다.

#credspec을 읽을 Role 생성
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: webapp1-role
rules:
- apiGroups: ["windows.k8s.io"]
  resources: ["gmsacredentialspecs"]
  verbs: ["use"]
  resourceNames: ["gmsa-WebApp1"]

특정 GMSA credspecs를 사용하도록 서비스 어카운트에 롤 할당

(파드가 사용하게 되는) 서비스 어카운트는 위에서 생성한 클러스터 롤에 바인딩되어야 한다. 이렇게 하면 서비스 어카운트가 원하는 GMSA 자격 증명 사양 리소스를 사용할 수 있다. 다음은 위에서 생성한 gmsa-WebApp1 자격 증명 사양 리소스를 사용하기 위해 webapp1-role 클러스터 롤에 바인딩되는 기본(default) 서비스 어카운트이다.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: allow-default-svc-account-read-on-gmsa-WebApp1
  namespace: default
subjects:
- kind: ServiceAccount
  name: default
  namespace: default
roleRef:
  kind: ClusterRole
  name: webapp1-role
  apiGroup: rbac.authorization.k8s.io

파드 사양에서 GMSA 자격 증명 사양 참조 구성

파드 사양 필드 securityContext.windowsOptions.gmsaCredentialSpecName은 파드 사양에서 원하는 GMSA 자격 증명 사양 사용자 정의 리소스에 대한 참조를 지정하는 데 사용된다. 이렇게 하면 지정된 GMSA를 사용하도록 파드 사양의 모든 컨테이너가 구성된다. 다음은 gmsa-WebApp1을 참조하도록 채워진 어노테이션이 있는 샘플 파드 사양이다.

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: with-creds
  name: with-creds
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      run: with-creds
  template:
    metadata:
      labels:
        run: with-creds
    spec:
      securityContext:
        windowsOptions:
          gmsaCredentialSpecName: gmsa-webapp1
      containers:
      - image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
        imagePullPolicy: Always
        name: iis
      nodeSelector:
        kubernetes.io/os: windows

파드 사양의 개별 컨테이너는 컨테이너별 securityContext.windowsOptions.gmsaCredentialSpecName 필드를 사용하여 원하는 GMSA credspec을 지정할 수도 있다. 다음은 예이다.

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: with-creds
  name: with-creds
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      run: with-creds
  template:
    metadata:
      labels:
        run: with-creds
    spec:
      containers:
      - image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
        imagePullPolicy: Always
        name: iis
        securityContext:
          windowsOptions:
            gmsaCredentialSpecName: gmsa-Webapp1
      nodeSelector:
        kubernetes.io/os: windows

(위에서 설명한 대로) GMSA 필드가 채워진 파드 사양이 클러스터에 적용되면 다음과 같은 일련의 이벤트가 발생한다.

  1. 변형 웹훅은 GMSA 자격 증명 사양 리소스에 대한 모든 참조를 확인하고 GMSA 자격 증명 사양의 내용으로 확장한다.

  2. 검증 웹훅은 파드와 연결된 서비스 어카운트가 지정된 GMSA 자격 증명 사양의 use 동사에 대해 승인되었는지 확인한다.

  3. 컨테이너 런타임은 컨테이너가 액티브 디렉터리에서 GMSA의 ID를 가정하고 해당 ID를 사용하여 도메인의 서비스에 접근할 수 있도록 지정된 GMSA 자격 증명 사양으로 각 윈도우 컨테이너를 구성한다.

Containerd

윈도우 서버 2019에서 containerd와 함께 GMSA를 사용하려면 패치 KB5000822된 OS Build 17763.1817 (또는 이후 버전)을 실행해야 한다.

또한 파드에서 SMB 공유에 연결하려고 할 때 발생하는 containerd와 관련된 알려진 문제가 있다. GMSA를 구성하면 파드가 hostname 또는 FQDN을 사용하여 공유에 연결할 수 없지만, IP 주소를 사용하여 공유에 연결하면 예상대로 작동한다.

ping adserver.ad.local

hostname을 IPv4 주소로 올바르게 변환한다. 출력은 다음과 유사하다.

Pinging adserver.ad.local [192.168.111.18] with 32 bytes of data:
Reply from 192.168.111.18: bytes=32 time=6ms TTL=124
Reply from 192.168.111.18: bytes=32 time=5ms TTL=124
Reply from 192.168.111.18: bytes=32 time=5ms TTL=124
Reply from 192.168.111.18: bytes=32 time=5ms TTL=124

그러나 hostname을 사용하여 디렉터리를 탐색하려고 할 때

cd \\adserver.ad.local\test

대상 공유가 존재하지 않음을 암시하는 오류가 표시된다.

cd : Cannot find path '\\adserver.ad.local\test' because it does not exist.
At line:1 char:1
+ cd \\adserver.ad.local\test
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (\\adserver.ad.local\test:String) [Set-Location], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.SetLocationCommand

그러나 IPv4 주소를 대신 사용하여 공유를 탐색하면 오류가 사라진다. 다음은 예시이다.

cd \\192.168.111.18\test

공유 내의 디렉터리로 변경하면 다음과 유사한 프롬프트가 표시된다.

Microsoft.PowerShell.Core\FileSystem::\\192.168.111.18\test>

동작을 수정하려면 노드에서 reg add "HKLM\SYSTEM\CurrentControlSet\Services\hns\State" /v EnableCompartmentNamespace /t REG_DWORD /d 1을 실행하여 필요한 레지스트리 키를 추가해야 한다. 이 노드 변경 사항은 새로 생성된 파드에만 적용되는데, SMB 공유에 액세스해야 하는 실행 중인 파드를 다시 생성해야 하는 것을 의미한다.

문제 해결

GMSA가 사용자 환경에서 작동하도록 하는 데 어려움이 있는 경우 취할 수 있는 몇 가지 문제 해결 단계가 있다.

먼저 credspec이 파드에 전달되었는지 확인한다. 이렇게 하려면 파드 중 하나에서 exec를 실행하고 nltest.exe /parentdomain 명령의 출력을 확인해야 한다.

아래 예에서 파드는 credspec을 올바르게 가져오지 못했다.

kubectl exec -it iis-auth-7776966999-n5nzr powershell.exe

nltest.exe /parentdomain 는 다음과 같은 오류를 발생시킨다.

Getting parent domain failed: Status = 1722 0x6ba RPC_S_SERVER_UNAVAILABLE

파드가 credspec을 올바르게 가져오면 다음으로 도메인과의 통신을 확인한다. 먼저 파드 내부에서 nslookup을 빠르게 수행하여 도메인의 루트를 찾는다.

이것은 다음의 세 가지를 의미한다.

  1. 파드는 DC에 도달할 수 있다.
  2. DC는 파드에 도달할 수 있다.
  3. DNS가 올바르게 작동하고 있다.

DNS 및 통신 테스트를 통과하면 다음으로 파드가 도메인과 보안 채널 통신을 설정했는지 확인해야 한다. 이렇게 하려면 파드에서 다시 exec를 실행하고 nltest.exe /query 명령을 실행한다.

nltest.exe /query

결과는 다음과 같다.

I_NetLogonControl failed: Status = 1722 0x6ba RPC_S_SERVER_UNAVAILABLE

이것은 어떤 이유로 파드가 credspec에 지정된 계정을 사용하여 도메인에 로그온할 수 없음을 알려준다. 다음을 실행하여 보안 채널 복구를 시도할 수 있다.

nltest /sc_reset:domain.example

명령이 성공하면 다음과 유사한 출력이 표시된다.

Flags: 30 HAS_IP  HAS_TIMESERV
Trusted DC Name \\dc10.domain.example
Trusted DC Connection Status Status = 0 0x0 NERR_Success
The command completed successfully

위의 방법으로 오류가 수정되면 다음 수명 주기 훅(hook)을 파드 사양에 추가하여 단계를 자동화할 수 있다. 오류가 수정되지 않은 경우 credspec을 다시 검사하여 정확하고 완전한지 확인해야 한다.

        image: registry.domain.example/iis-auth:1809v1
        lifecycle:
          postStart:
            exec:
              command: ["powershell.exe","-command","do { Restart-Service -Name netlogon } while ( $($Result = (nltest.exe /query); if ($Result -like '*0x0 NERR_Success*') {return $true} else {return $false}) -eq $false)"]
        imagePullPolicy: IfNotPresent

위의 lifecycle 섹션을 파드 사양에 추가하면, 파드는 nltest.exe /query 명령이 오류 없이 종료될 때까지 나열된 명령을 실행하여 netlogon 서비스를 다시 시작한다.