azure-security-keyvault-secrets-java

SDK Java Azure Key Vault Secrets pour la gestion des secrets. À utiliser lors du stockage, de la récupération ou de la gestion des mots de passe, clés API, chaînes de connexion ou 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)

Stockez et gérez de manière sécurisée les secrets tels que les mots de passe, les clés API et les 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"
            ))
        )
);

Obtenir un secret

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

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

// Obtenir uniquement les propriétés (pas 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 du secret

// Obtenir 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, pas les 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());

    // Obtenir 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 enquêteur 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 le 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 façon asynchrone
asyncClient.setSecret("async-secret", "async-value")
    .subscribe(
        secret -> System.out.println("Created: " + secret.getName()),
        error -> System.out.println("Error: " + error.getMessage())
    );

// Obtenir un secret de façon asynchrone
asyncClient.getSecret("async-secret")
    .subscribe(secret -> System.out.println("Value: " + secret.getValue()));

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

Modèles 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")
);

Modèle de rotation de secret

public void rotateSecret(String secretName, String newValue) {
    // Obtenir 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 de l'identifiant complet
contentType Indication 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

Meilleures pratiques

  1. Activer la suppression réversible - Protège contre la suppression accidentelle
  2. Utiliser les tags - Taguez les secrets avec l'environnement, le service, le propriétaire
  3. Définir une expiration - Utilisez setExpiresOn() pour les identifiants qui doivent être renouvelés
  4. Type de contenu - Définissez contentType pour indiquer le format (par ex. application/json)
  5. Gestion des versions - Ne supprimez pas les anciennes versions immédiatement lors de la rotation
  6. Journalisation des accès - Activez la journalisation des diagnostics sur Key Vault
  7. Privilège minimum - Utilisez des coffres séparés pour différents environnements

Types de secrets courants

// Chaîne de connexion à la 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"