为 Windows Pod 和容器配置 GMSA

功能状态: Kubernetes v1.18 [稳定]

此页面介绍如何为将在 Windows 节点上运行的 Pod 和容器配置 组托管服务帐户 (GMSA)。组托管服务帐户是 Active Directory 帐户的一种特定类型,它提供自动密码管理、简化的服务主体名称 (SPN) 管理以及将管理委托给跨多个服务器的其他管理员的能力。

在 Kubernetes 中,GMSA 凭据规范在 Kubernetes 集群范围内的自定义资源中进行配置。Windows Pod 以及 Pod 中的单个容器可以配置为使用 GMSA 执行基于域的功能(例如 Kerberos 身份验证)以与其他 Windows 服务进行交互。

开始之前

您需要拥有一个 Kubernetes 集群,并且 kubectl 命令行工具必须配置为与您的集群通信。预计集群将拥有 Windows 工作节点。本节介绍每个集群首次运行时所需的步骤集。

安装 GMSACredentialSpec CRD

需要在集群上配置 自定义资源定义(CRD) 用于 GMSA 凭据规范资源,以定义自定义资源类型 GMSACredentialSpec。下载 GMSA CRD YAML 并将其保存为 gmsa-crd.yaml。接下来,使用 kubectl apply -f gmsa-crd.yaml 安装 CRD。

安装 Webhook 以验证 GMSA 用户

需要在 Kubernetes 集群上配置两个 Webhook,以填充和验证 Pod 或容器级别的 GMSA 凭据规范引用。

  1. 一个变异 Webhook,它将对 GMSA 的引用(通过 Pod 规范中的名称)扩展为 Pod 规范中的 JSON 格式的完整凭据规范。

  2. 一个验证 Webhook 确保对 GMSA 的所有引用都被授权在 Pod 服务帐户中使用。

安装上述 Webhook 和相关对象需要以下步骤

  1. 创建一个证书密钥对(用于允许 Webhook 容器与集群通信)

  2. 使用上述证书安装一个密钥。

  3. 为核心 Webhook 逻辑创建一个部署。

  4. 创建验证和变异 Webhook 配置,引用该部署。

一个 脚本 可用于部署和配置上述提到的 GMSA Webhook 和相关对象。该脚本可以使用 --dry-run=server 选项运行,允许您查看将对集群进行的更改。

脚本使用的 YAML 模板 也可用于手动部署 Webhook 和相关对象(对参数进行适当替换)。

在 Active Directory 中配置 GMSA 和 Windows 节点

在 Kubernetes 中的 Pod 可以配置为使用 GMSA 之前,需要根据 Windows GMSA 文档 在 Active Directory 中预配所需的 GMSA。需要在 Active Directory 中配置 Windows 工作节点(属于 Kubernetes 集群的一部分)以访问与所需 GMSA 关联的秘密凭据,如 Windows GMSA 文档 中所述。

创建 GMSA 凭据规范资源

安装 GMSACredentialSpec CRD 后(如前所述),可以配置包含 GMSA 凭据规范的自定义资源。GMSA 凭据规范不包含秘密或敏感数据。它是容器运行时可用于描述容器所需 GMSA 的信息。可以使用实用程序 PowerShell 脚本 以 YAML 格式生成 GMSA 凭据规范。

以下是手动以 JSON 格式生成 GMSA 凭据规范 YAML 然后将其转换的步骤。

  1. 导入 CredentialSpec 模块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 格式,并应用必要的标头字段 apiVersionkindmetadatacredspec,使其成为可以在 Kubernetes 中配置的 GMSACredentialSpec 自定义资源。

以下 YAML 配置描述了名为 gmsa-WebApp1 的 GMSA 凭据规范

apiVersion: windows.k8s.io/v1
kind: GMSACredentialSpec
metadata:
  name: gmsa-WebApp1  # This is an arbitrary name but it will be used as a reference
credspec:
  ActiveDirectoryConfig:
    GroupManagedServiceAccounts:
    - Name: WebApp1   # Username of the GMSA account
      Scope: CONTOSO  # NETBIOS Domain Name
    - Name: WebApp1   # Username of the GMSA account
      Scope: contoso.com # DNS Domain Name
  CmsPlugins:
  - ActiveDirectory
  DomainJoinConfig:
    DnsName: contoso.com  # DNS Domain Name
    DnsTreeName: contoso.com # DNS Domain Name Root
    Guid: 244818ae-87ac-4fcd-92ec-e79e5252348a  # GUID of the Domain
    MachineAccountName: WebApp1 # Username of the GMSA account
    NetBiosName: CONTOSO  # NETBIOS Domain Name
    Sid: S-1-5-21-2126449477-2524075714-3094792973 # SID of the Domain

