在 Azure 上使用 系統指派的受控識別 (System-Assigned Managed Identity) 是最推薦的做法,因為它完全不需要在程式碼裡寫死密碼,安全性最高,且生命週期與你的資源(如 VM 或 App Service)同步。
要實現這個功能,你需要完成三個步驟:啟用身份識別、資料庫授權、以及修改 Python 連線字串。
第一步:在 Azure 資源上啟用受控識別
在你運行 Python 程式碼的資源(例如 Azure VM, App Service 或 Function)的頁面:
- 點選左側選單的 「身分識別」(Identity)。
- 在 「系統指派」 頁籤下,將狀態改為 「開啟」 並儲存。
- 系統會產生一個 物件識別碼 (Object ID),請記住這個資源的名稱。

上面的截圖來看,你目前是在 「Azure SQL Database」 的介面裡。
受控識別(Managed Identity)不是在資料庫(Database)上開啟的,而是在「跑 Python 程式碼的那個東西」上面開啟的。
請想像:
- SQL Database 是「銀行」。
- 你的 Python 程式碼(跑在 VM、App Service 或 Function 上)是「進去辦事的人」。
你現在需要在「辦事的人」身上發一張身分證(啟用受控識別),然後再去「銀行」告訴櫃檯(資料庫)說:「看到拿這張身分證的人就讓他進來」。
接下來你該怎麼做:
1. 找到「發身分證」的地方
請在 Azure Portal 最上方的搜尋框,搜尋你跑 Python 程式碼的資源名稱。
- 如果你是在 Azure VM 跑:去該 VM 的頁面,找左側選單的「身分識別」。
- 如果你是在 App Service 跑:去該 App Service 的頁面,找左側選單的「身分識別」。
- 如果你是在 Azure Function 跑:去該 Function 的頁面,找左側選單的「身分識別」。
進入後,你就會看到我上一個回覆說的「系統指派」狀態,將它改為 「開啟」。

2. 在資料庫(也就是你截圖的這個地方)授權
當你在上面的資源開啟受控識別後,回到你截圖的這個 SQL Database 介面:
- 點擊左側選單的 「查詢編輯器 (預覽)」(Query editor)。
- 用你的管理員帳號登入。
- 執行以下指令(假設你的 VM 或 App Service 名字叫
my-python-app):
SQL
CREATE USER [my-python-app] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [my-python-app];
ALTER ROLE db_datawriter ADD MEMBER [my-python-app];
💡 補充:截圖中的發現
從你的截圖中可以看到,在 「安全性」 區塊下,有一行:
- 系統指派的身分識別:已啟用
這指的是 「SQL Server 自己」 的身分,通常是用來讓 SQL 去讀取 Key Vault 等其他資源用的。這不是給你的 Python 程式連線用的。 總結: 請去尋找你運行 Python 的那個 Azure 資源(VM / App Service),在那裡開啟身分識別。
了解更多: 利用客戶自控金鑰支援透明資料加密的受控識別
https://learn.microsoft.com/zh-tw/azure/azure-sql/database/transparent-data-encryption-byok-identity?view=azuresql&WT.mc_id=Portal-SqlAzureExtension
▋ 數據安全的大門與那把遺失的鑰匙
在數位世界裡,我們使用「透明資料加密」技術,這就像是在資料庫門口裝了一道自動感應門,資料進出時會自動上鎖或解鎖。傳統做法是讓雲端平台幫你管理這把鑰匙,這對大多數人來說很方便。然而,對於需要極高掌控權的管理者來說,這就像是把身家財產的進出權限完全交給外人,一旦發生資安爭議,你可能無法第一時間主動切換鎖頭。
▋ 拿回屬於你的主權鑰匙
為了解決這個信任缺口,現在有一種「客戶管理金鑰」的機制。簡單來說,這就是讓你自備鎖頭與鑰匙。當你的資料庫要啟動加密功能時,系統不再使用預設的鑰匙,而是去你的私密保險庫中讀取你指定的「身份證明」。這確保了只有經過你授權的特定身份,才能啟動那把開啟資料的鑰匙。
▋ 建立你的專屬數位防線
如果你希望全面掌控數據的安全命運,可以嘗試以下步驟:
- 在雲端環境中建立一個專屬的「身份識別」,這就像是為你的資料庫申請一張專屬的身分證。
- 設定嚴格的存取權限,確保只有這個「身份」能接觸到你的加密鑰匙。
- 定期檢查這把鑰匙的使用紀錄,確保沒有任何未經授權的嘗試。
第二步:在 SQL Database 中授權
SQL Server 預設不認識這個受控識別,你必須進到資料庫裡幫它「開門」:
- 使用 Active Directory 管理員 帳號登入 SQL Database(可用 Azure Portal 的 Query Editor)。
- 執行以下 SQL 指令(將
<identity-name>替換為你的 Azure 資源名稱):
SQL
-- 建立資料庫使用者
CREATE USER [<identity-name>] FROM EXTERNAL PROVIDER;
-- 授予讀取/寫入權限 (視需求調整角色)
ALTER ROLE db_datareader ADD MEMBER [<identity-name>];
ALTER ROLE db_datawriter ADD MEMBER [<identity-name>];
如果你是在 Azure App Service 或 Azure VM 上啟用的受控識別,該「顯示名稱」通常就是你的 資源名稱。
- 錯誤做法:
CREATE USER [1234-1234-1234-1234-1234] ...(不可使用 ID) - 正確做法:
CREATE USER [你的AppService名稱] FROM EXTERNAL PROVIDER;
如果你不確定名稱,或者名稱有特殊字元,你可以直接使用 SID (這對應到你看到的物件識別碼) 來建立,這樣最準確:
-- 請將 '1234-1234-1234-1234-1234' 替換為你在身分識別頁面看到的 Object ID
CREATE USER [MyManagedIdentityName]
WITH OBJECT_ID = '1234-1234-1234-1234-1234';
-- 接著再授權
ALTER ROLE db_datareader ADD MEMBER [MyManagedIdentityName];

