mcpField
A
azure-security-keyvault-secrets-java

azure-security-keyvault-secrets-java

github.com/sickn33安全48.7k65 次安装今天更新
代码仓库

关于 azure-security-keyvault-secrets-java

使用 Azure SDK 管理 Azure Key Vault 机密的 Java 技能,涵盖创建、获取、版本管理、恢复和备份,并说明凭据处理及破坏性操作的安全注意事项。

主要功能

  1. 01创建和获取机密
  2. 02列出机密属性与版本
  3. 03更新机密元数据
  4. 04删除和恢复机密
  5. 05备份和还原机密
  6. 06使用同步或异步客户端

适用场景

  1. 01从保险库加载应用凭据
  2. 02轮换时创建新的机密版本
  3. 03恢复或还原已存储的机密

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sickn33/agentic-awesome-skills --skill azure-security-keyvault-secrets-java

安装后在 Claude Code 中输入/azure-security-keyvault-secrets-java确认已加载。

详细介绍

Azure Key Vault Secrets(Java)

安全地存储和管理密码、API 密钥和连接字符串等机密。

执行变更前,请确认保管库、租户、RBAC 以及要操作的机密和版本。示例使用合成值:请从经批准的机密输入源获取真实值,切勿从源代码或聊天记录中获取。备份包含敏感的加密材料,并且受服务恢复限制;请妥善保护文件并管理保留期限。过期元数据不等于在签发凭据的服务中轮换凭据。如果必需的机密不可用,必须以故障关闭方式处理;不得在配置不完整的情况下静默启动。异步代码片段需要错误处理机制,并且应用程序生命周期必须等待操作完成。

安装

<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-security-keyvault-secrets</artifactId>
    <version>4.9.0</version>
</dependency>

创建客户端

import com.azure.security.keyvault.secrets.SecretClient;
import com.azure.security.keyvault.secrets.SecretClientBuilder;
import com.azure.identity.DefaultAzureCredentialBuilder;

// Sync client
SecretClient secretClient = new SecretClientBuilder()
    .vaultUrl("https://<vault-name>.vault.azure.net")
    .credential(new DefaultAzureCredentialBuilder().build())
    .buildClient();

// Async client
SecretAsyncClient secretAsyncClient = new SecretClientBuilder()
    .vaultUrl("https://<vault-name>.vault.azure.net")
    .credential(new DefaultAzureCredentialBuilder().build())
    .buildAsyncClient();

创建/设置机密

import com.azure.security.keyvault.secrets.models.KeyVaultSecret;

// Simple secret
KeyVaultSecret secret = secretClient.setSecret("database-password", "P@ssw0rd123!");
System.out.println("Secret name: " + secret.getName());
System.out.println("Secret ID: " + secret.getId());

// Secret with options
KeyVaultSecret secretWithOptions = secretClient.setSecret(
    new KeyVaultSecret("api-key", "sk_live_abc123xyz")
        .setProperties(new SecretProperties()
            .setContentType("application/json")
            .setExpiresOn(OffsetDateTime.now().plusYears(1))
            .setNotBefore(OffsetDateTime.now())
            .setEnabled(true)
            .setTags(Map.of(
                "environment", "production",
                "service", "payment-api"
            ))
        )
);

获取机密

// Get latest version
KeyVaultSecret secret = secretClient.getSecret("database-password");
String value = secret.getValue();
// Consume value in memory; never print secret material.

// Get specific version
KeyVaultSecret specificVersion = secretClient.getSecret("database-password", "<version-id>");

// Get only properties (no value)
SecretProperties props = secretClient.getSecret("database-password").getProperties();
System.out.println("Enabled: " + props.isEnabled());
System.out.println("Created: " + props.getCreatedOn());

更新机密属性

// Get secret
KeyVaultSecret secret = secretClient.getSecret("api-key");

// Update properties (cannot update value - create new version instead)
secret.getProperties()
    .setEnabled(false)
    .setExpiresOn(OffsetDateTime.now().plusMonths(6))
    .setTags(Map.of("status", "rotating"));

SecretProperties updated = secretClient.updateSecretProperties(secret.getProperties());
System.out.println("Updated: " + updated.getUpdatedOn());

