You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中使用Azure Key Vault访问Blob Storage列文件时认证失败

Azure Key Vault认证失败问题解决方案

问题描述

我可以直接使用Blob存储的连接字符串或访问密钥列出Azure Blob Storage中的文件,但为避免密钥硬编码到代码中,改用Azure Key Vault获取访问密钥时出现认证错误(确认已有足够权限,无Key Vault时代码可正常运行)。

代码片段

package org.example;
import com.azure.storage.common.StorageSharedKeyCredential;
import com.azure.identity.DefaultAzureCredentialBuilder;
import com.azure.security.keyvault.secrets.SecretClient;
import com.azure.security.keyvault.secrets.SecretClientBuilder;
import com.azure.security.keyvault.secrets.models.KeyVaultSecret;
import com.azure.storage.blob.BlobContainerClient;
import com.azure.storage.blob.BlobServiceClient;
import com.azure.storage.blob.BlobServiceClientBuilder;
import com.azure.storage.blob.models.BlobItem;

public class ListKeyVaultSecrets {
    public static void main(String[] args) {

        String accountName = "";
        String containerName = "";
        String secretName = "";
        String keyVaultUrl = "";

        SecretClient secretClient = new SecretClientBuilder()
                .vaultUrl(keyVaultUrl)
                .credential(new DefaultAzureCredentialBuilder().build())
                .buildClient();

        KeyVaultSecret secret = secretClient.getSecret(secretName); // 错误发生在此处
        String accountKey = secret.getValue();

        BlobServiceClient blobServiceClient = new BlobServiceClientBuilder()
                .endpoint(String.format("https://%s.blob.core.windows.net", accountName))
                .credential(new StorageSharedKeyCredential(accountName, accountKey))
                .buildClient();

        BlobContainerClient containerClient = blobServiceClient.getBlobContainerClient(containerName);

        for (BlobItem blobItem : containerClient.listBlobs()) {
            System.out.println(blobItem.getName());
        }
    }
}

报错信息

[main] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential EnvironmentCredential is unavailable.
[ForkJoinPool.commonPool-worker-1] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential ManagedIdentityCredential is unavailable.
[ForkJoinPool.commonPool-worker-1] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential SharedTokenCacheCredential is unavailable.
[ForkJoinPool.commonPool-worker-1] ERROR com.azure.identity.implementation.WindowsCredentialAccessor - Elemento não encontrado.
[ForkJoinPool.commonPool-worker-1] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential IntelliJCredential is unavailable.
[ForkJoinPool.commonPool-worker-1] ERROR com.azure.identity.implementation.IdentityClient - 'az' não é reconhecido como um comando internoou externo, um programa operável ou um arquivo em lotes.
[ForkJoinPool.commonPool-worker-1] ERROR com.azure.identity.implementation.IdentityClient - 'az' não é reconhecido como um comando internoou externo, um programa operável ou um arquivo em lotes.
[ForkJoinPool.commonPool-worker-1] ERROR com.azure.core.implementation.AccessTokenCache - Failed to acquire a new access token.
[parallel-1] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential EnvironmentCredential is unavailable.
[ForkJoinPool.commonPool-worker-1] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential ManagedIdentityCredential is unavailable.
[ForkJoinPool.commonPool-worker-2] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential SharedTokenCacheCredential is unavailable.
[ForkJoinPool.commonPool-worker-2] ERROR com.azure.identity.implementation.WindowsCredentialAccessor - Elemento não encontrado.
[ForkJoinPool.commonPool-worker-2] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential IntelliJCredential is unavailable.
[ForkJoinPool.commonPool-worker-2] ERROR com.azure.identity.implementation.IdentityClient - 'az' não é reconhecido como um comando internoou externo, um programa operável ou um arquivo em lotes.
[ForkJoinPool.commonPool-worker-2] ERROR com.azure.identity.implementation.IdentityClient - 'az' não é reconhecido como um comando internoou externo, um programa operável ou um arquivo em lotes.
[ForkJoinPool.commonPool-worker-2] ERROR com.azure.core.implementation.AccessTokenCache - Failed to acquire a new access token.
[parallel-2] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential EnvironmentCredential is unavailable.
[ForkJoinPool.commonPool-worker-2] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential ManagedIdentityCredential is unavailable.
[ForkJoinPool.commonPool-worker-1] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential SharedTokenCacheCredential is unavailable.
[ForkJoinPool.commonPool-worker-1] ERROR com.azure.identity.implementation.WindowsCredentialAccessor - Elemento não encontrado.
[ForkJoinPool.commonPool-worker-1] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential IntelliJCredential is unavailable.
[ForkJoinPool.commonPool-worker-1] ERROR com.azure.identity.implementation.IdentityClient - 'az' não é reconhecido como um comando internoou externo, um programa operável ou um arquivo em lotes.
[ForkJoinPool.commonPool-worker-1] ERROR com.azure.identity.implementation.IdentityClient - 'az' não é reconhecido como um comando internoou externo, um programa operável ou um arquivo em lotes.
[ForkJoinPool.commonPool-worker-1] ERROR com.azure.core.implementation.AccessTokenCache - Failed to acquire a new access token.
[parallel-3] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential EnvironmentCredential is unavailable.
[ForkJoinPool.commonPool-worker-1] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential ManagedIdentityCredential is unavailable.
[ForkJoinPool.commonPool-worker-1] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential SharedTokenCacheCredential is unavailable.
[ForkJoinPool.commonPool-worker-1] ERROR com.azure.identity.implementation.WindowsCredentialAccessor - Elemento não encontrado.
[ForkJoinPool.commonPool-worker-1] INFO com.azure.identity.ChainedTokenCredential - Azure Identity => Attempted credential IntelliJCredential is unavailable.
[ForkJoinPool.commonPool-worker-1] ERROR com.azure.identity.implementation.IdentityClient - 'az' não é reconhecido como um comando internoou externo, um programa operável ou um arquivo em lotes.
[ForkJoinPool.commonPool-worker-1] ERROR com.azure.identity.implementation.IdentityClient - 'az' não é reconhecido como um comando internoou externo, um programa operável ou um arquivo em lotes.
[ForkJoinPool.commonPool-worker-1] ERROR com.azure.core.implementation.AccessTokenCache - Failed to acquire a new access token.
[main] ERROR com.azure.core.http.policy.RetryPolicy - {"az.sdk.message":"Retry attempts have been exhausted.","exception":"DefaultAzureCredential authentication failed. ---> AzureCliCredential authentication failed. Error Details: 'az' não é reconhecido como um comando internoou externo, um programa operável ou um arquivo em lotes.","tryCount":3}
[main] ERROR com.azure.core.http.policy.RetryPolicy - DefaultAzureCredential authentication failed. ---> AzureCliCredential authentication failed. Error Details: 'az' não é reconhecido como um comando internoou externo, um programa operável ou um arquivo em lotes.
[main] ERROR com.azure.core.implementation.http.rest.RestProxyBase - DefaultAzureCredential authentication failed. ---> AzureCliCredential authentication failed. Error Details: 'az' não é reconhecido como um comando internoou externo, um programa operável ou um arquivo em lotes.

