使用托管身份从Azure VM访问Blob存储的后续步骤及认证问题
已完成以下配置:
- 为Azure VM启用了Azure托管身份
- 授予VM访问Azure Blob存储的权限
现需明确访问Blob并列出目录的后续步骤,同时确认:
- 是否需要在VM上配置凭据?
- 仅通过Python代码直接访问是否必须使用CLI?
当前遇到的错误
使用ManagedIdentityCredential时的错误:
Listing directories in container: optitex
ImdsCredential.get_token_info failed: ManagedIdentityCredential authentication unavailable.
ManagedIdentityCredential.get_token_info failed: ManagedIdentityCredential authentication unavailable.
改用DefaultAzureCredential时的错误:
DefaultAzureCredential failed to retrieve a token from the included credentials.
Attempted credentials:
EnvironmentCredential: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
ManagedIdentityCredential: ManagedIdentityCredential authentication unavailable.
SharedTokenCacheCredential: SharedTokenCacheCredential authentication unavailable. No accounts were found in the cache.
AzureCliCredential: Azure CLI not found on path
AzurePowerShellCredential: Az.Account module >= 2.2.0 is not installed
AzureDeveloperCliCredential: Azure Developer CLI could not be found.
使用的Python代码
from azure.storage.blob import BlobServiceClient from azure.core.exceptions import ResourceNotFoundError # 原代码遗漏身份验证类导入,需补充 from azure.identity import ManagedIdentityCredential, DefaultAzureCredential # 列出容器内目录的函数 def list_directories_in_blob_container(storage_account_name, container_name): try: # 尝试使用托管身份凭据 try: print('********') credential = ManagedIdentityCredential() except Exception as e: print(f"ManagedIdentityCredential失败: {e}") print("回退到DefaultAzureCredential") credential = DefaultAzureCredential() blob_service_client = BlobServiceClient( account_url=f"https://{storage_account_name}.blob.core.windows.net", credential=credential ) # 获取容器客户端 container_client = blob_service_client.get_container_client(container_name) # 列出所有Blob并识别目录 print(f"正在列出容器 {container_name} 中的目录:") blob_list = container_client.walk_blobs() directories = set() for blob in blob_list: blob_path_parts = blob.name.split('/') if len(blob_path_parts) > 1: directories.add(blob_path_parts[0]) # 输出结果 if directories: print("找到的目录:") for directory in sorted(directories): print(f" - {directory}") else: print("未找到目录。") except ResourceNotFoundError: print(f"存储账户 '{storage_account_name}' 中未找到容器 '{container_name}'。") except Exception as ex: print(f"发生错误: {ex}") # 示例调用 if __name__ == "__main__": storage_account_name = "xxx" container_name = "xxx" list_directories_in_blob_container(storage_account_name, container_name)
核心结论
- 不需要额外配置CLI或环境变量:你已为VM启用系统托管身份并授予Blob访问权限,理论上直接通过托管身份即可完成验证。
- 不需要在VM上手动配置凭据:托管身份会自动从Azure实例元数据服务(IMDS)获取令牌,无需手动配置任何凭据文件或环境变量。
后续步骤及问题排查
补充代码缺失的导入:原代码未导入
ManagedIdentityCredential和DefaultAzureCredential,这是运行错误的直接原因之一,必须添加对应的导入语句。排查托管身份未生效的原因
- 确认VM的系统托管身份状态:在Azure门户的VM“身份”选项卡中,检查“系统分配”是否为“开启”状态。
- 验证角色分配正确性:确保为VM托管身份分配了存储Blob数据读取者或更高权限的角色,且角色作用范围覆盖目标存储账户或容器。
- 检查VM对IMDS的访问权限:在VM内部执行命令
curl http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fstorage.azure.com/,如果无法返回令牌,说明NSG或其他网络策略限制了VM访问IMDS服务。
简化代码逻辑:无需手动切换凭据类型,直接使用
DefaultAzureCredential即可,它会自动优先尝试托管身份验证,失败后才会尝试其他方式:credential = DefaultAzureCredential()
关于CLI的说明
仅通过Python代码访问Blob存储不需要使用CLI,CLI只是DefaultAzureCredential尝试的身份验证方式之一,并非必须配置。当托管身份正常工作时,DefaultAzureCredential会自动使用托管身份完成验证,无需依赖CLI。
内容的提问来源于stack exchange,提问作者Md Neyaz

