Azure Synapse Python SDK托管身份读取Key Vault密钥报错排查
你遇到的Connection to 169.254.169.254 timed out报错,核心原因是1.13.0版本以下的azure-identityPython包中,ManagedIdentityCredential默认只会尝试访问Azure全局通用的IMDS端点(169.254.169.254)获取托管身份令牌,但Synapse Apache Spark作业运行在隔离计算环境中,托管身份令牌不通过这个公开IMDS端点发放,而是走Synapse内置的本地令牌服务,老版本SDK没有内置该环境的探测逻辑,就会出现连接超时。
你查到的两份文档不存在实质矛盾:JS SDK故障排查文档提到的不支持,是指对应老版本JS SDK未做Synapse环境适配,并非Synapse服务本身不支持托管身份认证。
按稳定性从高到低排序:
方案1:使用Synapse内置mssparkutils实现认证(最稳定,无兼容问题)
Synapse Spark运行时自带mssparkutils工具集,可直接调用内置令牌服务获取访问凭证,完全绕开IMDS连接问题,同时兼容系统分配、用户分配托管身份。你可以自定义一个符合azure-identity凭证协议的类,直接对接Key Vault SDK,参考代码如下:
from azure.keyvault.secrets import SecretClient from azure.core.credentials import AccessToken from notebookutils import mssparkutils class SynapseMsiCredential: def __init__(self, user_assigned_client_id: str = None): self.client_id = user_assigned_client_id def get_token(self, *scopes, **kwargs): # 固定传入Key Vault的资源ID,获取对应权限的令牌 token_str = mssparkutils.credentials.getToken( "https://vault.azure.net", self.client_id ) return AccessToken(token_str, 0) # 配置参数 kv_uri = "你的Key Vault服务地址,格式为https://<你的kv名称>.vault.azure.net/" secret_name = "需要读取的密钥名称" # 系统分配托管身份用下面这行初始化 # credential = SynapseMsiCredential() # 用户分配托管身份用下面这行初始化,替换为实际的用户分配身份Client ID credential = SynapseMsiCredential(user_assigned_client_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") client = SecretClient(vault_url=kv_uri, credential=credential) retrieved_secret = client.get_secret(secret_name).value
这个方案不需要额外安装第三方依赖,批作业、交互式Notebook环境都可直接运行。
方案2:升级azure-identity包到兼容版本
1.13.0及以上版本的azure-identity包已经新增Synapse Spark环境的自动探测逻辑,会自动识别Synapse环境变量、调用内置令牌服务,不会再尝试连接169.254.169.254端点。升级完成后你原来写的DefaultAzureCredential、ManagedIdentityCredential代码不需要修改即可正常运行。
注意:需要将符合版本要求的azure-identity包配置为Spark作业的依赖,不要使用Spark运行时预装的老版本包。
- 出现IMDS连接超时错误时,不需要反复检查Key Vault的IAM角色、访问策略配置:这个错误发生在获取令牌阶段,请求还没发到Key Vault服务,和Key Vault侧权限配置无关。
- 给Synapse工作区附加托管身份后,需要确认对应Spark池已经开启托管身份挂载,附加新的用户分配身份后建议重启Spark池,避免配置不生效。
- 不要在Synapse Spark环境里手动指定IMDS端点地址,内置令牌服务不需要公网访问,手动改端点反而会触发网络策略拦截。
内容的提问来源于stack exchange,提问作者Rafs

