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:
@@ -0,0 +1,440 @@
|
||||
---
|
||||
name: microsoft-azure-webjobs-extensions-authentication-events-dotnet
|
||||
description: |
|
||||
Microsoft Entra Authentication Events SDK for .NET. Azure Functions triggers for custom authentication extensions. Use for token enrichment, custom claims, attribute collection, and OTP customization in Entra ID. Triggers: "Authentication Events", "WebJobsAuthenticationEventsTrigger", "OnTokenIssuanceStart", "OnAttributeCollectionStart", "custom claims", "token enrichment", "Entra custom extension", "authentication extension".
|
||||
---
|
||||
|
||||
# Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents (.NET)
|
||||
|
||||
Azure Functions extension for handling Microsoft Entra ID custom authentication events.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
dotnet add package Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents
|
||||
```
|
||||
|
||||
**Current Version**: v1.1.0 (stable)
|
||||
|
||||
## Supported Events
|
||||
|
||||
| Event | Purpose |
|
||||
|-------|---------|
|
||||
| `OnTokenIssuanceStart` | Add custom claims to tokens during issuance |
|
||||
| `OnAttributeCollectionStart` | Customize attribute collection UI before display |
|
||||
| `OnAttributeCollectionSubmit` | Validate/modify attributes after user submission |
|
||||
| `OnOtpSend` | Custom OTP delivery (SMS, email, etc.) |
|
||||
|
||||
## Core Workflows
|
||||
|
||||
### 1. Token Enrichment (Add Custom Claims)
|
||||
|
||||
Add custom claims to access or ID tokens during sign-in.
|
||||
|
||||
```csharp
|
||||
using Microsoft.Azure.WebJobs;
|
||||
using Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents;
|
||||
using Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents.TokenIssuanceStart;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
public static class TokenEnrichmentFunction
|
||||
{
|
||||
[FunctionName("OnTokenIssuanceStart")]
|
||||
public static WebJobsAuthenticationEventResponse Run(
|
||||
[WebJobsAuthenticationEventsTrigger] WebJobsTokenIssuanceStartRequest request,
|
||||
ILogger log)
|
||||
{
|
||||
log.LogInformation("Token issuance event for user: {UserId}",
|
||||
request.Data?.AuthenticationContext?.User?.Id);
|
||||
|
||||
// Create response with custom claims
|
||||
var response = new WebJobsTokenIssuanceStartResponse();
|
||||
|
||||
// Add claims to the token
|
||||
response.Actions.Add(new WebJobsProvideClaimsForToken
|
||||
{
|
||||
Claims = new Dictionary<string, string>
|
||||
{
|
||||
{ "customClaim1", "customValue1" },
|
||||
{ "department", "Engineering" },
|
||||
{ "costCenter", "CC-12345" },
|
||||
{ "apiVersion", "v2" }
|
||||
}
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Token Enrichment with External Data
|
||||
|
||||
Fetch claims from external systems (databases, APIs).
|
||||
|
||||
```csharp
|
||||
using Microsoft.Azure.WebJobs;
|
||||
using Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents;
|
||||
using Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents.TokenIssuanceStart;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
|
||||
public static class TokenEnrichmentWithExternalData
|
||||
{
|
||||
private static readonly HttpClient _httpClient = new();
|
||||
|
||||
[FunctionName("OnTokenIssuanceStartExternal")]
|
||||
public static async Task<WebJobsAuthenticationEventResponse> Run(
|
||||
[WebJobsAuthenticationEventsTrigger] WebJobsTokenIssuanceStartRequest request,
|
||||
ILogger log)
|
||||
{
|
||||
string? userId = request.Data?.AuthenticationContext?.User?.Id;
|
||||
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
log.LogWarning("No user ID in request");
|
||||
return new WebJobsTokenIssuanceStartResponse();
|
||||
}
|
||||
|
||||
// Fetch user data from external API
|
||||
var userProfile = await GetUserProfileAsync(userId);
|
||||
|
||||
var response = new WebJobsTokenIssuanceStartResponse();
|
||||
response.Actions.Add(new WebJobsProvideClaimsForToken
|
||||
{
|
||||
Claims = new Dictionary<string, string>
|
||||
{
|
||||
{ "employeeId", userProfile.EmployeeId },
|
||||
{ "department", userProfile.Department },
|
||||
{ "roles", string.Join(",", userProfile.Roles) }
|
||||
}
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private static async Task<UserProfile> GetUserProfileAsync(string userId)
|
||||
{
|
||||
var response = await _httpClient.GetAsync($"https://api.example.com/users/{userId}");
|
||||
response.EnsureSuccessStatusCode();
|
||||
var json = await response.Content.ReadAsStringAsync();
|
||||
return JsonSerializer.Deserialize<UserProfile>(json)!;
|
||||
}
|
||||
}
|
||||
|
||||
public record UserProfile(string EmployeeId, string Department, string[] Roles);
|
||||
```
|
||||
|
||||
### 3. Attribute Collection - Customize UI (Start Event)
|
||||
|
||||
Customize the attribute collection page before it's displayed.
|
||||
|
||||
```csharp
|
||||
using Microsoft.Azure.WebJobs;
|
||||
using Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents;
|
||||
using Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents.Framework;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
public static class AttributeCollectionStartFunction
|
||||
{
|
||||
[FunctionName("OnAttributeCollectionStart")]
|
||||
public static WebJobsAuthenticationEventResponse Run(
|
||||
[WebJobsAuthenticationEventsTrigger] WebJobsAttributeCollectionStartRequest request,
|
||||
ILogger log)
|
||||
{
|
||||
log.LogInformation("Attribute collection start for correlation: {CorrelationId}",
|
||||
request.Data?.AuthenticationContext?.CorrelationId);
|
||||
|
||||
var response = new WebJobsAttributeCollectionStartResponse();
|
||||
|
||||
// Option 1: Continue with default behavior
|
||||
response.Actions.Add(new WebJobsContinueWithDefaultBehavior());
|
||||
|
||||
// Option 2: Prefill attributes
|
||||
// response.Actions.Add(new WebJobsSetPrefillValues
|
||||
// {
|
||||
// Attributes = new Dictionary<string, string>
|
||||
// {
|
||||
// { "city", "Seattle" },
|
||||
// { "country", "USA" }
|
||||
// }
|
||||
// });
|
||||
|
||||
// Option 3: Show blocking page (prevent sign-up)
|
||||
// response.Actions.Add(new WebJobsShowBlockPage
|
||||
// {
|
||||
// Message = "Sign-up is currently disabled."
|
||||
// });
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Attribute Collection - Validate Submission (Submit Event)
|
||||
|
||||
Validate and modify attributes after user submission.
|
||||
|
||||
```csharp
|
||||
using Microsoft.Azure.WebJobs;
|
||||
using Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents;
|
||||
using Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents.Framework;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
public static class AttributeCollectionSubmitFunction
|
||||
{
|
||||
[FunctionName("OnAttributeCollectionSubmit")]
|
||||
public static WebJobsAuthenticationEventResponse Run(
|
||||
[WebJobsAuthenticationEventsTrigger] WebJobsAttributeCollectionSubmitRequest request,
|
||||
ILogger log)
|
||||
{
|
||||
var response = new WebJobsAttributeCollectionSubmitResponse();
|
||||
|
||||
// Access submitted attributes
|
||||
var attributes = request.Data?.UserSignUpInfo?.Attributes;
|
||||
|
||||
string? email = attributes?["email"]?.ToString();
|
||||
string? displayName = attributes?["displayName"]?.ToString();
|
||||
|
||||
// Validation example: block certain email domains
|
||||
if (email?.EndsWith("@blocked.com") == true)
|
||||
{
|
||||
response.Actions.Add(new WebJobsShowBlockPage
|
||||
{
|
||||
Message = "Sign-up from this email domain is not allowed."
|
||||
});
|
||||
return response;
|
||||
}
|
||||
|
||||
// Validation example: show validation error
|
||||
if (string.IsNullOrEmpty(displayName) || displayName.Length < 3)
|
||||
{
|
||||
response.Actions.Add(new WebJobsShowValidationError
|
||||
{
|
||||
Message = "Display name must be at least 3 characters.",
|
||||
AttributeErrors = new Dictionary<string, string>
|
||||
{
|
||||
{ "displayName", "Name is too short" }
|
||||
}
|
||||
});
|
||||
return response;
|
||||
}
|
||||
|
||||
// Modify attributes before saving
|
||||
response.Actions.Add(new WebJobsModifyAttributeValues
|
||||
{
|
||||
Attributes = new Dictionary<string, string>
|
||||
{
|
||||
{ "displayName", displayName.Trim() },
|
||||
{ "city", attributes?["city"]?.ToString()?.ToUpperInvariant() ?? "" }
|
||||
}
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Custom OTP Delivery
|
||||
|
||||
Send one-time passwords via custom channels (SMS, email, push notification).
|
||||
|
||||
```csharp
|
||||
using Microsoft.Azure.WebJobs;
|
||||
using Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents;
|
||||
using Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents.Framework;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
public static class CustomOtpFunction
|
||||
{
|
||||
[FunctionName("OnOtpSend")]
|
||||
public static async Task<WebJobsAuthenticationEventResponse> Run(
|
||||
[WebJobsAuthenticationEventsTrigger] WebJobsOnOtpSendRequest request,
|
||||
ILogger log)
|
||||
{
|
||||
var response = new WebJobsOnOtpSendResponse();
|
||||
|
||||
string? phoneNumber = request.Data?.OtpContext?.Identifier;
|
||||
string? otp = request.Data?.OtpContext?.OneTimeCode;
|
||||
|
||||
if (string.IsNullOrEmpty(phoneNumber) || string.IsNullOrEmpty(otp))
|
||||
{
|
||||
log.LogError("Missing phone number or OTP");
|
||||
response.Actions.Add(new WebJobsOnOtpSendFailed
|
||||
{
|
||||
Error = "Missing required data"
|
||||
});
|
||||
return response;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Send OTP via your SMS provider
|
||||
await SendSmsAsync(phoneNumber, $"Your verification code is: {otp}");
|
||||
|
||||
response.Actions.Add(new WebJobsOnOtpSendSuccess());
|
||||
log.LogInformation("OTP sent successfully to {PhoneNumber}", phoneNumber);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.LogError(ex, "Failed to send OTP");
|
||||
response.Actions.Add(new WebJobsOnOtpSendFailed
|
||||
{
|
||||
Error = "Failed to send verification code"
|
||||
});
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private static async Task SendSmsAsync(string phoneNumber, string message)
|
||||
{
|
||||
// Implement your SMS provider integration (Twilio, Azure Communication Services, etc.)
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Function App Configuration
|
||||
|
||||
Configure the Function App for authentication events.
|
||||
|
||||
```csharp
|
||||
// Program.cs (Isolated worker model)
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
var host = new HostBuilder()
|
||||
.ConfigureFunctionsWorkerDefaults()
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
```
|
||||
|
||||
```json
|
||||
// host.json
|
||||
{
|
||||
"version": "2.0",
|
||||
"logging": {
|
||||
"applicationInsights": {
|
||||
"samplingSettings": {
|
||||
"isEnabled": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"extensions": {
|
||||
"http": {
|
||||
"routePrefix": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
// local.settings.json
|
||||
{
|
||||
"IsEncrypted": false,
|
||||
"Values": {
|
||||
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
|
||||
"FUNCTIONS_WORKER_RUNTIME": "dotnet"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Key Types Reference
|
||||
|
||||
| Type | Purpose |
|
||||
|------|---------|
|
||||
| `WebJobsAuthenticationEventsTriggerAttribute` | Function trigger attribute |
|
||||
| `WebJobsTokenIssuanceStartRequest` | Token issuance event request |
|
||||
| `WebJobsTokenIssuanceStartResponse` | Token issuance event response |
|
||||
| `WebJobsProvideClaimsForToken` | Action to add claims |
|
||||
| `WebJobsAttributeCollectionStartRequest` | Attribute collection start request |
|
||||
| `WebJobsAttributeCollectionStartResponse` | Attribute collection start response |
|
||||
| `WebJobsAttributeCollectionSubmitRequest` | Attribute submission request |
|
||||
| `WebJobsAttributeCollectionSubmitResponse` | Attribute submission response |
|
||||
| `WebJobsSetPrefillValues` | Prefill form values |
|
||||
| `WebJobsShowBlockPage` | Block user with message |
|
||||
| `WebJobsShowValidationError` | Show validation errors |
|
||||
| `WebJobsModifyAttributeValues` | Modify submitted values |
|
||||
| `WebJobsOnOtpSendRequest` | OTP send event request |
|
||||
| `WebJobsOnOtpSendResponse` | OTP send event response |
|
||||
| `WebJobsOnOtpSendSuccess` | OTP sent successfully |
|
||||
| `WebJobsOnOtpSendFailed` | OTP send failed |
|
||||
| `WebJobsContinueWithDefaultBehavior` | Continue with default flow |
|
||||
|
||||
## Entra ID Configuration
|
||||
|
||||
After deploying your Function App, configure the custom extension in Entra ID:
|
||||
|
||||
1. **Register the API** in Entra ID → App registrations
|
||||
2. **Create Custom Authentication Extension** in Entra ID → External Identities → Custom authentication extensions
|
||||
3. **Link to User Flow** in Entra ID → External Identities → User flows
|
||||
|
||||
### Required App Registration Settings
|
||||
|
||||
```
|
||||
Expose an API:
|
||||
- Application ID URI: api://<your-function-app-name>.azurewebsites.net
|
||||
- Scope: CustomAuthenticationExtension.Receive.Payload
|
||||
|
||||
API Permissions:
|
||||
- Microsoft Graph: User.Read (delegated)
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Validate all inputs** — Never trust request data; validate before processing
|
||||
2. **Handle errors gracefully** — Return appropriate error responses
|
||||
3. **Log correlation IDs** — Use `CorrelationId` for troubleshooting
|
||||
4. **Keep functions fast** — Authentication events have timeout limits
|
||||
5. **Use managed identity** — Access Azure resources securely
|
||||
6. **Cache external data** — Avoid slow lookups on every request
|
||||
7. **Test locally** — Use Azure Functions Core Tools with sample payloads
|
||||
8. **Monitor with App Insights** — Track function execution and errors
|
||||
|
||||
## Error Handling
|
||||
|
||||
```csharp
|
||||
[FunctionName("OnTokenIssuanceStart")]
|
||||
public static WebJobsAuthenticationEventResponse Run(
|
||||
[WebJobsAuthenticationEventsTrigger] WebJobsTokenIssuanceStartRequest request,
|
||||
ILogger log)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Your logic here
|
||||
var response = new WebJobsTokenIssuanceStartResponse();
|
||||
response.Actions.Add(new WebJobsProvideClaimsForToken
|
||||
{
|
||||
Claims = new Dictionary<string, string> { { "claim", "value" } }
|
||||
});
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.LogError(ex, "Error processing token issuance event");
|
||||
|
||||
// Return empty response - authentication continues without custom claims
|
||||
// Do NOT throw - this would fail the authentication
|
||||
return new WebJobsTokenIssuanceStartResponse();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Related SDKs
|
||||
|
||||
| SDK | Purpose | Install |
|
||||
|-----|---------|---------|
|
||||
| `Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents` | Auth events (this SDK) | `dotnet add package Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents` |
|
||||
| `Microsoft.Identity.Web` | Web app authentication | `dotnet add package Microsoft.Identity.Web` |
|
||||
| `Azure.Identity` | Azure authentication | `dotnet add package Azure.Identity` |
|
||||
|
||||
## Reference Links
|
||||
|
||||
| Resource | URL |
|
||||
|----------|-----|
|
||||
| NuGet Package | https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents |
|
||||
| Custom Extensions Overview | https://learn.microsoft.com/entra/identity-platform/custom-extension-overview |
|
||||
| Token Issuance Events | https://learn.microsoft.com/entra/identity-platform/custom-extension-tokenissuancestart-setup |
|
||||
| Attribute Collection Events | https://learn.microsoft.com/entra/identity-platform/custom-extension-attribute-collection |
|
||||
| GitHub Source | https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/entra/Microsoft.Azure.WebJobs.Extensions.AuthenticationEvents |
|
||||
339
skills/official/microsoft/dotnet/entra/azure-identity/SKILL.md
Normal file
339
skills/official/microsoft/dotnet/entra/azure-identity/SKILL.md
Normal file
@@ -0,0 +1,339 @@
|
||||
---
|
||||
name: azure-identity-dotnet
|
||||
description: |
|
||||
Azure Identity SDK for .NET. Authentication library for Azure SDK clients using Microsoft Entra ID. Use for DefaultAzureCredential, managed identity, service principals, and developer credentials. Triggers: "Azure Identity", "DefaultAzureCredential", "ManagedIdentityCredential", "ClientSecretCredential", "authentication .NET", "Azure auth", "credential chain".
|
||||
package: Azure.Identity
|
||||
---
|
||||
|
||||
# Azure.Identity (.NET)
|
||||
|
||||
Authentication library for Azure SDK clients using Microsoft Entra ID (formerly Azure AD).
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
dotnet add package Azure.Identity
|
||||
|
||||
# For ASP.NET Core
|
||||
dotnet add package Microsoft.Extensions.Azure
|
||||
|
||||
# For brokered authentication (Windows)
|
||||
dotnet add package Azure.Identity.Broker
|
||||
```
|
||||
|
||||
**Current Versions**: Stable v1.17.1, Preview v1.18.0-beta.2
|
||||
|
||||
## Environment Variables
|
||||
|
||||
### Service Principal with Secret
|
||||
```bash
|
||||
AZURE_CLIENT_ID=<application-client-id>
|
||||
AZURE_TENANT_ID=<directory-tenant-id>
|
||||
AZURE_CLIENT_SECRET=<client-secret-value>
|
||||
```
|
||||
|
||||
### Service Principal with Certificate
|
||||
```bash
|
||||
AZURE_CLIENT_ID=<application-client-id>
|
||||
AZURE_TENANT_ID=<directory-tenant-id>
|
||||
AZURE_CLIENT_CERTIFICATE_PATH=<path-to-pfx-or-pem>
|
||||
AZURE_CLIENT_CERTIFICATE_PASSWORD=<certificate-password> # Optional
|
||||
```
|
||||
|
||||
### Managed Identity
|
||||
```bash
|
||||
AZURE_CLIENT_ID=<user-assigned-managed-identity-client-id> # Only for user-assigned
|
||||
```
|
||||
|
||||
## DefaultAzureCredential
|
||||
|
||||
The recommended credential for most scenarios. Tries multiple authentication methods in order:
|
||||
|
||||
| Order | Credential | Enabled by Default |
|
||||
|-------|------------|-------------------|
|
||||
| 1 | EnvironmentCredential | Yes |
|
||||
| 2 | WorkloadIdentityCredential | Yes |
|
||||
| 3 | ManagedIdentityCredential | Yes |
|
||||
| 4 | VisualStudioCredential | Yes |
|
||||
| 5 | VisualStudioCodeCredential | Yes |
|
||||
| 6 | AzureCliCredential | Yes |
|
||||
| 7 | AzurePowerShellCredential | Yes |
|
||||
| 8 | AzureDeveloperCliCredential | Yes |
|
||||
| 9 | InteractiveBrowserCredential | **No** |
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```csharp
|
||||
using Azure.Identity;
|
||||
using Azure.Storage.Blobs;
|
||||
|
||||
var credential = new DefaultAzureCredential();
|
||||
var blobClient = new BlobServiceClient(
|
||||
new Uri("https://myaccount.blob.core.windows.net"),
|
||||
credential);
|
||||
```
|
||||
|
||||
### ASP.NET Core with Dependency Injection
|
||||
|
||||
```csharp
|
||||
using Azure.Identity;
|
||||
using Microsoft.Extensions.Azure;
|
||||
|
||||
builder.Services.AddAzureClients(clientBuilder =>
|
||||
{
|
||||
clientBuilder.AddBlobServiceClient(
|
||||
new Uri("https://myaccount.blob.core.windows.net"));
|
||||
clientBuilder.AddSecretClient(
|
||||
new Uri("https://myvault.vault.azure.net"));
|
||||
|
||||
// Uses DefaultAzureCredential by default
|
||||
clientBuilder.UseCredential(new DefaultAzureCredential());
|
||||
});
|
||||
```
|
||||
|
||||
### Customizing DefaultAzureCredential
|
||||
|
||||
```csharp
|
||||
var credential = new DefaultAzureCredential(
|
||||
new DefaultAzureCredentialOptions
|
||||
{
|
||||
ExcludeEnvironmentCredential = true,
|
||||
ExcludeManagedIdentityCredential = false,
|
||||
ExcludeVisualStudioCredential = false,
|
||||
ExcludeAzureCliCredential = false,
|
||||
ExcludeInteractiveBrowserCredential = false, // Enable interactive
|
||||
TenantId = "<tenant-id>",
|
||||
ManagedIdentityClientId = "<user-assigned-mi-client-id>"
|
||||
});
|
||||
```
|
||||
|
||||
## Credential Types
|
||||
|
||||
### ManagedIdentityCredential (Production)
|
||||
|
||||
```csharp
|
||||
// System-assigned managed identity
|
||||
var credential = new ManagedIdentityCredential(ManagedIdentityId.SystemAssigned);
|
||||
|
||||
// User-assigned by client ID
|
||||
var credential = new ManagedIdentityCredential(
|
||||
ManagedIdentityId.FromUserAssignedClientId("<client-id>"));
|
||||
|
||||
// User-assigned by resource ID
|
||||
var credential = new ManagedIdentityCredential(
|
||||
ManagedIdentityId.FromUserAssignedResourceId("<resource-id>"));
|
||||
```
|
||||
|
||||
### ClientSecretCredential
|
||||
|
||||
```csharp
|
||||
var credential = new ClientSecretCredential(
|
||||
tenantId: "<tenant-id>",
|
||||
clientId: "<client-id>",
|
||||
clientSecret: "<client-secret>");
|
||||
|
||||
var client = new SecretClient(
|
||||
new Uri("https://myvault.vault.azure.net"),
|
||||
credential);
|
||||
```
|
||||
|
||||
### ClientCertificateCredential
|
||||
|
||||
```csharp
|
||||
var certificate = X509CertificateLoader.LoadCertificateFromFile("MyCertificate.pfx");
|
||||
var credential = new ClientCertificateCredential(
|
||||
tenantId: "<tenant-id>",
|
||||
clientId: "<client-id>",
|
||||
certificate);
|
||||
```
|
||||
|
||||
### ChainedTokenCredential (Custom Chain)
|
||||
|
||||
```csharp
|
||||
var credential = new ChainedTokenCredential(
|
||||
new ManagedIdentityCredential(),
|
||||
new AzureCliCredential());
|
||||
|
||||
var client = new SecretClient(
|
||||
new Uri("https://myvault.vault.azure.net"),
|
||||
credential);
|
||||
```
|
||||
|
||||
### Developer Credentials
|
||||
|
||||
```csharp
|
||||
// Azure CLI
|
||||
var credential = new AzureCliCredential();
|
||||
|
||||
// Azure PowerShell
|
||||
var credential = new AzurePowerShellCredential();
|
||||
|
||||
// Azure Developer CLI (azd)
|
||||
var credential = new AzureDeveloperCliCredential();
|
||||
|
||||
// Visual Studio
|
||||
var credential = new VisualStudioCredential();
|
||||
|
||||
// Interactive Browser
|
||||
var credential = new InteractiveBrowserCredential();
|
||||
```
|
||||
|
||||
## Environment-Based Configuration
|
||||
|
||||
```csharp
|
||||
// Production vs Development
|
||||
TokenCredential credential = builder.Environment.IsProduction()
|
||||
? new ManagedIdentityCredential("<client-id>")
|
||||
: new DefaultAzureCredential();
|
||||
```
|
||||
|
||||
## Sovereign Clouds
|
||||
|
||||
```csharp
|
||||
var credential = new DefaultAzureCredential(
|
||||
new DefaultAzureCredentialOptions
|
||||
{
|
||||
AuthorityHost = AzureAuthorityHosts.AzureGovernment
|
||||
});
|
||||
|
||||
// Available authority hosts:
|
||||
// AzureAuthorityHosts.AzurePublicCloud (default)
|
||||
// AzureAuthorityHosts.AzureGovernment
|
||||
// AzureAuthorityHosts.AzureChina
|
||||
// AzureAuthorityHosts.AzureGermany
|
||||
```
|
||||
|
||||
## Credential Types Reference
|
||||
|
||||
| Category | Credential | Purpose |
|
||||
|----------|------------|---------|
|
||||
| **Chains** | `DefaultAzureCredential` | Preconfigured chain for dev-to-prod |
|
||||
| | `ChainedTokenCredential` | Custom credential chain |
|
||||
| **Azure-Hosted** | `ManagedIdentityCredential` | Azure managed identity |
|
||||
| | `WorkloadIdentityCredential` | Kubernetes workload identity |
|
||||
| | `EnvironmentCredential` | Environment variables |
|
||||
| **Service Principal** | `ClientSecretCredential` | Client ID + secret |
|
||||
| | `ClientCertificateCredential` | Client ID + certificate |
|
||||
| | `ClientAssertionCredential` | Signed client assertion |
|
||||
| **User** | `InteractiveBrowserCredential` | Browser-based auth |
|
||||
| | `DeviceCodeCredential` | Device code flow |
|
||||
| | `OnBehalfOfCredential` | Delegated identity |
|
||||
| **Developer** | `AzureCliCredential` | Azure CLI |
|
||||
| | `AzurePowerShellCredential` | Azure PowerShell |
|
||||
| | `AzureDeveloperCliCredential` | Azure Developer CLI |
|
||||
| | `VisualStudioCredential` | Visual Studio |
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Use Deterministic Credentials in Production
|
||||
|
||||
```csharp
|
||||
// Development
|
||||
var devCredential = new DefaultAzureCredential();
|
||||
|
||||
// Production - use specific credential
|
||||
var prodCredential = new ManagedIdentityCredential("<client-id>");
|
||||
```
|
||||
|
||||
### 2. Reuse Credential Instances
|
||||
|
||||
```csharp
|
||||
// Good: Single credential instance shared across clients
|
||||
var credential = new DefaultAzureCredential();
|
||||
var blobClient = new BlobServiceClient(blobUri, credential);
|
||||
var secretClient = new SecretClient(vaultUri, credential);
|
||||
```
|
||||
|
||||
### 3. Configure Retry Policies
|
||||
|
||||
```csharp
|
||||
var options = new ManagedIdentityCredentialOptions(
|
||||
ManagedIdentityId.FromUserAssignedClientId(clientId))
|
||||
{
|
||||
Retry =
|
||||
{
|
||||
MaxRetries = 3,
|
||||
Delay = TimeSpan.FromSeconds(0.5),
|
||||
}
|
||||
};
|
||||
var credential = new ManagedIdentityCredential(options);
|
||||
```
|
||||
|
||||
### 4. Enable Logging for Debugging
|
||||
|
||||
```csharp
|
||||
using Azure.Core.Diagnostics;
|
||||
|
||||
using AzureEventSourceListener listener = new((args, message) =>
|
||||
{
|
||||
if (args is { EventSource.Name: "Azure-Identity" })
|
||||
{
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
}, EventLevel.LogAlways);
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
```csharp
|
||||
using Azure.Identity;
|
||||
using Azure.Security.KeyVault.Secrets;
|
||||
|
||||
var client = new SecretClient(
|
||||
new Uri("https://myvault.vault.azure.net"),
|
||||
new DefaultAzureCredential());
|
||||
|
||||
try
|
||||
{
|
||||
KeyVaultSecret secret = await client.GetSecretAsync("secret1");
|
||||
}
|
||||
catch (AuthenticationFailedException e)
|
||||
{
|
||||
Console.WriteLine($"Authentication Failed: {e.Message}");
|
||||
}
|
||||
catch (CredentialUnavailableException e)
|
||||
{
|
||||
Console.WriteLine($"Credential Unavailable: {e.Message}");
|
||||
}
|
||||
```
|
||||
|
||||
## Key Exceptions
|
||||
|
||||
| Exception | Description |
|
||||
|-----------|-------------|
|
||||
| `AuthenticationFailedException` | Base exception for authentication errors |
|
||||
| `CredentialUnavailableException` | Credential cannot authenticate in current environment |
|
||||
| `AuthenticationRequiredException` | Interactive authentication is required |
|
||||
|
||||
## Managed Identity Support
|
||||
|
||||
Supported Azure services:
|
||||
- Azure App Service and Azure Functions
|
||||
- Azure Arc
|
||||
- Azure Cloud Shell
|
||||
- Azure Kubernetes Service (AKS)
|
||||
- Azure Service Fabric
|
||||
- Azure Virtual Machines
|
||||
- Azure Virtual Machine Scale Sets
|
||||
|
||||
## Thread Safety
|
||||
|
||||
All credential implementations are thread-safe. A single credential instance can be safely shared across multiple clients and threads.
|
||||
|
||||
## Related SDKs
|
||||
|
||||
| SDK | Purpose | Install |
|
||||
|-----|---------|---------|
|
||||
| `Azure.Identity` | Authentication (this SDK) | `dotnet add package Azure.Identity` |
|
||||
| `Microsoft.Extensions.Azure` | DI integration | `dotnet add package Microsoft.Extensions.Azure` |
|
||||
| `Azure.Identity.Broker` | Brokered auth (Windows) | `dotnet add package Azure.Identity.Broker` |
|
||||
|
||||
## Reference Links
|
||||
|
||||
| Resource | URL |
|
||||
|----------|-----|
|
||||
| NuGet Package | https://www.nuget.org/packages/Azure.Identity |
|
||||
| API Reference | https://learn.microsoft.com/dotnet/api/azure.identity |
|
||||
| Credential Chains | https://learn.microsoft.com/dotnet/azure/sdk/authentication/credential-chains |
|
||||
| Best Practices | https://learn.microsoft.com/dotnet/azure/sdk/authentication/best-practices |
|
||||
| GitHub Source | https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/identity/Azure.Identity |
|
||||
406
skills/official/microsoft/dotnet/entra/keyvault/SKILL.md
Normal file
406
skills/official/microsoft/dotnet/entra/keyvault/SKILL.md
Normal file
@@ -0,0 +1,406 @@
|
||||
---
|
||||
name: azure-security-keyvault-keys-dotnet
|
||||
description: |
|
||||
Azure Key Vault Keys SDK for .NET. Client library for managing cryptographic keys in Azure Key Vault and Managed HSM. Use for key creation, rotation, encryption, decryption, signing, and verification. Triggers: "Key Vault keys", "KeyClient", "CryptographyClient", "RSA key", "EC key", "encrypt decrypt .NET", "key rotation", "HSM".
|
||||
package: Azure.Security.KeyVault.Keys
|
||||
---
|
||||
|
||||
# Azure.Security.KeyVault.Keys (.NET)
|
||||
|
||||
Client library for managing cryptographic keys in Azure Key Vault and Managed HSM.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
dotnet add package Azure.Security.KeyVault.Keys
|
||||
dotnet add package Azure.Identity
|
||||
```
|
||||
|
||||
**Current Version**: 4.7.0 (stable)
|
||||
|
||||
## Environment Variables
|
||||
|
||||
```bash
|
||||
KEY_VAULT_NAME=<your-key-vault-name>
|
||||
# Or full URI
|
||||
AZURE_KEYVAULT_URL=https://<vault-name>.vault.azure.net
|
||||
```
|
||||
|
||||
## Client Hierarchy
|
||||
|
||||
```
|
||||
KeyClient (key management)
|
||||
├── CreateKey / CreateRsaKey / CreateEcKey
|
||||
├── GetKey / GetKeys
|
||||
├── UpdateKeyProperties
|
||||
├── DeleteKey / PurgeDeletedKey
|
||||
├── BackupKey / RestoreKey
|
||||
└── GetCryptographyClient() → CryptographyClient
|
||||
|
||||
CryptographyClient (cryptographic operations)
|
||||
├── Encrypt / Decrypt
|
||||
├── WrapKey / UnwrapKey
|
||||
├── Sign / Verify
|
||||
└── SignData / VerifyData
|
||||
|
||||
KeyResolver (key resolution)
|
||||
└── Resolve(keyId) → CryptographyClient
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
### DefaultAzureCredential (Recommended)
|
||||
|
||||
```csharp
|
||||
using Azure.Identity;
|
||||
using Azure.Security.KeyVault.Keys;
|
||||
|
||||
var keyVaultName = Environment.GetEnvironmentVariable("KEY_VAULT_NAME");
|
||||
var kvUri = $"https://{keyVaultName}.vault.azure.net";
|
||||
|
||||
var client = new KeyClient(new Uri(kvUri), new DefaultAzureCredential());
|
||||
```
|
||||
|
||||
### Service Principal
|
||||
|
||||
```csharp
|
||||
var credential = new ClientSecretCredential(
|
||||
tenantId: "<tenant-id>",
|
||||
clientId: "<client-id>",
|
||||
clientSecret: "<client-secret>");
|
||||
|
||||
var client = new KeyClient(new Uri(kvUri), credential);
|
||||
```
|
||||
|
||||
## Key Management
|
||||
|
||||
### Create Keys
|
||||
|
||||
```csharp
|
||||
// Create RSA key
|
||||
KeyVaultKey rsaKey = await client.CreateKeyAsync("my-rsa-key", KeyType.Rsa);
|
||||
Console.WriteLine($"Created key: {rsaKey.Name}, Type: {rsaKey.KeyType}");
|
||||
|
||||
// Create RSA key with options
|
||||
var rsaOptions = new CreateRsaKeyOptions("my-rsa-key-2048")
|
||||
{
|
||||
KeySize = 2048,
|
||||
HardwareProtected = false, // true for HSM-backed
|
||||
ExpiresOn = DateTimeOffset.UtcNow.AddYears(1),
|
||||
NotBefore = DateTimeOffset.UtcNow,
|
||||
Enabled = true
|
||||
};
|
||||
rsaOptions.KeyOperations.Add(KeyOperation.Encrypt);
|
||||
rsaOptions.KeyOperations.Add(KeyOperation.Decrypt);
|
||||
|
||||
KeyVaultKey rsaKey2 = await client.CreateRsaKeyAsync(rsaOptions);
|
||||
|
||||
// Create EC key
|
||||
var ecOptions = new CreateEcKeyOptions("my-ec-key")
|
||||
{
|
||||
CurveName = KeyCurveName.P256,
|
||||
HardwareProtected = true // HSM-backed
|
||||
};
|
||||
KeyVaultKey ecKey = await client.CreateEcKeyAsync(ecOptions);
|
||||
|
||||
// Create Oct (symmetric) key for wrap/unwrap
|
||||
var octOptions = new CreateOctKeyOptions("my-oct-key")
|
||||
{
|
||||
KeySize = 256,
|
||||
HardwareProtected = true
|
||||
};
|
||||
KeyVaultKey octKey = await client.CreateOctKeyAsync(octOptions);
|
||||
```
|
||||
|
||||
### Retrieve Keys
|
||||
|
||||
```csharp
|
||||
// Get specific key (latest version)
|
||||
KeyVaultKey key = await client.GetKeyAsync("my-rsa-key");
|
||||
Console.WriteLine($"Key ID: {key.Id}");
|
||||
Console.WriteLine($"Key Type: {key.KeyType}");
|
||||
Console.WriteLine($"Version: {key.Properties.Version}");
|
||||
|
||||
// Get specific version
|
||||
KeyVaultKey keyVersion = await client.GetKeyAsync("my-rsa-key", "version-id");
|
||||
|
||||
// List all keys
|
||||
await foreach (KeyProperties keyProps in client.GetPropertiesOfKeysAsync())
|
||||
{
|
||||
Console.WriteLine($"Key: {keyProps.Name}, Enabled: {keyProps.Enabled}");
|
||||
}
|
||||
|
||||
// List key versions
|
||||
await foreach (KeyProperties version in client.GetPropertiesOfKeyVersionsAsync("my-rsa-key"))
|
||||
{
|
||||
Console.WriteLine($"Version: {version.Version}, Created: {version.CreatedOn}");
|
||||
}
|
||||
```
|
||||
|
||||
### Update Key Properties
|
||||
|
||||
```csharp
|
||||
KeyVaultKey key = await client.GetKeyAsync("my-rsa-key");
|
||||
|
||||
key.Properties.ExpiresOn = DateTimeOffset.UtcNow.AddYears(2);
|
||||
key.Properties.Tags["environment"] = "production";
|
||||
|
||||
KeyVaultKey updatedKey = await client.UpdateKeyPropertiesAsync(key.Properties);
|
||||
```
|
||||
|
||||
### Delete and Purge Keys
|
||||
|
||||
```csharp
|
||||
// Start delete operation
|
||||
DeleteKeyOperation operation = await client.StartDeleteKeyAsync("my-rsa-key");
|
||||
|
||||
// Wait for deletion to complete (required before purge)
|
||||
await operation.WaitForCompletionAsync();
|
||||
Console.WriteLine($"Deleted key scheduled purge date: {operation.Value.ScheduledPurgeDate}");
|
||||
|
||||
// Purge immediately (if soft-delete is enabled)
|
||||
await client.PurgeDeletedKeyAsync("my-rsa-key");
|
||||
|
||||
// Or recover deleted key
|
||||
KeyVaultKey recoveredKey = await client.StartRecoverDeletedKeyAsync("my-rsa-key");
|
||||
```
|
||||
|
||||
### Backup and Restore
|
||||
|
||||
```csharp
|
||||
// Backup key
|
||||
byte[] backup = await client.BackupKeyAsync("my-rsa-key");
|
||||
await File.WriteAllBytesAsync("key-backup.bin", backup);
|
||||
|
||||
// Restore key
|
||||
byte[] backupData = await File.ReadAllBytesAsync("key-backup.bin");
|
||||
KeyVaultKey restoredKey = await client.RestoreKeyBackupAsync(backupData);
|
||||
```
|
||||
|
||||
## Cryptographic Operations
|
||||
|
||||
### Get CryptographyClient
|
||||
|
||||
```csharp
|
||||
// From KeyClient
|
||||
KeyVaultKey key = await client.GetKeyAsync("my-rsa-key");
|
||||
CryptographyClient cryptoClient = client.GetCryptographyClient(
|
||||
key.Name,
|
||||
key.Properties.Version);
|
||||
|
||||
// Or create directly with key ID
|
||||
CryptographyClient cryptoClient = new CryptographyClient(
|
||||
new Uri("https://myvault.vault.azure.net/keys/my-rsa-key/version"),
|
||||
new DefaultAzureCredential());
|
||||
```
|
||||
|
||||
### Encrypt and Decrypt
|
||||
|
||||
```csharp
|
||||
byte[] plaintext = Encoding.UTF8.GetBytes("Secret message to encrypt");
|
||||
|
||||
// Encrypt
|
||||
EncryptResult encryptResult = await cryptoClient.EncryptAsync(
|
||||
EncryptionAlgorithm.RsaOaep256,
|
||||
plaintext);
|
||||
Console.WriteLine($"Encrypted: {Convert.ToBase64String(encryptResult.Ciphertext)}");
|
||||
|
||||
// Decrypt
|
||||
DecryptResult decryptResult = await cryptoClient.DecryptAsync(
|
||||
EncryptionAlgorithm.RsaOaep256,
|
||||
encryptResult.Ciphertext);
|
||||
string decrypted = Encoding.UTF8.GetString(decryptResult.Plaintext);
|
||||
Console.WriteLine($"Decrypted: {decrypted}");
|
||||
```
|
||||
|
||||
### Wrap and Unwrap Keys
|
||||
|
||||
```csharp
|
||||
// Key to wrap (e.g., AES key)
|
||||
byte[] keyToWrap = new byte[32]; // 256-bit key
|
||||
RandomNumberGenerator.Fill(keyToWrap);
|
||||
|
||||
// Wrap key
|
||||
WrapResult wrapResult = await cryptoClient.WrapKeyAsync(
|
||||
KeyWrapAlgorithm.RsaOaep256,
|
||||
keyToWrap);
|
||||
|
||||
// Unwrap key
|
||||
UnwrapResult unwrapResult = await cryptoClient.UnwrapKeyAsync(
|
||||
KeyWrapAlgorithm.RsaOaep256,
|
||||
wrapResult.EncryptedKey);
|
||||
```
|
||||
|
||||
### Sign and Verify
|
||||
|
||||
```csharp
|
||||
// Data to sign
|
||||
byte[] data = Encoding.UTF8.GetBytes("Data to sign");
|
||||
|
||||
// Sign data (computes hash internally)
|
||||
SignResult signResult = await cryptoClient.SignDataAsync(
|
||||
SignatureAlgorithm.RS256,
|
||||
data);
|
||||
|
||||
// Verify signature
|
||||
VerifyResult verifyResult = await cryptoClient.VerifyDataAsync(
|
||||
SignatureAlgorithm.RS256,
|
||||
data,
|
||||
signResult.Signature);
|
||||
Console.WriteLine($"Signature valid: {verifyResult.IsValid}");
|
||||
|
||||
// Or sign pre-computed hash
|
||||
using var sha256 = SHA256.Create();
|
||||
byte[] hash = sha256.ComputeHash(data);
|
||||
|
||||
SignResult signHashResult = await cryptoClient.SignAsync(
|
||||
SignatureAlgorithm.RS256,
|
||||
hash);
|
||||
```
|
||||
|
||||
## Key Resolver
|
||||
|
||||
```csharp
|
||||
using Azure.Security.KeyVault.Keys.Cryptography;
|
||||
|
||||
var resolver = new KeyResolver(new DefaultAzureCredential());
|
||||
|
||||
// Resolve key by ID to get CryptographyClient
|
||||
CryptographyClient cryptoClient = await resolver.ResolveAsync(
|
||||
new Uri("https://myvault.vault.azure.net/keys/my-key/version"));
|
||||
|
||||
// Use for encryption
|
||||
EncryptResult result = await cryptoClient.EncryptAsync(
|
||||
EncryptionAlgorithm.RsaOaep256,
|
||||
plaintext);
|
||||
```
|
||||
|
||||
## Key Rotation
|
||||
|
||||
```csharp
|
||||
// Rotate key (creates new version)
|
||||
KeyVaultKey rotatedKey = await client.RotateKeyAsync("my-rsa-key");
|
||||
Console.WriteLine($"New version: {rotatedKey.Properties.Version}");
|
||||
|
||||
// Get rotation policy
|
||||
KeyRotationPolicy policy = await client.GetKeyRotationPolicyAsync("my-rsa-key");
|
||||
|
||||
// Update rotation policy
|
||||
policy.ExpiresIn = "P90D"; // 90 days
|
||||
policy.LifetimeActions.Add(new KeyRotationLifetimeAction
|
||||
{
|
||||
Action = KeyRotationPolicyAction.Rotate,
|
||||
TimeBeforeExpiry = "P30D" // Rotate 30 days before expiry
|
||||
});
|
||||
|
||||
await client.UpdateKeyRotationPolicyAsync("my-rsa-key", policy);
|
||||
```
|
||||
|
||||
## Key Types Reference
|
||||
|
||||
| Type | Purpose |
|
||||
|------|---------|
|
||||
| `KeyClient` | Key management operations |
|
||||
| `CryptographyClient` | Cryptographic operations |
|
||||
| `KeyResolver` | Resolve key ID to CryptographyClient |
|
||||
| `KeyVaultKey` | Key with cryptographic material |
|
||||
| `KeyProperties` | Key metadata (no crypto material) |
|
||||
| `CreateRsaKeyOptions` | RSA key creation options |
|
||||
| `CreateEcKeyOptions` | EC key creation options |
|
||||
| `CreateOctKeyOptions` | Symmetric key options |
|
||||
| `EncryptResult` | Encryption result |
|
||||
| `DecryptResult` | Decryption result |
|
||||
| `SignResult` | Signing result |
|
||||
| `VerifyResult` | Verification result |
|
||||
| `WrapResult` | Key wrap result |
|
||||
| `UnwrapResult` | Key unwrap result |
|
||||
|
||||
## Algorithms Reference
|
||||
|
||||
### Encryption Algorithms
|
||||
| Algorithm | Key Type | Description |
|
||||
|-----------|----------|-------------|
|
||||
| `RsaOaep` | RSA | RSA-OAEP |
|
||||
| `RsaOaep256` | RSA | RSA-OAEP-256 |
|
||||
| `Rsa15` | RSA | RSA 1.5 (legacy) |
|
||||
| `A128Gcm` | Oct | AES-128-GCM |
|
||||
| `A256Gcm` | Oct | AES-256-GCM |
|
||||
|
||||
### Signature Algorithms
|
||||
| Algorithm | Key Type | Description |
|
||||
|-----------|----------|-------------|
|
||||
| `RS256` | RSA | RSASSA-PKCS1-v1_5 SHA-256 |
|
||||
| `RS384` | RSA | RSASSA-PKCS1-v1_5 SHA-384 |
|
||||
| `RS512` | RSA | RSASSA-PKCS1-v1_5 SHA-512 |
|
||||
| `PS256` | RSA | RSASSA-PSS SHA-256 |
|
||||
| `ES256` | EC | ECDSA P-256 SHA-256 |
|
||||
| `ES384` | EC | ECDSA P-384 SHA-384 |
|
||||
| `ES512` | EC | ECDSA P-521 SHA-512 |
|
||||
|
||||
### Key Wrap Algorithms
|
||||
| Algorithm | Key Type | Description |
|
||||
|-----------|----------|-------------|
|
||||
| `RsaOaep` | RSA | RSA-OAEP |
|
||||
| `RsaOaep256` | RSA | RSA-OAEP-256 |
|
||||
| `A128KW` | Oct | AES-128 Key Wrap |
|
||||
| `A256KW` | Oct | AES-256 Key Wrap |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use Managed Identity** — Prefer `DefaultAzureCredential` over secrets
|
||||
2. **Enable soft-delete** — Protect against accidental deletion
|
||||
3. **Use HSM-backed keys** — Set `HardwareProtected = true` for sensitive keys
|
||||
4. **Implement key rotation** — Use automatic rotation policies
|
||||
5. **Limit key operations** — Only enable required `KeyOperations`
|
||||
6. **Set expiration dates** — Always set `ExpiresOn` for keys
|
||||
7. **Use specific versions** — Pin to versions in production
|
||||
8. **Cache CryptographyClient** — Reuse for multiple operations
|
||||
|
||||
## Error Handling
|
||||
|
||||
```csharp
|
||||
using Azure;
|
||||
|
||||
try
|
||||
{
|
||||
KeyVaultKey key = await client.GetKeyAsync("my-key");
|
||||
}
|
||||
catch (RequestFailedException ex) when (ex.Status == 404)
|
||||
{
|
||||
Console.WriteLine("Key not found");
|
||||
}
|
||||
catch (RequestFailedException ex) when (ex.Status == 403)
|
||||
{
|
||||
Console.WriteLine("Access denied - check RBAC permissions");
|
||||
}
|
||||
catch (RequestFailedException ex)
|
||||
{
|
||||
Console.WriteLine($"Key Vault error: {ex.Status} - {ex.Message}");
|
||||
}
|
||||
```
|
||||
|
||||
## Required RBAC Roles
|
||||
|
||||
| Role | Permissions |
|
||||
|------|-------------|
|
||||
| Key Vault Crypto Officer | Full key management |
|
||||
| Key Vault Crypto User | Use keys for crypto operations |
|
||||
| Key Vault Reader | Read key metadata |
|
||||
|
||||
## Related SDKs
|
||||
|
||||
| SDK | Purpose | Install |
|
||||
|-----|---------|---------|
|
||||
| `Azure.Security.KeyVault.Keys` | Keys (this SDK) | `dotnet add package Azure.Security.KeyVault.Keys` |
|
||||
| `Azure.Security.KeyVault.Secrets` | Secrets | `dotnet add package Azure.Security.KeyVault.Secrets` |
|
||||
| `Azure.Security.KeyVault.Certificates` | Certificates | `dotnet add package Azure.Security.KeyVault.Certificates` |
|
||||
| `Azure.Identity` | Authentication | `dotnet add package Azure.Identity` |
|
||||
|
||||
## Reference Links
|
||||
|
||||
| Resource | URL |
|
||||
|----------|-----|
|
||||
| NuGet Package | https://www.nuget.org/packages/Azure.Security.KeyVault.Keys |
|
||||
| API Reference | https://learn.microsoft.com/dotnet/api/azure.security.keyvault.keys |
|
||||
| Quickstart | https://learn.microsoft.com/azure/key-vault/keys/quick-create-net |
|
||||
| GitHub Source | https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/keyvault/Azure.Security.KeyVault.Keys |
|
||||
Reference in New Issue
Block a user