Sql-Server

連結伺服器連接開始失敗並出現“無法生成 SSPI 上下文 … SQL Server 網路介面:登錄嘗試失敗”錯誤?

  • June 6, 2021

問題

我在同一個域上有兩台 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 日誌:

伺服器 A SQL 日誌

ServerB SPN 註冊成功 SQL 日誌:

ServerB SQL 日誌

  • 請注意,兩台伺服器都為自己的埠 1433 和未指定埠成功註冊了 SPN。

ServerA 註冊的 SPN:

伺服器 A 註冊的 SPN

  • 我不確定第二個“CN=”行(倒數第二行)是什麼,但它的字面意思是“CN=ServerASvc”,但這不是 SQL 服務帳戶的名稱。SQL 服務帳戶是“SQLServiceAccount1”。
  • 我也不確定為什麼最後一行只有伺服器名稱“ServerA”的 SPN(我們的 DC 中確實有一個 Host / CName),但對於前一行來說似乎是多餘的。

ServerB 註冊的 SPN:

ServerB 註冊的 SPN

回顧一下我的 SPN:

  • 我的 ServerA 的 SQL Server 實例的服務帳戶(我們稱之為 ServiceAccountA)有一個 SPN 來信任自己的伺服器。
  • 我的 ServerB 的 SQL Server 實例的服務帳戶 (ServiceAccountB) 有一個 SPN 來信任它自己的伺服器。
  • 為 ServiceAccountA 設置了委派,以便能夠訪問 ServiceAccountB 的 SPN。

ServerA 的服務帳戶是SQLServiceAccount1,也是我們 DevSqlServer1 上使用的相同服務帳戶。

ServerB 的服務帳號是SQLServiceAccount2,也是我們 DevSqlServer2 上使用的同一個服務帳號。

對我來說,執行查詢會在ServerAServerBSELECT net_transport, auth_scheme FROM sys.dm_exec_connections WHERE session_id = @@SPID上返回TCP和。KERBEROS

此外,為每台伺服器執行不同的 SQL Server 實例服務帳戶。ServiceAccountA用於 ServerA,ServiceAccountB用於 ServerB。

在此問題開始發生的前一天晚上,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 設置是否正確。所以我認為這不是我們的問題。

此時,兩個集群都被破壞,並且輔助伺服器被移除,但問題仍然存在於各個伺服器(ServerA 和 ServerB)。


我們嘗試過的事情/問題進展

更改我的 AD 密碼後註銷並重新登錄並沒有解決問題,但****暫時重新啟動我的機器確實為我解決了這個問題。

我跑了setspn -l ServerA_SQLServiceAccountName,在我這樣做之後,我確實看到了我的SQL Error Log中的 SPN 。所以我認為Pinal Dave在我的情況下是正確的。

今天我醒來,我域中的每個人都再次被沖洗,包括我自己。我嘗試刷新 ServerA 上的 DNS,現在我們在從 ServerA 查詢連結伺服器時收到錯誤“連結伺服器錯誤:使用者 ‘NT AUTHORITY\ANONYMOUS LOGON’ 登錄失敗”,而不是我原來的錯誤。

看來我正面臨某種 SPN / 雙跳問題,因為當我 RDP 直接連接到 ServerA 並連接到 ServerA 上的 SQL 實例時(從 RDP 會話中 - 與我在不是 RDP 時連接到實例的帳戶相同)編輯)並嘗試查詢連結伺服器,一切都很好。問題是,我的 SPN 真的正確嗎?**(請參閱上面“相關資訊”**部分中的目前 SPN 。)

我們對 SPN 和服務帳戶的 AD 委託屬性進行了三次檢查。我們相當有信心所有的鴨子都井井有條。我們又完全崩潰了:Web 伺服器、SSMS 等,無論我們如何嘗試查詢連結伺服器,我認為這是由於 Kerberos 的預設 10 小時票證時間失效,並且它沒有正確更新新的實例同一張票。我們目前面臨這個錯誤:

消息 18456,級別 14,狀態 1,第 1 行使用者“NT AUTHORITY\ANONYMOUS LOGON”登錄失敗。