I've tried most of the solutions on the documentation but it doesnt seem to work for some reason.

报错分析

从日志可以明确看到,DefaultAzureCredential依次尝试了所有内置认证方式但全部失败:

  • 环境变量凭证:未配置相关Azure认证环境变量
  • 托管身份凭证:当前运行环境(本地)没有启用Azure托管身份
  • 共享令牌缓存凭证:无可用的缓存令牌
  • IntelliJ凭证:未在IDE中配置Azure账户认证
  • Azure CLI凭证:系统未安装Azure CLI,或未执行登录操作

核心问题是本地运行时没有为DefaultAzureCredential提供有效的认证途径,导致无法访问Key Vault。

解决方案

方案1:安装并登录Azure CLI(本地调试首选)

  1. 下载安装对应系统的Azure CLI
  2. 打开命令行执行登录命令:
az login
  1. 登录成功后重新运行代码,DefaultAzureCredential会自动使用CLI的登录凭证访问Key Vault。

方案2:配置服务主体环境变量

  1. 在Azure AD中创建服务主体,并为其分配Key Vault的**密钥读取者(Secret Reader)**权限
  2. 获取服务主体的client-id、client-secret、tenant-id
  3. 设置系统环境变量:
    • AZURE_CLIENT_ID:服务主体的客户端ID
    • AZURE_CLIENT_SECRET:服务主体的客户端密钥
    • AZURE_TENANT_ID:服务主体所在租户ID
  4. 重启IDE或命令行,让环境变量生效后运行代码

方案3:IDE中配置Azure认证(以IntelliJ为例)

  1. 安装IntelliJ Azure插件,添加并登录拥有Key Vault访问权限的Azure账户
  2. 重新运行代码,DefaultAzureCredential会自动读取IDE中的认证信息

方案4:使用托管身份(部署到Azure服务时)

若代码将部署到Azure服务(如App Service、VM等):

  1. 为目标Azure服务启用系统分配或用户分配的托管身份
  2. 给该托管身份分配Key Vault的密钥读取者权限
  3. 部署后代码会自动使用托管身份认证,无需额外配置

额外优化:直接用Azure AD认证访问Blob Storage(更安全)

可以跳过从Key Vault获取存储账户密钥的步骤,直接用Azure AD身份认证访问Blob Storage,进一步提升安全性:
修改代码如下,无需获取存储账户密钥:

BlobServiceClient blobServiceClient = new BlobServiceClientBuilder()
        .endpoint(String.format("https://%s.blob.core.windows.net", accountName))
        .credential(new DefaultAzureCredentialBuilder().build())
        .buildClient();

需要给认证主体(服务主体、托管身份等)分配Blob存储的存储Blob数据读取者权限。


内容的提问来源于stack exchange,提问作者Italo Gonçalves

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 17:24:57