J.D*_*.D. 9 sql-server linked-server errors sql-server-2016 logon
我在同一个域中有两个 SQL Server 2016 标准版服务器。ServerA有两个链接服务器连接设置到ServerB。
第一个链接服务器连接使用专用的远程SQL 登录安全上下文。那个一直是并且仍然工作正常。
第二个连接使用“登录的当前安全上下文”,它是ServerA 上的Windows 身份验证 (AD) 登录。直到今天,这也运行良好。
今天突然间,连接到 ServerA 然后尝试运行使用第二个链接服务器连接的查询的每个人最终都会遇到以下错误:
链接服务器“LinkedServerName”的 OLE DB 访问接口“SQLNCLI11”返回消息“无法生成 SSPI 上下文”。消息 -2146893044,级别 16,状态 1,第 0 行 SQL Server 网络接口:登录尝试失败
此外,用户目前可以直接连接到 ServerA 和 ServerB,甚至可以直接对 ServerB 上的对象执行查询,但是当他们尝试通过 ServerA 上的链接服务器运行引用 ServerB 上相同对象的查询时,这是唯一一次他们得到上述错误,目前。
这是我们目前看到的SPN和日志(抱歉所有混淆):
ServerB 成功的 SPN 注册 SQL 日志:
ServerB 成功的 SPN 注册 SQL 日志:
ServerA 注册的 SPN:
ServerB 注册的 SPN:
回顾我的 SPN:
ServerA 的服务帐户是SQLServiceAccount1,也是我们 DevSqlServer1 上使用的相同服务帐户。
ServerB 的服务帐户是SQLServiceAccount2,也是我们 DevSqlServer2 上使用的相同服务帐户。
对我来说,在ServerA和ServerB上运行查询会SELECT net_transport, auth_scheme FROM sys.dm_exec_connections WHERE session_id = @@SPID返回。TCPKERBEROS
此外,每个服务器都运行不同的 SQL Server 实例服务帐户。ServiceAccountA为服务器A和ServiceAccountB为服务器B。
在此问题开始发生的前一天晚上,Windows 更新安装在 ServerB(以及我们的一些其他服务器)上。具体来说,此更新2020 年 11 月 10 日 - KB4586830(操作系统内部版本 14393.4046) 显然说明了这一点:
在您环境中的域控制器 (DC) 和只读域控制器 (RODC) 上安装此更新后,您可能会遇到 Kerberos 身份验证和票证续订问题。这是由这些更新中如何解决 CVE-2020-17049 的问题引起的。
我们尝试回滚更新,它调用了服务器的重新启动,事情似乎又开始工作了,但随后又开始为我们的 Web 服务器(第三个/单独的服务器)再次中断,它击中我们的 ServerA 以查询链接服务器服务器 B.
最初 ServerA 和 ServerB 是单独的 Windows 故障转移群集(ServerA1 和 ServerA2,以及 ServerB1 和 ServerB2)的一部分。在这种情况下,汉娜·弗农 (Hannah Vernon) 的DBA.StackExchange 回答听起来与我们所经历的相似。
唯一的区别是我们以前在问题开始时不允许服务帐户注册/取消注册 SPN。现在我们让他们这样做,并且没有任何故障转移事件,我们三重检查了当前所有 SPN 的设置是否正确。所以我不认为这是我们的问题。
此时,两个集群都被破坏,辅助服务器被移除,但问题仍然存在于单个服务器(服务器 A 和服务器 B)上。
更改我的 AD 密码后注销并重新登录并没有解决问题,但物理重新启动我的机器暂时确实为我解决了这个问题。
我跑了setspn -l ServerA_SQLServiceAccountName之后,我确实看到了SQL 错误日志中的 SPN 。所以我认为Pinal Dave 对我来说是对的。
今天我醒来,我域上的每个人都再次被冲洗,包括我自己。我尝试刷新 ServerA 上的 DNS,现在我们在从 ServerA 查询链接服务器时收到错误“链接服务器错误:用户'NT AUTHORITY\ANONYMOUS LOGON'登录失败”而不是我原来的错误。
看来我正面临某种 SPN/双跳问题,因为当我 RDP 直接连接到 ServerA 并连接到 ServerA 上的 SQL 实例时(从 RDP 会话中 - 与我在非 RDP 时连接到实例的帐户相同) ed in) 并尝试查询链接服务器,一切都很好。问题是,我的 SPN 真的正确吗?(请参阅上面“相关信息”部分中的当前 SPN 。)
我们对服务帐户的 SPN 和 AD 委托属性进行了三次检查。我们相当有信心所有的鸭子都井井有条。我们再次完全关闭:Web 服务器、SSMS 等,无论我们如何尝试查询链接服务器,我认为这是由于 Kerberos 的默认 10 小时票证时间失效,并且它没有正确更新新实例同一张票。我们目前正面临这个错误:
消息 18456,级别 14,状态 1,第 1 行用户“NT AUTHORITY\ANONYMOUS LOGON”登录失败。
我们一直在尝试使用Kerberos 配置管理器进行故障排除,它发现的唯一问题(一直以来)是一条警告说“ Kerberos 配置管理器报告“必须启用 TCP 才能使用 Kerberos 身份验证”:
我们已经检查了我们的两个服务器中都启用了 TCP,所以我不确定为什么会出现这个警告或如何解决它,以及它是否是我们的根本问题。
另一件值得注意的事情是,我们大部分时间都只是间歇性地停机。也就是说,某些用户在使用我们的应用程序(网络、移动设备等)时能够成功查询链接服务器,而有些则不能。因此,如果这是一个真正的 SPN 问题,我认为没有人能够查询链接服务器 - 一种全有或全无的情况。这绝对感觉更像是一个随机的 Kerberos 问题(可能与前面提到的 Windows 更新有关)。
在这一点上,我们已经在客户端机器和服务器(SQL 服务器、DNS 服务器和 Web 服务器)上尝试purge了我们的 KLIST Kerberos 票证,ipconfig /flushdns并尝试重新启动客户端机器和服务器机器,回滚上述 Windows 更新除了前面提到的所有其他东西之外,在任何我们可靠地确定它的机器上都无济于事。充其量我们得到了非常间歇性的混合结果,有时会临时重新启动客户端机器。
目前,ServerA 和 ServerB 都是真正的单一服务器(这些是本问题开始时的 Windows 故障转移群集,但已被删除并且群集已被破坏)。我们还有共享相同 SQL 服务帐户的 ServerA ( ServerADev ) 和 ServerB ( ServerBDev ) 的开发副本。
我们已经设置了从 ServerB 到 ServerA 的复制,以暂时解决生产中的问题,但本周我们在开发环境中也遇到了同样的问题。
我尝试使用xp_cmdshell运行klist purge并为 ServerADev 和 ServerBDev 循环 SQL 服务,但问题仍然存在。
在这一点上,我很确定问题是由于2020 年 11 月 10 日的拙劣 Windows 更新——KB4586830(操作系统内部版本 14393.4046)特别指出“您可能会遇到 Kerberos 身份验证和票证续订问题”。不幸的是,它安装在我们的许多服务器(SQL 服务器和域控制器)上,并且随后运行的 Windows 更新,从Windows 更新历史记录中删除了拙劣的更新,所以我没有可靠的方法来判断哪些服务器甚至最初收到了拙劣的更新。
您已经说明,分别列出了可能是什么问题:
链接服务器“LinkedServerName”的 OLE DB 访问接口“SQLNCLI11”返回消息“无法生成 SSPI 上下文”。消息 -2146893044,级别 16,状态 1,第 0 行 SQL Server 网络接口:登录尝试失败
那么什么是 SSPI?微软将其描述为:
结合其操作系统,Microsoft 提供安全支持提供程序接口 (SSPI)。SSPI 为安全的分布式应用程序提供了通用的行业标准接口。
参考: 安全支持提供程序接口 (SSPI) (Microsoft Docs)
基本上,它是应用程序如何针对请求身份验证的端点对自身、用户或其他组件进行身份验证。
在架构概述中有这样的描述......
提供各种 SSP 和软件包。Windows 附带NTLM 安全包和Microsoft Kerberos 协议安全包。此外,您可以选择安装安全套接字层 (SSL) 安全包,或任何其他与 SSPI 兼容的 SSP。
参考: SSPI 体系结构概述(Microsoft Docs)
当您的旧应用程序在另一个域中启动时,它将传递旧的 NTLM SID 值并将其与存储在 SQL Server 实例中的内容进行比较。
如果 [域/用户] 与 SQL Server 登录 [域/用户] 匹配,则 SQL Server 将让用户登录到相关数据库。SQL Server 将对分配给 SQL Server Windows 组登录名的 [域/用户] 执行相同的操作。
Kerberos 依赖于用户或服务帐户能够生成(请求的)令牌并将其与中央提供程序进行比较以确定用户是否是他/她/他们声称的身份的能力。
强调我的
Kerberos V5 基于麻省理工学院开发的 Kerberos 身份验证系统。在 Kerberos 下,客户端(通常是用户或服务)向密钥分发中心 (KDC) 发送票据请求。KDC 为客户端创建一个票据授予票据 (TGT),使用客户端的密码作为密钥对其进行加密,并将加密的 TGT 发送回客户端。然后客户端尝试使用其密码解密 TGT。如果客户端成功解密了 TGT(即,如果客户端给出了正确的密码),它会保留解密后的 TGT,这表明客户端的身份证明。
参考 1.1 什么是 Kerberos 以及它是如何工作的?(麻省理工学院 Kerberos V 5.0)
因此,您的服务器 A 正在尝试通过 Kerberos 身份验证访问服务器 B,但未能成功,因为可能缺少 SPN。
为了实现成功的身份验证,服务器应具有服务主体名称 (SPN)。描述如下:
服务主体名称 (SPN) 是服务实例的唯一标识符。Kerberos 身份验证使用 SPN 将服务实例与服务登录帐户相关联。这允许客户端应用程序请求服务验证帐户,即使客户端没有帐户名称。
再深入一点可能的根本原因:
如果在整个林中的计算机上安装服务的多个实例,则每个实例都必须有自己的 SPN。如果客户端可能使用多个名称进行身份验证,则给定的服务实例可以有多个 SPN。例如,SPN 始终包含运行服务实例的主机的名称,因此服务实例可能会为其主机的每个名称或别名注册一个 SPN。有关 SPN 格式和组成唯一 SPN 的详细信息,请参阅唯一 SPN 的名称格式。
参考 服务主体名称(Microsoft Docs)
如果您的应用程序(主机)和/或 SQL Server 实例无法注册服务主体名称,那么您的应用程序/服务器将无法通过 Kerberos 对用户进行身份验证,并且您的链接服务器可能会失败。
检查 SQL Server 实例的 ERRORLOG,并验证 SQL Server 实例是否能够注册其自己的 SPN。在实例启动过程中会有一个条目。
如果 SQL Server 服务帐户是域服务帐户并且满足其他一些条件,则它可以执行此操作。有些是:
客户端和服务器计算机必须是同一个 Windows 域的一部分,或者在受信任的域中。
和
服务主体名称 (SPN) 必须在 Active Directory 中注册,它在 Windows 域中承担密钥分发中心的角色。SPN 在注册后映射到启动 SQL Server 实例服务的 Windows 帐户。如果尚未执行 SPN 注册或注册失败,则 Windows 安全层无法确定与 SPN 关联的帐户,并且不会使用 Kerberos 身份验证。
参考: 为 Kerberos 连接注册服务主体名称(Microsoft Docs)
Run Code Online (Sandbox Code Playgroud)2020-12-01 11:14:18.87 Server SQL Server is attempting to register a Service Principal Name (SPN) for the SQL Server service. Kerberos authentication will not be possible until a SPN is registered for the SQL Server service. This is an informational message. No user action is required. ... 2020-12-01 11:14:18.94 Server The SQL Server Network Interface library successfully registered the Service Principal Name (SPN) [ MSSQLSvc/SERVERNAME.TG.CH ] for the SQL Server service.
如果服务无法注册 SPN,则:
笔记
如果服务器无法自动注册 SPN,则必须手动注册 SPN。请参阅手动 SPN 注册。
Run Code Online (Sandbox Code Playgroud)2020-11-27 15:41:56.24 Server SQL Server is attempting to register a Service Principal Name (SPN) for the SQL Server service. Kerberos authentication will not be possible until a SPN is registered for the SQL Server service. This is an informational message. No user action is required. ... 2020-11-27 15:41:56.43 Server The SQL Server Network Interface library could not register the Service Principal Name (SPN) [ MSSQLSvc/SERVERNAME:INSTANCENAME ] for the SQL Server service. Windows return code: 0x200b, state: 15. ... 2020-11-27 15:41:56.43 Server The SQL Server Network Interface library could not register the Service Principal Name (SPN) [ MSSQLSvc/SERVERNAME:INSTANCEPORT ] for the SQL Server service. Windows return code: 0x200b, state: 15.
一旦您的 SQL Server 实例注册了其 SPN,您就应该启动并运行了。
那么您必须是域管理员或被允许更改域的 OU 上的计算机帐户对象。然后您可以使用相关参数运行 SETSPN:
setspn -A MSSQLSvc/host.domain.tld:1433 domain\accountname
Run Code Online (Sandbox Code Playgroud)
参考: 手动 SPN 注册(Microsoft Docs)
为服务帐户配置 SPN 后,您应该能够再次启动服务器并访问数据库。
SPN 注册需要重新启动服务。
为了让 SQL Server 的服务帐户在 Active Directory 中自动创建 SPN,它(服务帐户)应该有权修改自己的对象 (OU)。
当数据库引擎服务启动时,它会尝试注册服务主体名称 (SPN)。假设启动 SQL Server 的帐户没有在 Active Directory 域服务中注册 SPN 的权限。在这种情况下,此调用将失败,并在应用程序事件日志和 SQL Server 错误日志中记录一条警告消息。要注册 SPN,数据库引擎必须在内置帐户下运行,例如本地系统(不推荐)或 NETWORK SERVICE,或具有注册 SPN 权限的帐户。您可以使用域管理员帐户注册 SPN,但在生产环境中不建议这样做。当 SQL Server 在 Windows 7 或 Windows Server 2008 R2 操作系统上运行时,您可以使用虚拟帐户或托管服务帐户 (MSA) 运行 SQL Server。虚拟帐户和 MSA 都可以注册 SPN。如果 SQL Server 不在这些帐户之一下运行,则 SPN 不会在启动时注册,域管理员必须手动注册 SPN。
参考: 为 Kerberos 连接注册服务主体名称(Microsoft Docs)
授予修改 SPN 的权限
- 打开 Active Directory 用户和计算机。若要打开 Active Directory 用户和计算机,请单击开始,单击运行,键入 dsa.msc,然后按 Enter。
- 单击查看,并验证是否选中了高级功能复选框。
- 如果未选中,请单击高级功能。如果控制台中没有出现要允许不相交命名空间的域,请执行以下步骤:
- 在控制台树中,右键单击 Active Directory 用户和计算机,然后单击连接到域。
- 在“域”框中,键入要允许不相交命名空间进入的 Active Directory 域的名称,然后单击“确定”。作为替代方法,您可以使用“浏览”按钮来定位 Active Directory 域。
- 在控制台树中,右键单击代表要允许不相交命名空间的域的节点,然后单击“属性”。
- 在安全选项卡上,单击高级。
- 在权限选项卡上,单击添加。
- 在“输入要选择的对象名称”中,键入要向其委派权限的组或用户帐户名称,然后单击“确定”。
- 为计算机对象配置应用到框。
- 在“权限”框底部,选中与“验证写入服务主体名称”权限对应的“允许”复选框,然后在三个打开的对话框中单击“确定”以确认您的更改。
- 关闭 Active Directory 用户和计算机。
参考: 授予修改 SPN 的权限(Microsoft Docs)
SPN 注册需要重新启动服务。您应该在权限设置正确的 ERRORLOG 中看到成功的 SPN 注册
在某些情况下,一个帐户可能属于太多的对象/AD 组/...这将导致相当大的 Kerberos 令牌。在这些情况下,您可能需要增加最大令牌大小.... 症状可能包括:
属于大量安全组的用户在身份验证时遇到问题。在进行身份验证时,用户可能会看到诸如 HTTP 400 > - Bad Request (Request Header too long) 之类的消息。用户在访问资源时也有问题,并且用户的组策略设置可能无法正确更新。
但
在类似条件下,Windows NTLM 身份验证按预期工作。除非您分析 Windows 行为,否则您可能看不到 Kerberos 身份验证问题。但是,在这种情况下,Windows 可能无法更新组策略设置。
参考: 当用户属于多个组时的 Kerberos 身份验证问题(Microsoft | Docs)
在运行 Windows Server 2003、Windows Server 2008、Windows Server 2008 R2 或 Windows Server 2012 的域控制器上,您可以使用组策略将以下注册表项添加到多台计算机:
Run Code Online (Sandbox Code Playgroud)Key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Parameters Entry: MaxTokenSize Data type: REG_DWORD Value: 48000
参考: 如何使用组策略将 MaxTokenSize 注册表项添加到多台计算机(Microsoft | Docs)
在阅读了问题和其他答案中的所有附加信息后,我得出的结论是,所有可能的解决方案都已研究过。我认为此问答可能会作为您在 Hannah Vernon 的回答中引用的问题的副本而结束。
但是,我想提供有关如何针对此问题应用修复程序的解决方案。
当 SQL Server 数据库引擎的实例启动时,SQL Server 会尝试为 SQL Server 服务注册 SPN。当实例停止时,SQL Server 会尝试取消注册 SPN。对于 TCP/IP 连接,SPN 以 MSSQLSvc/: 格式注册。命名实例和默认实例都注册为 MSSQLSvc,依靠值来区分实例。
对于支持 Kerberos 的其他连接,SPN 以 MSSQLSvc// 格式注册,用于命名实例。注册默认实例的格式为 MSSQLSvc/。
如果服务帐户缺乏这些操作所需的权限,则可能需要手动干预来注册或取消注册 SPN。
参考: 为 Kerberos 连接注册服务主体名称(Microsoft | SQL Docs)
应该注意的一件事是,如果 SQL Server 是群集的或者如果您有多个域控制器,则不建议授予这些权限(请参阅http://support.microsoft.com/kb/319723),因为 Active Directory 复制中的延迟会导致连接SQL Server 实例的问题。
参考: 使用 Kerberos 注册用于 SQL Server 身份验证的 SPN (MSSQLTips.com)
因此,解决方案是实际撤销服务帐户修改其自身对象的能力,这将拒绝其在故障转移期间删除 SPN 的可能性。
启动Active Directory 计算机和用户并确保您查看的是Advanced View 版本。
打开服务帐户属性并切换到安全选项卡。
从Group- 或 Username部分选择Self项,然后查看Permissions for SELF。
如果选择了完全访问权限和/或写入和/或写入 servicePrincipalName和/或写入公共信息权限,则删除它们。
该写的servicePrincipalName可能设在高级中的部分权限(点击按钮高级)。
这应该可以防止在集群进行故障转移时出现更多问题,因为实例会重新启动,这会导致 SPN 被取消注册。