我們一直在嘗試使用Kerberos 配置管理器進行故障排除,它發現的唯一問題(一直以來)是一個警告,上面寫著“ Kerberos 配置管理器報告“必須啟用 TCP 才能使用 Kerberos 身份驗證”:

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 Server 和域控制器)上,隨後執行的 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

當您的舊應用程序在另一個域中啟動時,它將傳遞舊的 NTLM SID 值並將其與 SQL Server 實例中儲存的值進行比較。

如果有比賽

$$ Domain/User $$使用 SQL Server 登錄$$ Domain/User $$然後 SQL Server 會讓使用者登錄到相關的數據庫。SQL Server 將執行相同的操作$$ Domain/User $$ 分配給 SQL Server Windows 組登錄。

Kerberos

Kerberos 依賴於使用者或服務帳戶能夠生成(請求的)令牌並將其與中央提供程序進行比較以確定使用者是否是他/她/他們聲稱的人的能力。

強調我的

Kerberos V5 基於 MIT 開發的 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)

成功 SPN 註冊的輸出

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 註冊

不成功的 SPN 註冊的輸出

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,您就應該啟動並執行。


解決方案

手動 SPN 註冊

好吧,您必須是域管理員或允許更改域 OU 上的電腦帳戶對象。然後您可以使用相關參數執行SETSPN:

setspn -A MSSQLSvc/host.domain.tld:1433 domain\accountname 

參考: 手動 SPN 註冊(Microsoft Docs)

為服務帳戶配置 SPN 後,您應該能夠再次啟動伺服器並訪問數據庫。

SPN 註冊需要重新啟動服務。

修改 OU 對象的權限

為了讓 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 註冊

增加 Kerberos 令牌大小

在某些情況下,一個帳戶可能屬於太多的對象/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 的域控制器上,您可以使用組策略將以下系統資料庫​​項添加到多台電腦:

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)

有趣的資訊

應該注意的一件事是不建議授予這些權限(請參閱http://support.microsoft.com/kb/319723)如果 SQL Server 是群集的,或者如果您有多個域控制器,因為 Active Directory 複製中的延遲可能會導致連接SQL Server 實例的問題。

參考: 為使用 Kerberos 的 SQL Server 身份驗證註冊 SPN (MSSQLTips.com)

因此,解決方案是實際撤銷服務帳戶修改其自己的對象的能力,這將拒絕它在故障轉移期間刪除 SPN 的可能性。

  • 啟動Active Directory 電腦和使用者並確保您正在查看Advanced View 版本。
  • 打開服務帳戶屬性並切換到安全選項卡。
  • 從Group- 或 Username部分選擇Self項目,然後查看Permissions for SELF
  • 刪除完全訪問和/或寫入和/或寫入 servicePrincipalName和/或寫入公共資訊權限(如果已選擇)。
  • Write servicePrincipalName可能位於PermissionsAdvanced部分(點擊Advanced按鈕)。

這應該可以防止在集群進行故障轉移時出現進一步的問題,因為實例重新啟動,這將導致 SPN 被取消註冊。

作為一名 DBA,我遇到的 SPN 問題比我想像的要多。對於我們來說,我們被允許用於安裝 SQL Server 的 SQL 帳戶沒有將 SPN 寫入 Active Directory 的權限。因此,SQL 改為使用 NTLM 身份驗證。從那裡,一些 SPN 問題確實浮出水面。

說了這麼多,你的問題似乎是在微軟剛剛發布更新導致包括交換在內的整個線上服務主機的身份驗證問題的時候出現的。

選項 1:回滾最新的 Microsoft 更新檔

在您對 SPN 過於瘋狂之前,並且我去過那裡,請嘗試在您遇到問題的上述盒子上回滾 Microsoft 更新檔。即使它只是用於 Windows Server。

選項 2:使用 KCM 分析您的 SPN 並生成缺失的 SPN

如果失敗,我會在 Microsoft Kerberos 配置管理器中分析您的 SPN。執行它,我們意識到我們的某些盒子需要一些 SPN 失去。該工具允許我們生成腳本,因此我們的 Windows Server 人員可以使用正確的權限執行它們,從而將 SPN 放入 Active Directory。這是一個 GUI 工具,當我們上次發生 SPN 問題時,它確實為我們增加了價值。

我意識到有各種各樣的建議和建議,我只是想我會把我的加入其中。

引用自:https://dba.stackexchange.com/questions/287180