feat: Add Official Microsoft & Gemini Skills (845+ Total)
🚀 Impact Significantly expands the capabilities of **Antigravity Awesome Skills** by integrating official skill collections from **Microsoft** and **Google Gemini**. This update increases the total skill count to **845+**, making the library even more comprehensive for AI coding assistants. ✨ Key Changes 1. New Official Skills - **Microsoft Skills**: Added a massive collection of official skills from [microsoft/skills](https://github.com/microsoft/skills). - Includes Azure, .NET, Python, TypeScript, and Semantic Kernel skills. - Preserves the original directory structure under `skills/official/microsoft/`. - Includes plugin skills from the `.github/plugins` directory. - **Gemini Skills**: Added official Gemini API development skills under `skills/gemini-api-dev/`. 2. New Scripts & Tooling - **`scripts/sync_microsoft_skills.py`**: A robust synchronization script that: - Clones the official Microsoft repository. - Preserves the original directory heirarchy. - Handles symlinks and plugin locations. - Generates attribution metadata. - **`scripts/tests/inspect_microsoft_repo.py`**: Debug tool to inspect the remote repository structure. - **`scripts/tests/test_comprehensive_coverage.py`**: Verification script to ensure 100% of skills are captured during sync. 3. Core Improvements - **`scripts/generate_index.py`**: Enhanced frontmatter parsing to safely handle unquoted values containing `@` symbols and commas (fixing issues with some Microsoft skill descriptions). - **`package.json`**: Added `sync:microsoft` and `sync:all-official` scripts for easy maintenance. 4. Documentation - Updated `README.md` to reflect the new skill counts (845+) and added Microsoft/Gemini to the provider list. - Updated `CATALOG.md` and `skills_index.json` with the new skills. 🧪 Verification - Ran `scripts/tests/test_comprehensive_coverage.py` to verify all Microsoft skills are detected. - Validated `generate_index.py` fixes by successfully indexing the new skills.
This commit is contained in:
366
skills/official/microsoft/java/entra/azure-identity/SKILL.md
Normal file
366
skills/official/microsoft/java/entra/azure-identity/SKILL.md
Normal file
@@ -0,0 +1,366 @@
|
||||
---
|
||||
name: azure-identity-java
|
||||
description: Azure Identity Java SDK for authentication with Azure services. Use when implementing DefaultAzureCredential, managed identity, service principal, or any Azure authentication pattern in Java applications.
|
||||
package: com.azure:azure-identity
|
||||
---
|
||||
|
||||
# Azure Identity (Java)
|
||||
|
||||
Authenticate Java applications with Azure services using Microsoft Entra ID (Azure AD).
|
||||
|
||||
## Installation
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.azure</groupId>
|
||||
<artifactId>azure-identity</artifactId>
|
||||
<version>1.15.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## Key Concepts
|
||||
|
||||
| Credential | Use Case |
|
||||
|------------|----------|
|
||||
| `DefaultAzureCredential` | **Recommended** - Works in dev and production |
|
||||
| `ManagedIdentityCredential` | Azure-hosted apps (App Service, Functions, VMs) |
|
||||
| `EnvironmentCredential` | CI/CD pipelines with env vars |
|
||||
| `ClientSecretCredential` | Service principals with secret |
|
||||
| `ClientCertificateCredential` | Service principals with certificate |
|
||||
| `AzureCliCredential` | Local dev using `az login` |
|
||||
| `InteractiveBrowserCredential` | Interactive login flow |
|
||||
| `DeviceCodeCredential` | Headless device authentication |
|
||||
|
||||
## DefaultAzureCredential (Recommended)
|
||||
|
||||
The `DefaultAzureCredential` tries multiple authentication methods in order:
|
||||
|
||||
1. Environment variables
|
||||
2. Workload Identity
|
||||
3. Managed Identity
|
||||
4. Azure CLI
|
||||
5. Azure PowerShell
|
||||
6. Azure Developer CLI
|
||||
|
||||
```java
|
||||
import com.azure.identity.DefaultAzureCredential;
|
||||
import com.azure.identity.DefaultAzureCredentialBuilder;
|
||||
|
||||
// Simple usage
|
||||
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
|
||||
|
||||
// Use with any Azure client
|
||||
BlobServiceClient blobClient = new BlobServiceClientBuilder()
|
||||
.endpoint("https://<storage-account>.blob.core.windows.net")
|
||||
.credential(credential)
|
||||
.buildClient();
|
||||
|
||||
KeyClient keyClient = new KeyClientBuilder()
|
||||
.vaultUrl("https://<vault-name>.vault.azure.net")
|
||||
.credential(credential)
|
||||
.buildClient();
|
||||
```
|
||||
|
||||
### Configure DefaultAzureCredential
|
||||
|
||||
```java
|
||||
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder()
|
||||
.managedIdentityClientId("<user-assigned-identity-client-id>") // For user-assigned MI
|
||||
.tenantId("<tenant-id>") // Limit to specific tenant
|
||||
.excludeEnvironmentCredential() // Skip env vars
|
||||
.excludeAzureCliCredential() // Skip Azure CLI
|
||||
.build();
|
||||
```
|
||||
|
||||
## Managed Identity
|
||||
|
||||
For Azure-hosted applications (App Service, Functions, AKS, VMs).
|
||||
|
||||
```java
|
||||
import com.azure.identity.ManagedIdentityCredential;
|
||||
import com.azure.identity.ManagedIdentityCredentialBuilder;
|
||||
|
||||
// System-assigned managed identity
|
||||
ManagedIdentityCredential credential = new ManagedIdentityCredentialBuilder()
|
||||
.build();
|
||||
|
||||
// User-assigned managed identity (by client ID)
|
||||
ManagedIdentityCredential credential = new ManagedIdentityCredentialBuilder()
|
||||
.clientId("<user-assigned-client-id>")
|
||||
.build();
|
||||
|
||||
// User-assigned managed identity (by resource ID)
|
||||
ManagedIdentityCredential credential = new ManagedIdentityCredentialBuilder()
|
||||
.resourceId("/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<name>")
|
||||
.build();
|
||||
```
|
||||
|
||||
## Service Principal with Secret
|
||||
|
||||
```java
|
||||
import com.azure.identity.ClientSecretCredential;
|
||||
import com.azure.identity.ClientSecretCredentialBuilder;
|
||||
|
||||
ClientSecretCredential credential = new ClientSecretCredentialBuilder()
|
||||
.tenantId("<tenant-id>")
|
||||
.clientId("<client-id>")
|
||||
.clientSecret("<client-secret>")
|
||||
.build();
|
||||
```
|
||||
|
||||
## Service Principal with Certificate
|
||||
|
||||
```java
|
||||
import com.azure.identity.ClientCertificateCredential;
|
||||
import com.azure.identity.ClientCertificateCredentialBuilder;
|
||||
|
||||
// From PEM file
|
||||
ClientCertificateCredential credential = new ClientCertificateCredentialBuilder()
|
||||
.tenantId("<tenant-id>")
|
||||
.clientId("<client-id>")
|
||||
.pemCertificate("<path-to-cert.pem>")
|
||||
.build();
|
||||
|
||||
// From PFX file with password
|
||||
ClientCertificateCredential credential = new ClientCertificateCredentialBuilder()
|
||||
.tenantId("<tenant-id>")
|
||||
.clientId("<client-id>")
|
||||
.pfxCertificate("<path-to-cert.pfx>", "<pfx-password>")
|
||||
.build();
|
||||
|
||||
// Send certificate chain for SNI
|
||||
ClientCertificateCredential credential = new ClientCertificateCredentialBuilder()
|
||||
.tenantId("<tenant-id>")
|
||||
.clientId("<client-id>")
|
||||
.pemCertificate("<path-to-cert.pem>")
|
||||
.sendCertificateChain(true)
|
||||
.build();
|
||||
```
|
||||
|
||||
## Environment Credential
|
||||
|
||||
Reads credentials from environment variables.
|
||||
|
||||
```java
|
||||
import com.azure.identity.EnvironmentCredential;
|
||||
import com.azure.identity.EnvironmentCredentialBuilder;
|
||||
|
||||
EnvironmentCredential credential = new EnvironmentCredentialBuilder().build();
|
||||
```
|
||||
|
||||
### Required Environment Variables
|
||||
|
||||
**For service principal with secret:**
|
||||
```bash
|
||||
AZURE_TENANT_ID=<tenant-id>
|
||||
AZURE_CLIENT_ID=<client-id>
|
||||
AZURE_CLIENT_SECRET=<client-secret>
|
||||
```
|
||||
|
||||
**For service principal with certificate:**
|
||||
```bash
|
||||
AZURE_TENANT_ID=<tenant-id>
|
||||
AZURE_CLIENT_ID=<client-id>
|
||||
AZURE_CLIENT_CERTIFICATE_PATH=/path/to/cert.pem
|
||||
AZURE_CLIENT_CERTIFICATE_PASSWORD=<optional-password>
|
||||
```
|
||||
|
||||
**For username/password:**
|
||||
```bash
|
||||
AZURE_TENANT_ID=<tenant-id>
|
||||
AZURE_CLIENT_ID=<client-id>
|
||||
AZURE_USERNAME=<username>
|
||||
AZURE_PASSWORD=<password>
|
||||
```
|
||||
|
||||
## Azure CLI Credential
|
||||
|
||||
For local development using `az login`.
|
||||
|
||||
```java
|
||||
import com.azure.identity.AzureCliCredential;
|
||||
import com.azure.identity.AzureCliCredentialBuilder;
|
||||
|
||||
AzureCliCredential credential = new AzureCliCredentialBuilder()
|
||||
.tenantId("<tenant-id>") // Optional: specific tenant
|
||||
.build();
|
||||
```
|
||||
|
||||
## Interactive Browser
|
||||
|
||||
For desktop applications requiring user login.
|
||||
|
||||
```java
|
||||
import com.azure.identity.InteractiveBrowserCredential;
|
||||
import com.azure.identity.InteractiveBrowserCredentialBuilder;
|
||||
|
||||
InteractiveBrowserCredential credential = new InteractiveBrowserCredentialBuilder()
|
||||
.clientId("<client-id>")
|
||||
.redirectUrl("http://localhost:8080") // Must match app registration
|
||||
.build();
|
||||
```
|
||||
|
||||
## Device Code
|
||||
|
||||
For headless devices (IoT, CLI tools).
|
||||
|
||||
```java
|
||||
import com.azure.identity.DeviceCodeCredential;
|
||||
import com.azure.identity.DeviceCodeCredentialBuilder;
|
||||
|
||||
DeviceCodeCredential credential = new DeviceCodeCredentialBuilder()
|
||||
.clientId("<client-id>")
|
||||
.challengeConsumer(challenge -> {
|
||||
// Display to user
|
||||
System.out.println(challenge.getMessage());
|
||||
})
|
||||
.build();
|
||||
```
|
||||
|
||||
## Chained Credential
|
||||
|
||||
Create custom authentication chains.
|
||||
|
||||
```java
|
||||
import com.azure.identity.ChainedTokenCredential;
|
||||
import com.azure.identity.ChainedTokenCredentialBuilder;
|
||||
|
||||
ChainedTokenCredential credential = new ChainedTokenCredentialBuilder()
|
||||
.addFirst(new ManagedIdentityCredentialBuilder().build())
|
||||
.addLast(new AzureCliCredentialBuilder().build())
|
||||
.build();
|
||||
```
|
||||
|
||||
## Workload Identity (AKS)
|
||||
|
||||
For Azure Kubernetes Service with workload identity.
|
||||
|
||||
```java
|
||||
import com.azure.identity.WorkloadIdentityCredential;
|
||||
import com.azure.identity.WorkloadIdentityCredentialBuilder;
|
||||
|
||||
// Reads from AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_FEDERATED_TOKEN_FILE
|
||||
WorkloadIdentityCredential credential = new WorkloadIdentityCredentialBuilder().build();
|
||||
|
||||
// Or explicit configuration
|
||||
WorkloadIdentityCredential credential = new WorkloadIdentityCredentialBuilder()
|
||||
.tenantId("<tenant-id>")
|
||||
.clientId("<client-id>")
|
||||
.tokenFilePath("/var/run/secrets/azure/tokens/azure-identity-token")
|
||||
.build();
|
||||
```
|
||||
|
||||
## Token Caching
|
||||
|
||||
Enable persistent token caching for better performance.
|
||||
|
||||
```java
|
||||
// Enable token caching (in-memory by default)
|
||||
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder()
|
||||
.enableAccountIdentifierLogging()
|
||||
.build();
|
||||
|
||||
// With shared token cache (for multi-credential scenarios)
|
||||
SharedTokenCacheCredential credential = new SharedTokenCacheCredentialBuilder()
|
||||
.clientId("<client-id>")
|
||||
.build();
|
||||
```
|
||||
|
||||
## Sovereign Clouds
|
||||
|
||||
```java
|
||||
import com.azure.identity.AzureAuthorityHosts;
|
||||
|
||||
// Azure Government
|
||||
DefaultAzureCredential govCredential = new DefaultAzureCredentialBuilder()
|
||||
.authorityHost(AzureAuthorityHosts.AZURE_GOVERNMENT)
|
||||
.build();
|
||||
|
||||
// Azure China
|
||||
DefaultAzureCredential chinaCredential = new DefaultAzureCredentialBuilder()
|
||||
.authorityHost(AzureAuthorityHosts.AZURE_CHINA)
|
||||
.build();
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
```java
|
||||
import com.azure.identity.CredentialUnavailableException;
|
||||
import com.azure.core.exception.ClientAuthenticationException;
|
||||
|
||||
try {
|
||||
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
|
||||
AccessToken token = credential.getToken(new TokenRequestContext()
|
||||
.addScopes("https://management.azure.com/.default"));
|
||||
} catch (CredentialUnavailableException e) {
|
||||
// No credential could authenticate
|
||||
System.out.println("Authentication failed: " + e.getMessage());
|
||||
} catch (ClientAuthenticationException e) {
|
||||
// Authentication error (wrong credentials, expired, etc.)
|
||||
System.out.println("Auth error: " + e.getMessage());
|
||||
}
|
||||
```
|
||||
|
||||
## Logging
|
||||
|
||||
Enable authentication logging for debugging.
|
||||
|
||||
```java
|
||||
// Via environment variable
|
||||
// AZURE_LOG_LEVEL=verbose
|
||||
|
||||
// Or programmatically
|
||||
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder()
|
||||
.enableAccountIdentifierLogging() // Log account info
|
||||
.build();
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
```bash
|
||||
# DefaultAzureCredential configuration
|
||||
AZURE_TENANT_ID=<tenant-id>
|
||||
AZURE_CLIENT_ID=<client-id>
|
||||
AZURE_CLIENT_SECRET=<client-secret>
|
||||
|
||||
# Managed Identity
|
||||
AZURE_CLIENT_ID=<user-assigned-mi-client-id>
|
||||
|
||||
# Workload Identity (AKS)
|
||||
AZURE_FEDERATED_TOKEN_FILE=/var/run/secrets/azure/tokens/azure-identity-token
|
||||
|
||||
# Logging
|
||||
AZURE_LOG_LEVEL=verbose
|
||||
|
||||
# Authority host
|
||||
AZURE_AUTHORITY_HOST=https://login.microsoftonline.com/
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use DefaultAzureCredential** - Works seamlessly from dev to production
|
||||
2. **Managed Identity in Production** - No secrets to manage, automatic rotation
|
||||
3. **Azure CLI for Local Dev** - Run `az login` before running your app
|
||||
4. **Least Privilege** - Grant only required permissions to service principals
|
||||
5. **Token Caching** - Enabled by default, reduces auth round-trips
|
||||
6. **Environment Variables** - Use for CI/CD, not hardcoded secrets
|
||||
|
||||
## Credential Selection Matrix
|
||||
|
||||
| Environment | Recommended Credential |
|
||||
|-------------|----------------------|
|
||||
| Local Development | `DefaultAzureCredential` (uses Azure CLI) |
|
||||
| Azure App Service | `DefaultAzureCredential` (uses Managed Identity) |
|
||||
| Azure Functions | `DefaultAzureCredential` (uses Managed Identity) |
|
||||
| Azure Kubernetes Service | `WorkloadIdentityCredential` |
|
||||
| Azure VMs | `DefaultAzureCredential` (uses Managed Identity) |
|
||||
| CI/CD Pipeline | `EnvironmentCredential` |
|
||||
| Desktop App | `InteractiveBrowserCredential` |
|
||||
| CLI Tool | `DeviceCodeCredential` |
|
||||
|
||||
## Trigger Phrases
|
||||
|
||||
- "Azure authentication Java", "DefaultAzureCredential Java"
|
||||
- "managed identity Java", "service principal Java"
|
||||
- "Azure login Java", "Azure credentials Java"
|
||||
- "AZURE_CLIENT_ID", "AZURE_TENANT_ID"
|
||||
362
skills/official/microsoft/java/entra/keyvault-keys/SKILL.md
Normal file
362
skills/official/microsoft/java/entra/keyvault-keys/SKILL.md
Normal file
@@ -0,0 +1,362 @@
|
||||
---
|
||||
name: azure-security-keyvault-keys-java
|
||||
description: Azure Key Vault Keys Java SDK for cryptographic key management. Use when creating, managing, or using RSA/EC keys, performing encrypt/decrypt/sign/verify operations, or working with HSM-backed keys.
|
||||
package: com.azure:azure-security-keyvault-keys
|
||||
---
|
||||
|
||||
# Azure Key Vault Keys (Java)
|
||||
|
||||
Manage cryptographic keys and perform cryptographic operations in Azure Key Vault and Managed HSM.
|
||||
|
||||
## Installation
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.azure</groupId>
|
||||
<artifactId>azure-security-keyvault-keys</artifactId>
|
||||
<version>4.9.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## Client Creation
|
||||
|
||||
```java
|
||||
import com.azure.security.keyvault.keys.KeyClient;
|
||||
import com.azure.security.keyvault.keys.KeyClientBuilder;
|
||||
import com.azure.security.keyvault.keys.cryptography.CryptographyClient;
|
||||
import com.azure.security.keyvault.keys.cryptography.CryptographyClientBuilder;
|
||||
import com.azure.identity.DefaultAzureCredentialBuilder;
|
||||
|
||||
// Key management client
|
||||
KeyClient keyClient = new KeyClientBuilder()
|
||||
.vaultUrl("https://<vault-name>.vault.azure.net")
|
||||
.credential(new DefaultAzureCredentialBuilder().build())
|
||||
.buildClient();
|
||||
|
||||
// Async client
|
||||
KeyAsyncClient keyAsyncClient = new KeyClientBuilder()
|
||||
.vaultUrl("https://<vault-name>.vault.azure.net")
|
||||
.credential(new DefaultAzureCredentialBuilder().build())
|
||||
.buildAsyncClient();
|
||||
|
||||
// Cryptography client (for encrypt/decrypt/sign/verify)
|
||||
CryptographyClient cryptoClient = new CryptographyClientBuilder()
|
||||
.keyIdentifier("https://<vault-name>.vault.azure.net/keys/<key-name>/<key-version>")
|
||||
.credential(new DefaultAzureCredentialBuilder().build())
|
||||
.buildClient();
|
||||
```
|
||||
|
||||
## Key Types
|
||||
|
||||
| Type | Description |
|
||||
|------|-------------|
|
||||
| `RSA` | RSA key (2048, 3072, 4096 bits) |
|
||||
| `RSA_HSM` | RSA key in HSM |
|
||||
| `EC` | Elliptic Curve key |
|
||||
| `EC_HSM` | Elliptic Curve key in HSM |
|
||||
| `OCT` | Symmetric key (Managed HSM only) |
|
||||
| `OCT_HSM` | Symmetric key in HSM |
|
||||
|
||||
## Create Keys
|
||||
|
||||
### Create RSA Key
|
||||
|
||||
```java
|
||||
import com.azure.security.keyvault.keys.models.*;
|
||||
|
||||
// Simple RSA key
|
||||
KeyVaultKey rsaKey = keyClient.createRsaKey(new CreateRsaKeyOptions("my-rsa-key")
|
||||
.setKeySize(2048));
|
||||
|
||||
System.out.println("Key name: " + rsaKey.getName());
|
||||
System.out.println("Key ID: " + rsaKey.getId());
|
||||
System.out.println("Key type: " + rsaKey.getKeyType());
|
||||
|
||||
// RSA key with options
|
||||
KeyVaultKey rsaKeyWithOptions = keyClient.createRsaKey(new CreateRsaKeyOptions("my-rsa-key-2")
|
||||
.setKeySize(4096)
|
||||
.setExpiresOn(OffsetDateTime.now().plusYears(1))
|
||||
.setNotBefore(OffsetDateTime.now())
|
||||
.setEnabled(true)
|
||||
.setKeyOperations(KeyOperation.ENCRYPT, KeyOperation.DECRYPT,
|
||||
KeyOperation.WRAP_KEY, KeyOperation.UNWRAP_KEY)
|
||||
.setTags(Map.of("environment", "production")));
|
||||
|
||||
// HSM-backed RSA key
|
||||
KeyVaultKey hsmKey = keyClient.createRsaKey(new CreateRsaKeyOptions("my-hsm-key")
|
||||
.setKeySize(2048)
|
||||
.setHardwareProtected(true));
|
||||
```
|
||||
|
||||
### Create EC Key
|
||||
|
||||
```java
|
||||
// EC key with P-256 curve
|
||||
KeyVaultKey ecKey = keyClient.createEcKey(new CreateEcKeyOptions("my-ec-key")
|
||||
.setCurveName(KeyCurveName.P_256));
|
||||
|
||||
// EC key with other curves
|
||||
KeyVaultKey ecKey384 = keyClient.createEcKey(new CreateEcKeyOptions("my-ec-key-384")
|
||||
.setCurveName(KeyCurveName.P_384));
|
||||
|
||||
KeyVaultKey ecKey521 = keyClient.createEcKey(new CreateEcKeyOptions("my-ec-key-521")
|
||||
.setCurveName(KeyCurveName.P_521));
|
||||
|
||||
// HSM-backed EC key
|
||||
KeyVaultKey ecHsmKey = keyClient.createEcKey(new CreateEcKeyOptions("my-ec-hsm-key")
|
||||
.setCurveName(KeyCurveName.P_256)
|
||||
.setHardwareProtected(true));
|
||||
```
|
||||
|
||||
### Create Symmetric Key (Managed HSM only)
|
||||
|
||||
```java
|
||||
KeyVaultKey octKey = keyClient.createOctKey(new CreateOctKeyOptions("my-symmetric-key")
|
||||
.setKeySize(256)
|
||||
.setHardwareProtected(true));
|
||||
```
|
||||
|
||||
## Get Key
|
||||
|
||||
```java
|
||||
// Get latest version
|
||||
KeyVaultKey key = keyClient.getKey("my-key");
|
||||
|
||||
// Get specific version
|
||||
KeyVaultKey keyVersion = keyClient.getKey("my-key", "<version-id>");
|
||||
|
||||
// Get only key properties (no key material)
|
||||
KeyProperties keyProps = keyClient.getKey("my-key").getProperties();
|
||||
```
|
||||
|
||||
## Update Key Properties
|
||||
|
||||
```java
|
||||
KeyVaultKey key = keyClient.getKey("my-key");
|
||||
|
||||
// Update properties
|
||||
key.getProperties()
|
||||
.setEnabled(false)
|
||||
.setExpiresOn(OffsetDateTime.now().plusMonths(6))
|
||||
.setTags(Map.of("status", "archived"));
|
||||
|
||||
KeyVaultKey updatedKey = keyClient.updateKeyProperties(key.getProperties(),
|
||||
KeyOperation.ENCRYPT, KeyOperation.DECRYPT);
|
||||
```
|
||||
|
||||
## List Keys
|
||||
|
||||
```java
|
||||
import com.azure.core.util.paging.PagedIterable;
|
||||
|
||||
// List all keys
|
||||
for (KeyProperties keyProps : keyClient.listPropertiesOfKeys()) {
|
||||
System.out.println("Key: " + keyProps.getName());
|
||||
System.out.println(" Enabled: " + keyProps.isEnabled());
|
||||
System.out.println(" Created: " + keyProps.getCreatedOn());
|
||||
}
|
||||
|
||||
// List key versions
|
||||
for (KeyProperties version : keyClient.listPropertiesOfKeyVersions("my-key")) {
|
||||
System.out.println("Version: " + version.getVersion());
|
||||
System.out.println("Created: " + version.getCreatedOn());
|
||||
}
|
||||
```
|
||||
|
||||
## Delete Key
|
||||
|
||||
```java
|
||||
import com.azure.core.util.polling.SyncPoller;
|
||||
|
||||
// Begin delete (soft-delete enabled vaults)
|
||||
SyncPoller<DeletedKey, Void> deletePoller = keyClient.beginDeleteKey("my-key");
|
||||
|
||||
// Wait for deletion
|
||||
DeletedKey deletedKey = deletePoller.poll().getValue();
|
||||
System.out.println("Deleted: " + deletedKey.getDeletedOn());
|
||||
|
||||
deletePoller.waitForCompletion();
|
||||
|
||||
// Purge deleted key (permanent deletion)
|
||||
keyClient.purgeDeletedKey("my-key");
|
||||
|
||||
// Recover deleted key
|
||||
SyncPoller<KeyVaultKey, Void> recoverPoller = keyClient.beginRecoverDeletedKey("my-key");
|
||||
recoverPoller.waitForCompletion();
|
||||
```
|
||||
|
||||
## Cryptographic Operations
|
||||
|
||||
### Encrypt/Decrypt
|
||||
|
||||
```java
|
||||
import com.azure.security.keyvault.keys.cryptography.models.*;
|
||||
|
||||
CryptographyClient cryptoClient = new CryptographyClientBuilder()
|
||||
.keyIdentifier("https://<vault>.vault.azure.net/keys/<key-name>")
|
||||
.credential(new DefaultAzureCredentialBuilder().build())
|
||||
.buildClient();
|
||||
|
||||
byte[] plaintext = "Hello, World!".getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
// Encrypt
|
||||
EncryptResult encryptResult = cryptoClient.encrypt(EncryptionAlgorithm.RSA_OAEP, plaintext);
|
||||
byte[] ciphertext = encryptResult.getCipherText();
|
||||
System.out.println("Ciphertext length: " + ciphertext.length);
|
||||
|
||||
// Decrypt
|
||||
DecryptResult decryptResult = cryptoClient.decrypt(EncryptionAlgorithm.RSA_OAEP, ciphertext);
|
||||
String decrypted = new String(decryptResult.getPlainText(), StandardCharsets.UTF_8);
|
||||
System.out.println("Decrypted: " + decrypted);
|
||||
```
|
||||
|
||||
### Sign/Verify
|
||||
|
||||
```java
|
||||
import java.security.MessageDigest;
|
||||
|
||||
// Create digest of data
|
||||
byte[] data = "Data to sign".getBytes(StandardCharsets.UTF_8);
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
byte[] digest = md.digest(data);
|
||||
|
||||
// Sign
|
||||
SignResult signResult = cryptoClient.sign(SignatureAlgorithm.RS256, digest);
|
||||
byte[] signature = signResult.getSignature();
|
||||
|
||||
// Verify
|
||||
VerifyResult verifyResult = cryptoClient.verify(SignatureAlgorithm.RS256, digest, signature);
|
||||
System.out.println("Valid signature: " + verifyResult.isValid());
|
||||
```
|
||||
|
||||
### Wrap/Unwrap Key
|
||||
|
||||
```java
|
||||
// Key to wrap (e.g., AES key)
|
||||
byte[] keyToWrap = new byte[32]; // 256-bit key
|
||||
new SecureRandom().nextBytes(keyToWrap);
|
||||
|
||||
// Wrap
|
||||
WrapResult wrapResult = cryptoClient.wrapKey(KeyWrapAlgorithm.RSA_OAEP, keyToWrap);
|
||||
byte[] wrappedKey = wrapResult.getEncryptedKey();
|
||||
|
||||
// Unwrap
|
||||
UnwrapResult unwrapResult = cryptoClient.unwrapKey(KeyWrapAlgorithm.RSA_OAEP, wrappedKey);
|
||||
byte[] unwrappedKey = unwrapResult.getKey();
|
||||
```
|
||||
|
||||
## Backup and Restore
|
||||
|
||||
```java
|
||||
// Backup
|
||||
byte[] backup = keyClient.backupKey("my-key");
|
||||
|
||||
// Save backup to file
|
||||
Files.write(Paths.get("key-backup.blob"), backup);
|
||||
|
||||
// Restore
|
||||
byte[] backupData = Files.readAllBytes(Paths.get("key-backup.blob"));
|
||||
KeyVaultKey restoredKey = keyClient.restoreKeyBackup(backupData);
|
||||
```
|
||||
|
||||
## Key Rotation
|
||||
|
||||
```java
|
||||
// Rotate to new version
|
||||
KeyVaultKey rotatedKey = keyClient.rotateKey("my-key");
|
||||
System.out.println("New version: " + rotatedKey.getProperties().getVersion());
|
||||
|
||||
// Set rotation policy
|
||||
KeyRotationPolicy policy = new KeyRotationPolicy()
|
||||
.setExpiresIn("P90D") // Expire after 90 days
|
||||
.setLifetimeActions(Arrays.asList(
|
||||
new KeyRotationLifetimeAction(KeyRotationPolicyAction.ROTATE)
|
||||
.setTimeBeforeExpiry("P30D"))); // Rotate 30 days before expiry
|
||||
|
||||
keyClient.updateKeyRotationPolicy("my-key", policy);
|
||||
|
||||
// Get rotation policy
|
||||
KeyRotationPolicy currentPolicy = keyClient.getKeyRotationPolicy("my-key");
|
||||
```
|
||||
|
||||
## Import Key
|
||||
|
||||
```java
|
||||
import com.azure.security.keyvault.keys.models.ImportKeyOptions;
|
||||
import com.azure.security.keyvault.keys.models.JsonWebKey;
|
||||
|
||||
// Import existing key material
|
||||
JsonWebKey jsonWebKey = new JsonWebKey()
|
||||
.setKeyType(KeyType.RSA)
|
||||
.setN(modulus)
|
||||
.setE(exponent)
|
||||
.setD(privateExponent)
|
||||
// ... other RSA components
|
||||
;
|
||||
|
||||
ImportKeyOptions importOptions = new ImportKeyOptions("imported-key", jsonWebKey)
|
||||
.setHardwareProtected(false);
|
||||
|
||||
KeyVaultKey importedKey = keyClient.importKey(importOptions);
|
||||
```
|
||||
|
||||
## Encryption Algorithms
|
||||
|
||||
| Algorithm | Key Type | Description |
|
||||
|-----------|----------|-------------|
|
||||
| `RSA1_5` | RSA | RSAES-PKCS1-v1_5 |
|
||||
| `RSA_OAEP` | RSA | RSAES with OAEP (recommended) |
|
||||
| `RSA_OAEP_256` | RSA | RSAES with OAEP using SHA-256 |
|
||||
| `A128GCM` | OCT | AES-GCM 128-bit |
|
||||
| `A256GCM` | OCT | AES-GCM 256-bit |
|
||||
| `A128CBC` | OCT | AES-CBC 128-bit |
|
||||
| `A256CBC` | OCT | AES-CBC 256-bit |
|
||||
|
||||
## Signature Algorithms
|
||||
|
||||
| Algorithm | Key Type | Hash |
|
||||
|-----------|----------|------|
|
||||
| `RS256` | RSA | SHA-256 |
|
||||
| `RS384` | RSA | SHA-384 |
|
||||
| `RS512` | RSA | SHA-512 |
|
||||
| `PS256` | RSA | SHA-256 (PSS) |
|
||||
| `ES256` | EC P-256 | SHA-256 |
|
||||
| `ES384` | EC P-384 | SHA-384 |
|
||||
| `ES512` | EC P-521 | SHA-512 |
|
||||
|
||||
## Error Handling
|
||||
|
||||
```java
|
||||
import com.azure.core.exception.HttpResponseException;
|
||||
import com.azure.core.exception.ResourceNotFoundException;
|
||||
|
||||
try {
|
||||
KeyVaultKey key = keyClient.getKey("non-existent-key");
|
||||
} catch (ResourceNotFoundException e) {
|
||||
System.out.println("Key not found: " + e.getMessage());
|
||||
} catch (HttpResponseException e) {
|
||||
System.out.println("HTTP error " + e.getResponse().getStatusCode());
|
||||
System.out.println("Message: " + e.getMessage());
|
||||
}
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
```bash
|
||||
AZURE_KEYVAULT_URL=https://<vault-name>.vault.azure.net
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use HSM Keys for Production** - Set `setHardwareProtected(true)` for sensitive keys
|
||||
2. **Enable Soft Delete** - Protects against accidental deletion
|
||||
3. **Key Rotation** - Set up automatic rotation policies
|
||||
4. **Least Privilege** - Use separate keys for different operations
|
||||
5. **Local Crypto When Possible** - Use `CryptographyClient` with local key material to reduce round-trips
|
||||
|
||||
## Trigger Phrases
|
||||
|
||||
- "Key Vault keys Java", "cryptographic keys Java"
|
||||
- "encrypt decrypt Java", "sign verify Java"
|
||||
- "RSA key", "EC key", "HSM key"
|
||||
- "key rotation", "wrap unwrap key"
|
||||
356
skills/official/microsoft/java/entra/keyvault-secrets/SKILL.md
Normal file
356
skills/official/microsoft/java/entra/keyvault-secrets/SKILL.md
Normal file
@@ -0,0 +1,356 @@
|
||||
---
|
||||
name: azure-security-keyvault-secrets-java
|
||||
description: Azure Key Vault Secrets Java SDK for secret management. Use when storing, retrieving, or managing passwords, API keys, connection strings, or other sensitive configuration data.
|
||||
package: com.azure:azure-security-keyvault-secrets
|
||||
---
|
||||
|
||||
# Azure Key Vault Secrets (Java)
|
||||
|
||||
Securely store and manage secrets like passwords, API keys, and connection strings.
|
||||
|
||||
## Installation
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.azure</groupId>
|
||||
<artifactId>azure-security-keyvault-secrets</artifactId>
|
||||
<version>4.9.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## Client Creation
|
||||
|
||||
```java
|
||||
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();
|
||||
```
|
||||
|
||||
## Create/Set Secret
|
||||
|
||||
```java
|
||||
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 Secret
|
||||
|
||||
```java
|
||||
// Get latest version
|
||||
KeyVaultSecret secret = secretClient.getSecret("database-password");
|
||||
String value = secret.getValue();
|
||||
System.out.println("Secret value: " + value);
|
||||
|
||||
// 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());
|
||||
```
|
||||
|
||||
## Update Secret Properties
|
||||
|
||||
```java
|
||||
// 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());
|
||||
```
|
||||
|
||||
## List Secrets
|
||||
|
||||
```java
|
||||
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());
|
||||
System.out.println(" Value: " + fullSecret.getValue().substring(0, 5) + "...");
|
||||
}
|
||||
}
|
||||
|
||||
// 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());
|
||||
}
|
||||
```
|
||||
|
||||
## Delete Secret
|
||||
|
||||
```java
|
||||
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();
|
||||
```
|
||||
|
||||
## Recover Deleted Secret
|
||||
|
||||
```java
|
||||
// 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 = recoverPoller.getFinalResult();
|
||||
System.out.println("Recovered: " + recovered.getName());
|
||||
```
|
||||
|
||||
## Purge Deleted Secret
|
||||
|
||||
```java
|
||||
// Permanently delete (cannot be recovered)
|
||||
secretClient.purgeDeletedSecret("old-secret");
|
||||
|
||||
// Get deleted secret info first
|
||||
DeletedSecret deleted = secretClient.getDeletedSecret("old-secret");
|
||||
System.out.println("Will purge: " + deleted.getName());
|
||||
secretClient.purgeDeletedSecret("old-secret");
|
||||
```
|
||||
|
||||
## Backup and Restore
|
||||
|
||||
```java
|
||||
// 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());
|
||||
```
|
||||
|
||||
## Async Operations
|
||||
|
||||
```java
|
||||
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 -> System.out.println("Value: " + secret.getValue()));
|
||||
|
||||
// List secrets async
|
||||
asyncClient.listPropertiesOfSecrets()
|
||||
.doOnNext(props -> System.out.println("Found: " + props.getName()))
|
||||
.subscribe();
|
||||
```
|
||||
|
||||
## Configuration Patterns
|
||||
|
||||
### Load Multiple Secrets
|
||||
|
||||
```java
|
||||
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")
|
||||
);
|
||||
```
|
||||
|
||||
### Secret Rotation Pattern
|
||||
|
||||
```java
|
||||
public void rotateSecret(String secretName, String newValue) {
|
||||
// Get current secret
|
||||
KeyVaultSecret current = secretClient.getSecret(secretName);
|
||||
|
||||
// Disable old version
|
||||
current.getProperties().setEnabled(false);
|
||||
secretClient.updateSecretProperties(current.getProperties());
|
||||
|
||||
// Create new version with new value
|
||||
KeyVaultSecret newSecret = secretClient.setSecret(secretName, newValue);
|
||||
System.out.println("Rotated to version: " + newSecret.getProperties().getVersion());
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
```java
|
||||
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);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Secret Properties
|
||||
|
||||
| Property | Description |
|
||||
|----------|-------------|
|
||||
| `name` | Secret name |
|
||||
| `value` | Secret value (string) |
|
||||
| `id` | Full identifier URL |
|
||||
| `contentType` | MIME type hint |
|
||||
| `enabled` | Whether secret can be retrieved |
|
||||
| `notBefore` | Activation time |
|
||||
| `expiresOn` | Expiration time |
|
||||
| `createdOn` | Creation timestamp |
|
||||
| `updatedOn` | Last update timestamp |
|
||||
| `recoveryLevel` | Soft-delete recovery level |
|
||||
| `tags` | User-defined metadata |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
```bash
|
||||
AZURE_KEYVAULT_URL=https://<vault-name>.vault.azure.net
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Enable Soft Delete** - Protects against accidental deletion
|
||||
2. **Use Tags** - Tag secrets with environment, service, owner
|
||||
3. **Set Expiration** - Use `setExpiresOn()` for credentials that should rotate
|
||||
4. **Content Type** - Set `contentType` to indicate format (e.g., `application/json`)
|
||||
5. **Version Management** - Don't delete old versions immediately during rotation
|
||||
6. **Access Logging** - Enable diagnostic logging on Key Vault
|
||||
7. **Least Privilege** - Use separate vaults for different environments
|
||||
|
||||
## Common Secret Types
|
||||
|
||||
```java
|
||||
// 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"))));
|
||||
```
|
||||
|
||||
## Trigger Phrases
|
||||
|
||||
- "Key Vault secrets Java", "secret management Java"
|
||||
- "store password", "store API key", "connection string"
|
||||
- "retrieve secret", "rotate secret"
|
||||
- "Azure secrets", "vault secrets"
|
||||
Reference in New Issue
Block a user