列出机密

import com.azure.core.util.paging.PagedIterable;
import com.azure.security.keyvault.secrets.models.SecretProperties;

// List all secrets (properties only, no values)
for (SecretProperties secretProps : secretClient.listPropertiesOfSecrets()) {
    System.out.println("Secret: " + secretProps.getName());
    System.out.println("  Enabled: " + secretProps.isEnabled());
    System.out.println("  Created: " + secretProps.getCreatedOn());
    System.out.println("  Content-Type: " + secretProps.getContentType());
    
    // Get value if needed
    if (secretProps.isEnabled()) {
        KeyVaultSecret fullSecret = secretClient.getSecret(secretProps.getName());
        // Do not print even a prefix of the secret.
    }
}

// List versions of a secret
for (SecretProperties version : secretClient.listPropertiesOfSecretVersions("database-password")) {
    System.out.println("Version: " + version.getVersion());
    System.out.println("Created: " + version.getCreatedOn());
    System.out.println("Enabled: " + version.isEnabled());
}

删除机密

import com.azure.core.util.polling.SyncPoller;
import com.azure.security.keyvault.secrets.models.DeletedSecret;

// Begin delete (returns poller for soft-delete enabled vaults)
SyncPoller<DeletedSecret, Void> deletePoller = secretClient.beginDeleteSecret("old-secret");

// Wait for deletion
DeletedSecret deletedSecret = deletePoller.poll().getValue();
System.out.println("Deleted on: " + deletedSecret.getDeletedOn());
System.out.println("Scheduled purge: " + deletedSecret.getScheduledPurgeDate());

deletePoller.waitForCompletion();

恢复已删除的机密

// List deleted secrets
for (DeletedSecret deleted : secretClient.listDeletedSecrets()) {
    System.out.println("Deleted: " + deleted.getName());
    System.out.println("Deletion date: " + deleted.getDeletedOn());
}

// Recover deleted secret
SyncPoller<KeyVaultSecret, Void> recoverPoller = secretClient.beginRecoverDeletedSecret("old-secret");
recoverPoller.waitForCompletion();

KeyVaultSecret recovered = secretClient.getSecret("old-secret");
System.out.println("Recovered: " + recovered.getName());

清除已删除的机密

// This is a separate irreversible operation, not the next step after recovery.
// Get deleted secret info first
DeletedSecret deleted = secretClient.getDeletedSecret("old-secret");
System.out.println("Will purge: " + deleted.getName());
secretClient.purgeDeletedSecret("old-secret");

备份和还原

// Backup secret (all versions)
byte[] backup = secretClient.backupSecret("important-secret");

// Save to file
Files.write(Paths.get("secret-backup.blob"), backup);

// Restore from backup
byte[] backupData = Files.readAllBytes(Paths.get("secret-backup.blob"));
KeyVaultSecret restored = secretClient.restoreSecretBackup(backupData);
System.out.println("Restored: " + restored.getName());

异步操作

SecretAsyncClient asyncClient = new SecretClientBuilder()
    .vaultUrl("https://<vault>.vault.azure.net")
    .credential(new DefaultAzureCredentialBuilder().build())
    .buildAsyncClient();

// Set secret async
asyncClient.setSecret("async-secret", "async-value")
    .subscribe(
        secret -> System.out.println("Created: " + secret.getName()),
        error -> System.out.println("Error: " + error.getMessage())
    );

// Get secret async
asyncClient.getSecret("async-secret")
    .subscribe(secret -> { /* consume secret.getValue() without logging it */ });

// List secrets async
asyncClient.listPropertiesOfSecrets()
    .doOnNext(props -> System.out.println("Found: " + props.getName()))
    .subscribe();

配置模式

加载多个机密
public class ConfigLoader {
    private final SecretClient client;
    
    public ConfigLoader(String vaultUrl) {
        this.client = new SecretClientBuilder()
            .vaultUrl(vaultUrl)
            .credential(new DefaultAzureCredentialBuilder().build())
            .buildClient();
    }
    
