对 Windows 容器的 gMSA 进行故障排除

适用于:Windows Server 2022、Windows Server 2019

已知问题

容器主机名必须与 Windows Server 2016 和 Windows 10 版本 1709 和 1803 的 gMSA 名称匹配

如果你运行的是 Windows Server 2016 版本 1709 或 1803,则容器的主机名必须与 gMSA SAM 帐户名称匹配。

当主机名与 gMSA 名称不匹配时,入站 NTLM 身份验证请求和名称/SID 转换(由许多库使用,例如 ASP.NET 成员身份角色提供程序)会失败。 即使主机名与 gMSA 名称不匹配,Kerberos 也会正常运行。

此限制在 Windows Server 2019 中已修复。目前,容器在网络上将始终使用其 gMSA 名称,不管分配的主机名是什么。

在 Windows Server 2016 和 Windows 10 版本 1709 和 1803 上,将一个 gMSA 同时用于多个容器会导致出现间歇性故障

因为所有容器都需要使用相同的主机名,所以有另一个问题影响 Windows Server 2019 和 Windows 10 版本 1809 之前的 Windows 版本。 如果为多个容器分配了相同的标识和主机名,则当两个容器同时与同一域控制器通信时,可能会出现争用情况。 当另一个容器与同一域控制器通信时,它会取消与使用相同标识的任何先前容器的通信。 这可能会导致间歇性的身份验证失败。当你在容器内运行 nltest /sc_verify:contoso.com 时,这有时可能会表现为信任失败。

我们在 Windows Server 2019 中更改了此行为,将容器标识与计算机名称分开,允许多个容器同时使用同一 gMSA。 因此,在 Windows Server 2019 中,可在同一个或多个主机上运行多个具有相同标识的容器。

在 Windows 10 版本 1703、1709 和 1803 上,不能将 gMSA 用于 Hyper-V 隔离容器

在 Windows 10 和 Windows Server 版本 1703、1709 和 1803 上,尝试将 gMSA 用于 Hyper-V 隔离容器时,容器初始化会挂起或失败。

此 bug 在 Windows Server 2019 和 Windows 10 版本 1809 中已修复。 在 Windows Server 2016 和 Windows 10 版本 1607 上,你也可以通过 gMSA 运行 Hyper-V 隔离容器。

常规故障排除指南

如果通过 gMSA 运行容器时遇到错误,则以下说明可能有助于你查明根本原因。

加入域的主机:确保主机可以使用 gMSA

  1. 验证主机是否已加入域,以及是否可以访问域控制器。

  2. 从 RSAT 安装 AD PowerShell 工具并运行 Test-ADServiceAccount,以查看计算机是否有权检索 gMSA。 如果该 cmdlet 返回 False,则计算机无权访问 gMSA 密码。

    # To install the AD module on Windows Server, run Install-WindowsFeature RSAT-AD-PowerShell
    # To install the AD module on Windows 10 version 1809 or later, run Add-WindowsCapability -Online -Name 'Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0'
    # To install the AD module on older versions of Windows 10, see https://aka.ms/rsat
    
    Test-ADServiceAccount WebApp01
    
  3. 如果 Test-ADServiceAccount 返回 False,请验证主机是否属于可以访问 gMSA 密码的安全组。

    # Get the current computer's group membership
    Get-ADComputer $env:computername | Get-ADPrincipalGroupMembership | Select-Object DistinguishedName
    
    # Get the groups allowed to retrieve the gMSA password
    # Change "WebApp01" for your own gMSA name
    (Get-ADServiceAccount WebApp01 -Properties PrincipalsAllowedToRetrieveManagedPassword).PrincipalsAllowedToRetrieveManagedPassword
    
  4. 如果你的主机属于有权检索 gMSA 密码的安全组但执行 Test-ADServiceAccount 时仍然失败,则可能需要重启计算机以获取反映其当前组成员身份的新票证。

未加入域的主机:确保主机已配置为检索 gMSA 帐户

