关于 azure-security-keyvault-secrets-java
使用 Azure SDK 管理 Azure Key Vault 机密的 Java 技能,涵盖创建、获取、版本管理、恢复和备份,并说明凭据处理及破坏性操作的安全注意事项。
主要功能
- 01创建和获取机密
- 02列出机密属性与版本
- 03更新机密元数据
- 04删除和恢复机密
- 05备份和还原机密
- 06使用同步或异步客户端
适用场景
- 01从保险库加载应用凭据
- 02轮换时创建新的机密版本
- 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 |
contentType | MIME 类型提示 |
enabled | 是否可以获取此机密 |
notBefore | 生效时间 |
expiresOn | 过期时间 |
createdOn | 创建时间戳 |
updatedOn | 上次更新时间戳 |
recoveryLevel | 软删除恢复级别 |
tags | 用户定义的元数据 |
环境变量
AZURE_KEYVAULT_URL=https://<vault-name>.vault.azure.net
最佳实践
- 启用软删除 - 防止意外删除
- 使用标记 - 为机密添加环境、服务和所有者标记
- 设置过期时间 - 对需要轮换的凭据使用
setExpiresOn() - 内容类型 - 设置
contentType以指示格式(例如,application/json) - 版本管理 - 轮换时不要立即删除旧版本
- 访问日志记录 - 在 Key Vault 上启用诊断日志记录
- 最小权限 - 为不同环境使用独立的保管库
常见机密类型
// 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