azure-security-keyvault-secrets-java

SDK Java Azure Key Vault Secrets pour la gestion des secrets. À utiliser pour stocker, récupérer ou gérer des mots de passe, des clés API, des chaînes de connexion ou d'autres données de configuration sensibles.

npx skills add https://github.com/microsoft/skills --skill azure-security-keyvault-secrets-java

Azure Key Vault Secrets (Java)

Stocker et gérer de manière sécurisée les secrets comme les mots de passe, clés API et chaînes de connexion.

Installation

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

Création du client

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

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

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

Créer/Définir un secret

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

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

// Secret avec 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"
            ))
        )
);

Récupérer un secret

// Récupérer la dernière version
KeyVaultSecret secret = secretClient.getSecret("database-password");
String value = secret.getValue();
System.out.println("Secret value: " + value);

// Récupérer une version spécifique
KeyVaultSecret specificVersion = secretClient.getSecret("database-password", "<version-id>");

// Récupérer uniquement les propriétés (sans la valeur)
SecretProperties props = secretClient.getSecret("database-password").getProperties();
System.out.println("Enabled: " + props.isEnabled());
System.out.println("Created: " + props.getCreatedOn());

Mettre à jour les propriétés d'un secret

// Récupérer le secret
KeyVaultSecret secret = secretClient.getSecret("api-key");

// Mettre à jour les propriétés (impossible de mettre à jour la valeur - créer une nouvelle version à la place)
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());

Lister les secrets

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

// Lister tous les secrets (propriétés uniquement, sans valeurs)
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());

    // Récupérer la valeur si nécessaire
    if (secretProps.isEnabled()) {
        KeyVaultSecret fullSecret = secretClient.getSecret(secretProps.getName());
        System.out.println("  Value: " + fullSecret.getValue().substring(0, 5) + "...");
    }
}

// Lister les versions d'un 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());
}

Supprimer un secret

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

// Commencer la suppression (retourne un poller pour les coffres avec soft-delete activé)
SyncPoller<DeletedSecret, Void> deletePoller = secretClient.beginDeleteSecret("old-secret");

// Attendre la suppression
DeletedSecret deletedSecret = deletePoller.poll().getValue();
System.out.println("Deleted on: " + deletedSecret.getDeletedOn());
System.out.println("Scheduled purge: " + deletedSecret.getScheduledPurgeDate());

deletePoller.waitForCompletion();

Récupérer un secret supprimé

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

// Récupérer un secret supprimé
SyncPoller<KeyVaultSecret, Void> recoverPoller = secretClient.beginRecoverDeletedSecret("old-secret");
recoverPoller.waitForCompletion();

KeyVaultSecret recovered = recoverPoller.getFinalResult();
System.out.println("Recovered: " + recovered.getName());

Purger un secret supprimé

// Supprimer définitivement (ne peut pas être récupéré)
secretClient.purgeDeletedSecret("old-secret");

// Obtenir d'abord les informations du secret supprimé
DeletedSecret deleted = secretClient.getDeletedSecret("old-secret");
System.out.println("Will purge: " + deleted.getName());
secretClient.purgeDeletedSecret("old-secret");

Sauvegarde et restauration

// Sauvegarder le secret (toutes les versions)
byte[] backup = secretClient.backupSecret("important-secret");

// Enregistrer dans un fichier
Files.write(Paths.get("secret-backup.blob"), backup);

// Restaurer à partir de la sauvegarde
byte[] backupData = Files.readAllBytes(Paths.get("secret-backup.blob"));
KeyVaultSecret restored = secretClient.restoreSecretBackup(backupData);
System.out.println("Restored: " + restored.getName());

Opérations asynchrones

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

// Définir un secret de manière asynchrone
asyncClient.setSecret("async-secret", "async-value")
    .subscribe(
        secret -> System.out.println("Created: " + secret.getName()),
        error -> System.out.println("Error: " + error.getMessage())
    );

// Récupérer un secret de manière asynchrone
asyncClient.getSecret("async-secret")
    .subscribe(secret -> System.out.println("Value: " + secret.getValue()));

// Lister les secrets de manière asynchrone
asyncClient.listPropertiesOfSecrets()
    .doOnNext(props -> System.out.println("Found: " + props.getName()))
    .subscribe();

Patterns de configuration

Charger plusieurs secrets

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;
    }
}

// Utilisation
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")
);

Pattern de rotation de secret

public void rotateSecret(String secretName, String newValue) {
    // Récupérer le secret actuel
    KeyVaultSecret current = secretClient.getSecret(secretName);

    // Désactiver l'ancienne version
    current.getProperties().setEnabled(false);
    secretClient.updateSecretProperties(current.getProperties());

    // Créer une nouvelle version avec la nouvelle valeur
    KeyVaultSecret newSecret = secretClient.setSecret(secretName, newValue);
    System.out.println("Rotated to version: " + newSecret.getProperties().getVersion());
}

Gestion des erreurs

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

try {
    KeyVaultSecret secret = secretClient.getSecret("my-secret");
    System.out.println("Value: " + secret.getValue());
} 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);
    }
}

Propriétés du secret

Propriété Description
name Nom du secret
value Valeur du secret (chaîne)
id URL d'identificateur complet
contentType Indice de type MIME
enabled Si le secret peut être récupéré
notBefore Heure d'activation
expiresOn Heure d'expiration
createdOn Horodatage de création
updatedOn Horodatage de la dernière mise à jour
recoveryLevel Niveau de récupération soft-delete
tags Métadonnées définies par l'utilisateur

Variables d'environnement

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

Bonnes pratiques

  1. Activer le soft delete - Protège contre les suppressions accidentelles
  2. Utiliser les tags - Taguer les secrets avec l'environnement, le service, le propriétaire
  3. Définir l'expiration - Utiliser setExpiresOn() pour les identifiants qui doivent être renouvelés
  4. Content Type - Définir contentType pour indiquer le format (p. ex. application/json)
  5. Gestion des versions - Ne pas supprimer les anciennes versions immédiatement lors de la rotation
  6. Enregistrement d'accès - Activer l'enregistrement des diagnostics sur Key Vault
  7. Privilèges minimaux - Utiliser des coffres séparés pour différents environnements

Types de secrets courants

// Chaîne de connexion à une base de données
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"))));

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

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

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

Expressions déclencheurs

  • "Key Vault secrets Java", "secret management Java"
  • "store password", "store API key", "connection string"
  • "retrieve secret", "rotate secret"
  • "Azure secrets", "vault secrets"

Skills similaires