Databricks用Azure托管标识对象ID连接SQL Server报错排查
结论
可以在Databricks平台使用Azure托管标识建立与Azure SQL Server的连接,但不支持使用托管标识的对象ID完成认证,认证流程必须使用托管标识对应的客户端(应用)ID。你遇到的DefaultAzureCredential failed to retrieve a token from the included credentials报错由配置错误或环境缺失导致,以下是具体排障方案和实现步骤。
常见报错排障点
- 参数使用错误:你当前代码里直接传入了未定义的
client_id变量,且最初计划使用托管标识对象ID认证,这是认证失败的核心原因之一。必须先给client_id变量赋值为托管标识的客户端ID,对象ID无法通过元数据服务拉取有效令牌。 - 托管标识未绑定到计算资源:Azure Databricks需要提前给对应集群、SQL仓库绑定系统分配托管标识,或关联已创建的用户分配托管标识,未绑定标识的计算资源无法调用Azure实例元数据服务拉取访问令牌。
- 网络拦截:如果集群配置了自定义虚拟网络,需要确认网络安全组、防火墙规则没有拦截到169.254.169.254(Azure实例元数据服务地址)的请求,拦截该请求会直接导致令牌拉取失败。
- 依赖版本问题:如果集群安装的
azure-identitySDK版本过低,可能存在托管标识认证逻辑的已知bug,建议升级到1.12.0以上版本。
可直接复用的实现方案
优先使用Databricks内置JDBC连接器实现认证,不需要手动安装SDK、手动拉取令牌,稳定性更高:
# 替换为你的SQL Server地址、目标数据库名 jdbc_url = "jdbc:sqlserver://bipp-training-server.database.windows.net:1433;database=你的目标数据库名;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;" df = spark.read.format("jdbc") \ .option("url", jdbc_url) \ .option("dbtable", "你的目标表名") \ .option("authentication", "ActiveDirectoryMSI") \ # 系统分配托管标识可省略下面这行,用户分配托管标识需要填入对应客户端ID .option("aadSecurePrincipalId", "你的用户分配托管标识客户端ID") \ .load()
如果你需要沿用手动拉取令牌的逻辑,可以参考以下修正后的代码:
from azure.core.exceptions import ClientAuthenticationError from azure.identity import ManagedIdentityCredential # 替换为你的用户分配托管标识客户端ID,使用系统分配托管标识可省略该参数赋值 client_id = "你的托管标识客户端ID" # 显式使用ManagedIdentityCredential,避免DefaultAzureCredential遍历多余认证源提升稳定性 credential = ManagedIdentityCredential(client_id=client_id) try: # 拉取SQL Server对应的访问令牌 token = credential.get_token("https://database.windows.net/.default") # 将令牌拼入JDBC连接串建立连接 jdbc_url = f"jdbc:sqlserver://bipp-training-server.database.windows.net:1433;database=你的目标数据库名;accessToken={token.token};encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;" df = spark.read.jdbc(url=jdbc_url, table="你的目标表名") except ClientAuthenticationError as ex: print(ex.message)
SQL侧必要前置配置
完成Databricks侧配置后,需要提前在目标Azure SQL数据库中执行以下SQL语句,给托管标识授予对应访问权限,否则即使拿到有效令牌也会被SQL服务拒绝连接:
-- 在目标数据库下创建托管标识对应的数据库用户,名称和你创建的托管标识名称一致 CREATE USER [你的托管标识名称] FROM EXTERNAL PROVIDER; -- 按需授予权限,以下示例授予库表读写权限 ALTER ROLE db_datareader ADD MEMBER [你的托管标识名称]; ALTER ROLE db_datawriter ADD MEMBER [你的托管标识名称];
内容的提问来源于stack exchange,提问作者Jeevan Kande
相关产品推荐
相关产品推荐

