在Azure DevOps流水线中使用工作负载身份联合认证Azure SQL失败求助
Azure DevOps流水线Python连接Azure SQL数据库认证失败解决方案
错误日志
开始执行: 单元测试 ============================================================================== 任务 : 命令行 描述 : 在Linux和macOS上使用Bash,在Windows上使用cmd.exe运行命令行脚本 版本 : 2.231.0 作者 : 微软公司 ============================================================================== 正在生成脚本。 脚本内容: python3 app.py ========================== 开始命令输出 =========================== /usr/bin/bash --noprofile --norc /azp/_work/_temp/2b90c137-aea9-43d5-8709-8aef64dbbbcc.sh InteractiveBrowserCredential.get_token 失败: 无法打开浏览器 DefaultAzureCredential 无法从包含的凭据中检索令牌。 尝试的凭据: EnvironmentCredential: EnvironmentCredential 认证不可用。环境变量未完全配置。 ManagedIdentityCredential: ManagedIdentityCredential 认证不可用,IMDS端点无响应。 SharedTokenCacheCredential: SharedTokenCacheCredential 认证不可用。缓存中未找到账户。 AzureCliCredential: 路径中未找到Azure CLI AzurePowerShellCredential: 未安装PowerShell AzureDeveloperCliCredential: 找不到Azure Developer CLI。 InteractiveBrowserCredential: 无法打开浏览器 Traceback (most recent call last):
已执行的操作
- 在Azure DevOps项目中创建了用于Azure ARM的「工作负载身份联合」服务连接
- 服务连接的流水线权限设置为无限制
- 为创建的企业应用授予「Azure SQL Database」权限
- 在SSMS中执行以下SQL查询:
CREATE LOGIN [app_name] FROM EXTERNAL PROVIDER; USE [Profile] GO; CREATE USER [app_name] FROM LOGIN [app_name]; ALTER ROLE db_datareader ADD MEMBER [app_name]; ALTER ROLE db_datawriter ADD MEMBER [app_name];
- Python代码如下:
import pyodbc, struct from azure import identity connection_string = 'Driver={ODBC Driver 18 for SQL Server};Server=tcp:dylanbartley.database.windows.net,1433;Database=Profile;Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30' def get_conn(): credential = identity.DefaultAzureCredential(exclude_interactive_browser_credential=False) token = credential.get_token("https://database.windows.net/.default").token token_bytes = token.encode("UTF-16-LE") token_struct = struct.pack(f'<I{len(token_bytes)}s', len(token_bytes), token_bytes) SQL_COPT_SS_ACCESS_TOKEN = 1256 # 此连接选项由微软在msodbcsql.h中定义 conn = pyodbc.connect(connection_string, attrs_before={SQL_COPT_SS_ACCESS_TOKEN: token_struct}) return conn def get_contacts(): records = [] with get_conn() as conn: cursor = conn.cursor() cursor.execute("select * from Contacts") for row in cursor.fetchall(): records.append(row.Id) return records rows = get_contacts() print(len(rows))
- 当前使用的流水线YAML:
trigger: - main pool: Default strategy: matrix: Python311: python.version: '3.11' steps: - script: | python3 -m pip install --upgrade pip pip3 install pyodbc azure-identity displayName: '安装依赖' - script: | python3 app.py displayName: '运行连接测试'
解决方案
1. 修改流水线YAML,添加工作负载身份联合认证步骤
在流水线中添加AzureCLI任务,通过已创建的工作负载身份联合服务连接获取认证上下文,自动生成DefaultAzureCredential可识别的环境变量。修改后的YAML如下:
trigger: - main pool: Default strategy: matrix: Python311: python.version: '3.11' steps: - script: | python3 -m pip install --upgrade pip pip3 install pyodbc azure-identity displayName: '安装依赖' # 添加Azure CLI任务,使用工作负载身份联合服务连接完成认证 - task: AzureCLI@2 inputs: azureSubscription: '你的工作负载身份联合服务连接名称' scriptType: 'bash' scriptLocation: 'inlineScript' inlineScript: | echo "Azure CLI认证完成" displayName: '通过工作负载身份联合认证' - script: | python3 app.py displayName: '运行连接测试'
2. 调整Python代码,排除交互式认证
流水线为无交互环境,无需启用交互式浏览器认证,修改DefaultAzureCredential初始化参数:
def get_conn(): # 排除交互式浏览器认证,避免无交互环境报错 credential = identity.DefaultAzureCredential(exclude_interactive_browser_credential=True) token = credential.get_token("https://database.windows.net/.default").token token_bytes = token.encode("UTF-16-LE") token_struct = struct.pack(f'<I{len(token_bytes)}s', len(token_bytes), token_bytes) SQL_COPT_SS_ACCESS_TOKEN = 1256 conn = pyodbc.connect(connection_string, attrs_before={SQL_COPT_SS_ACCESS_TOKEN: token_struct}) return conn
3. 确保代理池具备必要依赖
如果使用自托管代理,需确保代理机器已安装:
- ODBC Driver 18 for SQL Server
- 指定版本的Python(此处为3.11)
内容的提问来源于stack exchange,提问作者Dylan Bartley
相关产品推荐
相关产品推荐