上述凭据规范资源可以保存为 gmsa-Webapp1-credspec.yaml,并使用以下命令应用到集群:kubectl apply -f gmsa-Webapp1-credspec.yml

配置集群角色以启用特定 GMSA 凭据规范上的 RBAC

需要为每个 GMSA 凭据规范资源定义一个集群角色。这授权主体(通常是服务帐户)对特定 GMSA 资源使用 use 动词。以下示例显示了一个集群角色,它授权从上述示例中使用 gmsa-WebApp1 凭据规范。将文件保存为 gmsa-webapp1-role.yaml 并使用 kubectl apply -f gmsa-webapp1-role.yaml 应用。

# Create the Role to read the credspec
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 凭据规范

需要将一个服务帐户(Pod 将使用该服务帐户进行配置)绑定到上述创建的集群角色。这授权服务帐户使用所需的 GMSA 凭据规范资源。以下示例显示默认服务帐户绑定到一个集群角色 webapp1-role 以使用上面创建的 gmsa-WebApp1 凭据规范资源。

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

在 Pod 规范中配置 GMSA 凭据规范引用

Pod 规范字段 securityContext.windowsOptions.gmsaCredentialSpecName 用于在 Pod 规范中指定对所需 GMSA 凭据规范自定义资源的引用。这将配置 Pod 规范中的所有容器以使用指定的 GMSA。一个示例 Pod 规范,其中注释已填充以引用 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

Pod 规范中的单个容器也可以使用每个容器的 securityContext.windowsOptions.gmsaCredentialSpecName 字段指定所需的 GMSA 凭据规范。例如

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 字段的 Pod 规范(如上所述)时,将发生以下事件序列

  1. 变异 Webhook 会解析并扩展对 GMSA 凭据规范资源的所有引用,使其成为 GMSA 凭据规范的内容。

  2. 验证 Webhook 确保与 Pod 关联的服务帐户被授权在指定的 GMSA 凭据规范上使用 use 动词。

  3. 容器运行时使用指定的 GMSA 凭据规范配置每个 Windows 容器,以便容器可以在 Active Directory 中假定 GMSA 的身份,并使用该身份访问域中的服务。

使用主机名或 FQDN 身份验证到网络共享

如果您在使用主机名或 FQDN 从 Pod 连接到 SMB 共享时遇到问题,但能够通过其 IPv4 地址访问共享,请确保在 Windows 节点上设置以下注册表项。

reg add "HKLM\SYSTEM\CurrentControlSet\Services\hns\State" /v EnableCompartmentNamespace /t REG_DWORD /d 1

然后需要重新创建运行中的 Pod 以获取行为更改。有关此注册表项如何使用的更多信息,请参阅 此处

故障排除

如果您在环境中使用 GMSA 时遇到困难,您可以尝试以下几个故障排除步骤。

首先,确保凭据规范已传递到 Pod。为此,您需要 exec 到其中一个 Pod 并检查 nltest.exe /parentdomain 命令的输出。

在以下示例中,Pod 未正确获取凭据规范

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

nltest.exe /parentdomain 导致以下错误

Getting parent domain failed: Status = 1722 0x6ba RPC_S_SERVER_UNAVAILABLE

如果您的 Pod 正确获取了凭据规范,那么接下来检查与域的通信。首先,从 Pod 内部,快速执行 nslookup 以查找域的根目录。

这将告诉我们 3 件事

  1. Pod 可以访问 DC
  2. DC 可以访问 Pod
  3. DNS 工作正常。

如果 DNS 和通信测试通过,接下来您需要检查 Pod 是否已与域建立安全通道通信。为此,再次 exec 到您的 Pod 中并运行 nltest.exe /query 命令。

nltest.exe /query

导致以下输出

I_NetLogonControl failed: Status = 1722 0x6ba RPC_S_SERVER_UNAVAILABLE

这告诉我们,由于某种原因,Pod 无法使用凭据规范中指定的帐户登录到域。您可以尝试通过运行以下命令来修复安全通道

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

如果上述操作纠正了错误,则可以通过将以下生命周期挂钩添加到 Pod 规范中来自动执行此步骤。如果它没有纠正错误,则需要再次检查您的凭据规范并确认它是否正确且完整。

        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 部分添加到 Pod 规范中,Pod 将执行列出的命令以重新启动 netlogon 服务,直到 nltest.exe /query 命令在没有错误的情况下退出。

上次修改时间:2024 年 7 月 10 日 下午 2:05 PST:修复 gMSA 凭据规范定义 (97bd20e5a9)