验证主机上是否已正确安装用于在未加入域的容器主机上使用 gMSA 的插件。 Windows 不包含内置插件,需要你提供可实现 ICcgDomainAuthCredentials 接口的插件。 安装详细信息特定于插件。

检查凭据规范文件

  1. CredentialSpec PowerShell 模块运行 Get-CredentialSpec,找到计算机上的所有凭据规范。 凭据规范必须存储在 Docker 根目录下的“CredentialSpecs”目录中。 可以通过运行 docker info -f "{{.DockerRootDir}}" 找到 Docker 根目录。

  2. 打开 CredentialSpec 文件,确保已正确填写以下字段:

    1. 对于已加入域的容器主机:

      • Sid:域的 SID
      • MachineAccountName:gMSA SAM 帐户名称(不包括完整域名,也不包括美元符号)
      • DnsTreeName:Active Directory 林的 FQDN
      • DnsName:gMSA 所属域的 FQDN
      • NetBiosName:gMSA 所属域的 NETBIOS 名称
      • GroupManagedServiceAccounts/Name:gMSA SAM 帐户名称(不包括完整域名,也不包括美元符号)
      • GroupManagedServiceAccounts/Scope:一个条目用于域 FQDN,一个条目用于 NETBIOS

      你的输入应当类似于以下完整凭据规范示例:

      {
          "CmsPlugins": [
              "ActiveDirectory"
          ],
          "DomainJoinConfig": {
              "Sid": "S-1-5-21-702590844-1001920913-2680819671",
              "MachineAccountName": "webapp01",
              "Guid": "56d9b66c-d746-4f87-bd26-26760cfdca2e",
              "DnsTreeName": "contoso.com",
              "DnsName": "contoso.com",
              "NetBiosName": "CONTOSO"
          },
          "ActiveDirectoryConfig": {
              "GroupManagedServiceAccounts": [
                  {
                      "Name": "webapp01",
                      "Scope": "contoso.com"
                  },
                  {
                      "Name": "webapp01",
                      "Scope": "CONTOSO"
                  }
              ]
          }
      }
      
    2. 对于未加入域的主机:除了所有未加入域的容器主机字段之外,还要确保存在“HostAccountConfig”部分,并且正确定义了下面的字段。

      • PortableCcgVersion:应设置为“1”。
      • PluginGUID:ccg.exe 插件的 COM CLSID。 这对于所使用的插件是唯一的。
      • PluginInput:插件特定的输入,用于从机密存储中检索用户帐户信息。

      你的输入应当类似于以下完整凭据规范示例:

      {
          "CmsPlugins": [
          "ActiveDirectory"
          ],
          "DomainJoinConfig": {
              "Sid": "S-1-5-21-702590844-1001920913-2680819671",
              "MachineAccountName": "webapp01",
              "Guid": "56d9b66c-d746-4f87-bd26-26760cfdca2e",
              "DnsTreeName": "contoso.com",
              "DnsName": "contoso.com",
              "NetBiosName": "CONTOSO"
          },
          "ActiveDirectoryConfig": {
              "GroupManagedServiceAccounts": [
                  {
                      "Name": "webapp01",
                      "Scope": "contoso.com"
                  },
                  {
                      "Name": "webapp01",
                      "Scope": "CONTOSO"
                  }
              ],
              "HostAccountConfig": {
                  "PortableCcgVersion": "1",
                  "PluginGUID": "{GDMA0342-266A-4D1P-831J-20990E82944F}",
                  "PluginInput": "contoso.com:gmsaccg:<password>"
              }
          }
      }
      
  3. 验证凭据规范文件的路径对于你的业务流程解决方案来说是否正确。 如果使用的是 Docker,请确保容器运行命令包括 --security-opt="credentialspec=file://NAME.json",其中,“NAME.json”将替换为 Get-CredentialSpec 输出的名称。 该名称是一个平面文件名,相对于 Docker 根目录下的 CredentialSpecs 文件夹。