第三步:修改 Python 連線字串
使用受控識別時,連線字串不需要 UID 和 PWD,而是改用 Authentication=ActiveDirectoryMsi。
Python
import pyodbc
# 設定基礎參數
server = 'your-server.database.windows.net'
database = 'your-database'
driver = '{ODBC Driver 18 for SQL Server}'
# 系統指派受控識別的連線字串
connection_string = (
f"Driver={driver};"
f"Server={server};"
f"Database={database};"
"Authentication=ActiveDirectoryMsi;" # 關鍵設定
"Encrypt=yes;"
"TrustServerCertificate=no;"
"Connection Timeout=30;"
)
def connect_and_query():
try:
print(f"Connecting to {server} using Managed Identity...")
conn = pyodbc.connect(connection_string)
print("連線成功!")
return conn
except Exception as e:
print(f"連線失敗: {e}")
# 執行連線
conn = connect_and_query()
💡 關鍵筆記:
- 環境限制:
Authentication=ActiveDirectoryMsi只能在 Azure 環境內 運行(例如在 Azure VM 上跑)。如果你在自己的電腦(在地端)跑這段程式碼會報錯,因為地端環境沒有 Managed Identity 憑證。 - 驅動程式:請確保你的環境中安裝了 ODBC Driver 17 或 18,舊版驅動程式可能不支援
ActiveDirectoryMsi參數。 - 優點:即使你更換了密碼,或者這台機器被刪除了,都不需要去改程式碼,這就是「無密碼連線」的強大之處。
執行以下 SQL 指令時遇到 Error:
A connection was successfully established with the server, but then an error occurred during the pre-login handshake. (provider: TCP Provider, error: 0 – An existing connection was forcibly closed by the remote host.)
Failed to execute the query
這個錯誤「An existing connection was forcibly closed by the remote host」發生在 Pre-login handshake (預先登錄握手) 階段,通常不是程式碼邏輯問題,而是 網路層 或 防火牆 的攔截。
這代表你的 Python 程式已經碰到了 SQL Server 的大門,但 SQL Server 因為某些安全規則直接把連線「踢掉」了。
請檢查以下三個最常見的原因:
1. Azure SQL 防火牆未允許你的 IP
這是最常見的原因。即便你使用受控識別,網路還是要通。
- 如果你在 Azure 資源內執行:請到 SQL Server 的「網路 (Networking)」設定,確保 「允許 Azure 服務和資源存取此伺服器 (Allow Azure services and resources to access this server)」 有被勾選。
- 如果你在公司內網執行:請確認你的公用 IP 已加入 SQL Server 的防火牆白名單。

2. 強制使用 TLS 1.2
Azure SQL 預設要求 TLS 1.2。如果你的 Python 環境或 ODBC 驅動程式版本太舊,握手時會因為加密協定不匹配而被中斷。
- 解決方法:確保你的連線字串中有
Encrypt=yes;(你已經有了)。 - 檢查驅動:確認你安裝的是 ODBC Driver 18 for SQL Server。注意:Driver 18 預設會強制驗證證書,如果你沒有設定憑證,請試著在連線字串加上
TrustServerCertificate=yes;測試看看。
3. ODBC Driver 18 的「預設加密」改變
如果你是從 Driver 17 升級到 18,Driver 18 的預設行為變更了。請嘗試將連線字串稍微修改如下:
Python
connection_string = (
f"DRIVER={driver};"
f"SERVER={server};"
f"DATABASE={database};"
"Authentication=ActiveDirectoryMsi;"
"Encrypt=yes;"
"TrustServerCertificate=yes;" # 先暫時改成 yes 測試是否為證書握手失敗
"Connection Timeout=30;"
)
關鍵排除步驟(Debug Check)
- 測試工具連線:你在 Azure Portal 上的 「查詢編輯器 (Query Editor)」 現在能正常進去嗎?
- 如果連 Query Editor 都進不去,那是資料庫本身的網路/防火牆設定問題。
- 確認受控識別是否已成功建立 User:
- 你剛才在嘗試
CREATE USER時失敗了,這代表受控識別的身分還沒進到資料庫。 - 重要:如果
CREATE USER沒成功,Authentication=ActiveDirectoryMsi就絕對連不上。
- 你剛才在嘗試
目前的卡點建議:
先解決 CREATE USER 的問題。請確認你是用 「Microsoft Entra 管理員」 的帳號登入 Query Editor。只有管理員有權限執行 FROM EXTERNAL PROVIDER 的指令。
