我有一个运行 Windows Server 2012R2 和 SQL Server 2014 Enterprise 后端的操作服务器。此服务器用于通过 SQL 代理作业调用的 cmd 文件将新代码部署到其他生产服务器。所有服务器都在同一个域中。
服务器 A 运行 Windows Server 2008R2 和 SQL Server 2008R2 后端。此服务器有一个链接服务器连接到服务器 B 上的数据库,运行与 A 相同的操作系统和 SQL Server 版本。链接服务器配置有选项 @useself=TRUE。
- 所有三台服务器都使用启用了委派的服务帐户。
- 此服务帐户在所有三个 SQL Server 实例上都具有 sa 特权。
- 所有三台服务器都使用该帐户配置了 SPN,并被委派将 Kerberos 用于关联的 MSSQLSVC 服务。
我可以在每个上运行以下命令并返回“Kerberos”
SELECT auth_scheme FROM sys.dm_exec_connections WHERE session_id = @@spid
此外,我可以毫无问题地从任何这些服务器远程登录、ping 等到任何其他服务器 - 一切都已连接。代码部署从未出现过问题,并且经常引用链接服务器并且没有问题......除了一种情况,我不明白为什么。
双跳场景
- 操作服务器上的 SQL 代理作业由除 SQL 代理服务帐户之外的任何系统管理员临时运行,并在操作服务器上执行 cmd 文件。
- SQL 代理作业被配置为“运行方式”一个 SQL 代理服务帐户,具有 sa 权限。
- 部署的代码来自操作服务器上的 .sql 文件。
- cmd 文件调用 SQLCMD 来针对服务器 A 执行 .sql 文件中的代码。
.sql 文件中的代码引用链接服务器并失败并出现错误
*消息 18456,级别 14,状态 1,服务器 ServerB,第 1 行用户“NT AUTHORITY\ANONYMOUS LOGON”登录失败。* .
该错误针对链接服务器 - 服务器 B。如果我使用 SQLCMD 从操作服务器对服务器 A 手动运行此代码,它运行正常。如果我以 SQL 代理服务帐户身份登录到一个框并运行 SQL 代理作业,它运行良好。只有当 SQL 代理作业由 SQL 代理服务帐户以外的其他人执行时,我才会收到错误消息。
我已经阅读了很多关于 Kerberos、双跳等的帖子、博客和 MSDN 文章,告诉我去做已经做过的事情。我错过了什么?
附加信息 我终于能够回到这个并找到一些附加信息。根据 Bogdan 的建议,我运行了 Process Explorer 并验证了第一跳的凭据是否如预期来自 SQL 代理服务帐户,并且正在使用 TCP。唉,这就是我能够从该工具中获得的所有有用信息。
我深入研究了 Window 的应用程序日志并四处寻找机器上不同实例的登录信息,发现甚至没有使用 Kerberos!相反,正在使用 NTLM。
所以这就是我要走的新路径——为什么要使用 NTLM 身份验证,当 Kerberos 设置好并且端口和实例存在正确的 FQDN SDN 时?我是否需要以某种方式在 cmd 文件或 SQLCMD 调用中指定身份验证类型?还是我有一些我没有考虑的错误配置?
谜底加深 SQLCMD 调用通过别名引用了“第一跳”服务器。我修改了对实际命名实例的 SQLCMD 服务器引用并重新运行了该作业。有效!我们还为我们的机器和 SQL 实例使用 cNames,所以我尝试使用它。它也奏效了!为了咧嘴笑和咯咯笑,我重新尝试了别名......它工作了???我去检查每个这些的 Windows 应用程序日志,它仍然将身份验证报告为 NTLM!
在这一点上,我完全感到困惑,不知道如何解释这种行为来修复我们环境的其余部分。
终于想通了!
我们使用 SQL 别名和规范名称引用了许多非常活跃的 SQL Server 和实例。这使我们能够在不中断代码的情况下执行并行升级和切换机器。出于同样的原因,SQL 别名都被配置为引用规范名称。我们注册的标准 SPN 用于机器名称。
示例 SQL Server SSxyz\xyzInstance 在端口 12345 上侦听已注册 SPN:
这些都注册到该机器上拥有 MSSQLSVC 的服务帐户,并且为每个帐户设置了委派以传递凭据。
服务器和实例也有规范名称 cxyz\xyzInstance。最后,SQL Server 有一个 32 位和 64 位别名 xyzAlias,指向规范名称 cxyz\xyzInstance。
在从我的本地 pc 到 xyzAlias 到 abcAlias 的双跃点场景中,Kerberos 身份验证失败并回退到 NTLM,因为无法解析别名和 SPN。这就是日志显示 NTLM 的原因。
修复方法是添加更多 SPN 以将服务器的规范名称注册为实际名称。然后将 SQL 服务注册到另一个 SPN。像这样:
注册后,将为每个 SPN 配置委派。这些显示为唯一的 SPN,并允许 SQL 别名解析为实际的机器名称。记录的双跳身份验证是 kerberos,每个人都很高兴!除了广告人......他们将在几个小时内注册很多 SPN。
操作服务器上的Xcopy Process Explorer 。
修改 SQL Server 代理调用的 CMD 文件,使其
timeout 600
在失败的 sqlcmd.exe 调用之前调用。这将在实际调用 sqlcmd 之前引入 10 分钟的延迟。执行工作,首先你知道它是有效的。转到进程资源管理器并检查相应 cmd.exe 进程的属性选项卡(它将是调用 timeout.exe 的那个)。截取“安全”选项卡的屏幕截图,它会持续更长时间。
执行你知道它失败的作业。检查安全选项卡并与之前的案例进行比较。
sqlcmd.exe 使用的安全上下文是从 cmd.exe 继承的,它是由 SQLAGENT.EXE 创建的。您应该注意到在 2 种情况下创建的安全上下文之间的差异,这将导致解决方案。