    public Map<String, String> loadSecrets(List<String> secretNames) {
        Map<String, String> secrets = new HashMap<>();
        for (String name : secretNames) {
            try {
                KeyVaultSecret secret = client.getSecret(name);
                secrets.put(name, secret.getValue());
            } catch (ResourceNotFoundException e) {
                System.out.println("Secret not found: " + name);
            }
        }
        return secrets;
    }
}

// Usage
ConfigLoader loader = new ConfigLoader("https://my-vault.vault.azure.net");
Map<String, String> config = loader.loadSecrets(
    Arrays.asList("db-connection-string", "api-key", "jwt-secret")
);
机密轮换模式
public void rotateSecret(String secretName, String newValue) {
    // Get current secret
    KeyVaultSecret current = secretClient.getSecret(secretName);
    
    // Create and verify the new credential at its issuing service first.
    // Create a new version; migrate and verify consumers before retiring the old one.
    KeyVaultSecret newSecret = secretClient.setSecret(secretName, newValue);
    System.out.println("Rotated to version: " + newSecret.getProperties().getVersion());
}

错误处理

import com.azure.core.exception.HttpResponseException;
import com.azure.core.exception.ResourceNotFoundException;

try {
    KeyVaultSecret secret = secretClient.getSecret("my-secret");
    // Consume secret.getValue() without logging it.
} catch (ResourceNotFoundException e) {
    System.out.println("Secret not found");
} catch (HttpResponseException e) {
    int status = e.getResponse().getStatusCode();
    if (status == 403) {
        System.out.println("Access denied - check permissions");
    } else if (status == 429) {
        System.out.println("Rate limited - retry later");
    } else {
        System.out.println("HTTP error: " + status);
    }
}

机密属性

属性描述
name机密名称
value机密值(字符串)
id完整标识符 URL
contentTypeMIME 类型提示
enabled是否可以获取此机密
notBefore生效时间
expiresOn过期时间
createdOn创建时间戳
updatedOn上次更新时间戳
recoveryLevel软删除恢复级别
tags用户定义的元数据

环境变量

AZURE_KEYVAULT_URL=https://<vault-name>.vault.azure.net

最佳实践

  1. 启用软删除 - 防止意外删除
  2. 使用标记 - 为机密添加环境、服务和所有者标记
  3. 设置过期时间 - 对需要轮换的凭据使用 setExpiresOn()
  4. 内容类型 - 设置 contentType 以指示格式(例如,application/json)
  5. 版本管理 - 轮换时不要立即删除旧版本
  6. 访问日志记录 - 在 Key Vault 上启用诊断日志记录
  7. 最小权限 - 为不同环境使用独立的保管库

常见机密类型

// Database connection string
secretClient.setSecret(new KeyVaultSecret("db-connection", 
    "Server=myserver.database.windows.net;Database=mydb;...")
    .setProperties(new SecretProperties()
        .setContentType("text/plain")
        .setTags(Map.of("type", "connection-string"))));

// API key
secretClient.setSecret(new KeyVaultSecret("stripe-api-key", "sk_live_...")
    .setProperties(new SecretProperties()
        .setContentType("text/plain")
        .setExpiresOn(OffsetDateTime.now().plusYears(1))));

// JSON configuration
secretClient.setSecret(new KeyVaultSecret("app-config", 
    "{\"endpoint\":\"https://...\",\"key\":\"...\"}")
    .setProperties(new SecretProperties()
        .setContentType("application/json")));

// Certificate password
secretClient.setSecret(new KeyVaultSecret("cert-password", "CertP@ss!")
    .setProperties(new SecretProperties()
        .setContentType("text/plain")
        .setTags(Map.of("certificate", "my-cert"))));

触发短语

  • “Key Vault secrets Java”、“secret management Java”
  • “store password”、“store API key”、“connection string”
  • “retrieve secret”、“rotate secret”
  • “Azure secrets”、“vault secrets”

适用场景

当需要执行概述中描述的工作流或操作时,可使用此技能。

限制

  • 仅当任务明确符合上述范围时,才使用此技能。
  • 不要将输出视为环境特定验证、测试或专家审查的替代品。
  • 如果缺少必需的输入、权限、安全边界或成功标准,请暂停并请求澄清。

评论

支持 Markdown