检查网络配置

检查防火墙配置

如果你在容器或主机网络上使用严格的防火墙策略,该策略可能会阻止到 Active Directory 域控制器或 DNS 服务器的必需连接。

协议和端口 用途
TCP 和 UDP 53 DNS
TCP 和 UDP 88 Kerberos
TCP 139 NetLogon
TCP 和 UDP 389 LDAP
TCP 636 LDAP SSL

你可能需要根据容器发送到域控制器的流量的类型来允许对其他端口的访问。 有关 Active Directory 使用的端口的完整列表,请参阅 Active Directory 和 Active Directory 域服务端口要求

检查容器主机 DNS 配置

如果将 gMSA 与加入域的容器主机结合使用,应会在主机上自动配置 DNS,以便它可以正确解析并建立到域的连接。 如果将 gMSA 与未加入域的主机结合使用,将不会自动设置此配置。 应验证是否已配置主机网络,以便它能够解析域。 可使用以下方法检查是否可以从主机解析域:

nltest /sc_verify:contoso.com

检查容器

  1. 如果运行的是 Windows Server 2019 或 Windows 10 版本 1809 之前的 Windows 版本,则容器主机名必须与 gMSA 名称匹配。 确保 --hostname 参数与 gMSA 短名称(不含域组件,例如“webapp01”而非“webapp01.contoso.com”)匹配。

  2. 检查容器网络配置,验证容器能否解析和访问 gMSA 域的域控制器。 容器中配置不当的 DNS 服务器是导致标识问题的常见罪魁祸首。

  3. 通过在容器中运行以下 cmdlet(使用 docker exec 或等效项)来检查容器是否具有到域的有效连接:

    nltest /sc_verify:contoso.com
    

    如果 gMSA 可用并且网络连接允许容器与域进行通信,则信任验证应返回 NERR_SUCCESS。 如果该验证失败,请验证主机和容器的网络配置。 两者都需要能够与域控制器进行通信。

  4. 检查容器是否可以获取有效的 Kerberos 票证授予票证 (TGT):

    klist get <myapp>
    

    此命令应返回“A ticket to krbtgt has been retrieved successfully”(已成功检索 krbtgt 的票证)并列出用于检索票证的域控制器。 如果能够获取 TGT,但上一步中 nltest 失败,则可能表示 gMSA 帐户配置不当。 有关详细信息,请参阅检查 gMSA 帐户

    如果无法在容器中获取 TGT,则可能表示存在 DNS 或网络连接问题。 请确保容器可以使用域 DNS 名称来解析域控制器,并且可以从该容器路由到域控制器。

  5. 确保你的应用已配置为使用 gMSA。 使用 gMSA 时,容器中的用户帐户不会更改。 相反,当系统帐户与其他网络资源通信时,它将使用 gMSA。 这意味着应用将需要作为“网络服务”或“本地系统”运行以利用 gMSA 标识。

    提示

    如果运行 whoami 或使用其他工具在容器中标识当前用户上下文,则不会看到 gMSA 名称本身。 这是因为你始终作为本地用户而不是域标识登录到容器。 计算机帐户在与网络资源通信时都使用 gMSA,这就是应用需要作为“网络服务”或“本地系统”运行的原因。

