排查 Windows 容器的 gMSA 问题

适用于:Windows Server 2025、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 10 版本 1703、1709 和 1803 上将 gMSA 与 Hyper-V 隔离容器结合使用

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

此 bug 已在 Windows Server 2019 和 Windows 10 版本 1809 中修复。 还可以在 Windows Server 2016 和 Windows 10 版本 1607 上使用 gMSA 运行 Hyper-V 隔离容器。

如果指定了主机名参数,则同时使用具有多个容器的 gMSA 会导致 Windows Server 2019 及更高版本出现间歇性故障

当为多个容器分配相同的标识时,所有容器都使用 gMSA 帐户。 使用 --hostname 参数指定 gmsa 帐户名,并且当两个容器同时与同一域控制器通信时,可能会出现争用条件。 当另一个容器与同一域控制器通信时,它将取消与任何以前使用同一标识的容器的通信。

这可能会导致间歇性的身份验证失败,并且在你在容器内运行 nltest /sc_verify:contoso.com 时,有时可能会被视为信任失败。 若要避免 docker 容器中出现此问题,如果 --hostname 指定了参数,则在与 gmsa 帐户同时运行容器时,它必须始终是唯一的。 例如,如果 gmsa 帐户为“webapp01.contoso.com”,并且两个容器同时运行,则两个容器可以分别具有 --hostname 值为“webapp01”、“webapp02”的参数。

常规故障排除指南

如果在使用 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>
    

    此命令应返回“已成功检索到 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 日志文件中,可以在“应用程序和服务日志\Microsoft\Windows\Containers-CCG\Admin”下的“事件查看器”中找到。如果将此日志文件从容器主机导出到读取它,则必须在尝试读取日志文件的设备上启用容器功能,并且必须位于支持将 gMSA 与未加入域的容器主机配合使用的 Windows 版本上。

事件和说明

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