检查 gMSA 帐户

  1. 如果容器看起来已正确配置,但用户或其他服务无法自动向容器化应用进行身份验证,请检查你的 gMSA 帐户上的 SPN。 客户端将根据它们用来访问应用程序的名称来查找 gMSA 帐户。 这可能意味着在特定情况下(例如,当客户端通过负载均衡器或其他 DNS 名称连接到你的应用时),你的 gMSA 需要额外的 host SPN。

  2. 将 gMSA 与加入域的容器主机结合使用时,请确保 gMSA 和容器主机属于同一个 Active Directory 域。 如果 gMSA 属于其他域,则容器主机将无法检索 gMSA 密码。

  3. 确保域中只有一个帐户与你的 gMSA 同名。 gMSA 对象在其 SAM 帐户名后面附加了美元符号 ($),因此 gMSA 可以命名为“myaccount$”,而不相关的用户帐户在同一域中可以命名为“myaccount”。 如果域控制器或应用程序必须按名称查找 gMSA,这可能会导致问题。 可以通过以下命令在 AD 中搜索具有类似名称的对象:

    # Replace "GMSANAMEHERE" with your gMSA account name (no trailing dollar sign)
    Get-ADObject -Filter 'sAMAccountName -like "GMSANAMEHERE*"'
    
  4. 如果对 gMSA 帐户启用了无约束委托,请确保 UserAccountControl 属性WORKSTATION_TRUST_ACCOUNT 标志仍处于启用状态。 若要使容器中的 NETLOGON 与域控制器通信,此标志是必需的。在应用必须将名称解析为 SID 的情况下就是如此,反之亦然。 可以通过以下命令来检查是否正确配置了标志:

    $gMSA = Get-ADServiceAccount -Identity 'yourGmsaName' -Properties UserAccountControl
    ($gMSA.UserAccountControl -band 0x1000) -eq 0x1000
    

    如果上述命令返回 False,请使用以下命令将 WORKSTATION_TRUST_ACCOUNT 标志添加到 gMSA 帐户的 UserAccountControl 属性。 此命令还将清除 UserAccountControl 属性中的 NORMAL_ACCOUNTINTERDOMAIN_TRUST_ACCOUNTSERVER_TRUST_ACCOUNT 标志。

    Set-ADObject -Identity $gMSA -Replace @{ userAccountControl = ($gmsa.userAccountControl -band 0x7FFFC5FF) -bor 0x1000 }
    
    

未加入域的容器主机:使用事件日志来识别配置问题

可使用用于将 gMSA 与未加入域容器主机结合使用的事件日志记录来识别配置问题。 事件记录在 Microsoft-Windows-Containers-CCG 日志文件中,可在“Applications and Services Logs\Microsoft\Windows\Containers-CCG\Admin”下的“事件查看器”中找到。如果从容器主机导出此日志文件来进行读取,则必须在试图读取该日志文件的设备上启用容器功能,并且必须使用支持将 gMSA 与未加入域的容器主机结合使用的 Windows 版本。

事件和描述

事件编号 事件文本 说明
1 Container Credential Guard 对插件进行了实例化 此事件表明已安装并可以加载凭据规范中指定的插件。 无需执行任何操作。
2 Container Credential Guard 使用插件 %2 提取了 %1 的 gmsa 凭据 这是一个信息事件,表明已成功从 AD 提取 gMSA 凭据。 无需执行任何操作。
3 Container Credential Guard 未能解析凭据规范。错误:%1 此事件表明凭据规范有问题。 如果插件的 GUID 不正确,或者有其他字段不正确,可能就会发生这种情况。 请查看凭据规范的故障排除指南,以验证凭据规范的格式和内容。
4 Container Credential Guard 未能实例化插件 %1。 错误:%2 此事件表明无法加载插件。 应检查插件是否正确安装在主机上
6 Container Credential Guard 未能从插件 %1 中提取凭据。 错误:%2 此事件表明插件已加载,但无法检索从 AD 提取 gMSA 密码所需的凭据。 应验证插件的输入在凭据规范中是否设置了正确的格式,以及容器主机是否拥有访问插件使用的机密存储所必需的权限。
7 Container Credential Guard 正在使用插件 %1 重新提取凭据 这是信息事件。 当 gMSA 密码过期并需要使用插件提取的凭据进行刷新时,将生成此事件。
8 Container Credential Guard 无法使用插件 %2 获取 %1 的 gmsa 凭据。 错误原因:%3 此事件表明使用插件提取的凭据无法用于从 AD 提取 gMSA 凭据。 应验证从插件提取的帐户在 AD 中是否具有检索 gMSA 凭据的权限。