From 821db2e89286701c3d7c4bda95b807af37137a44 Mon Sep 17 00:00:00 2001 From: Heath Stewart Date: Tue, 15 Sep 2020 10:32:35 -0700 Subject: [PATCH] Add migration guides for KV certs and keys (#15147) * Add migration guides for KV certs and secrets Resolves #12108 * Add README links to MigrationGuide.md docs For all services that currently have them. --- .../Azure.Messaging.EventHubs/README.md | 2 +- .../MigrationGuide.md | 399 ++++++++++++++++++ .../README.md | 13 +- .../tests/samples/SampleSnippets.cs | 129 +++++- .../MigrationGuide.md | 345 +++++++++++++++ .../Azure.Security.KeyVault.Keys/README.md | 7 +- .../tests/samples/SampleSnippets.cs | 132 +++++- .../MigrationGuide.md | 12 +- .../Azure.Security.KeyVault.Secrets/README.md | 5 +- .../tests/SampleSnippets.cs | 364 +++++++++++++++- .../Azure.Messaging.ServiceBus/README.md | 2 +- 11 files changed, 1372 insertions(+), 38 deletions(-) create mode 100644 sdk/keyvault/Azure.Security.KeyVault.Certificates/MigrationGuide.md create mode 100644 sdk/keyvault/Azure.Security.KeyVault.Keys/MigrationGuide.md diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/README.md b/sdk/eventhub/Azure.Messaging.EventHubs/README.md index 93cc22f28e7c4..6274c72095cfe 100755 --- a/sdk/eventhub/Azure.Messaging.EventHubs/README.md +++ b/sdk/eventhub/Azure.Messaging.EventHubs/README.md @@ -12,7 +12,7 @@ The Azure Event Hubs client library allows for publishing and consuming of Azure - Receive events from one or more publishers, transform them to better meet the needs of your ecosystem, then publish the transformed events to a new stream for consumers to observe. -[Source code](.) | [Package (NuGet)](https://www.nuget.org/packages/Azure.Messaging.EventHubs/) | [API reference documentation](https://aka.ms/azsdk-dotnet-eventhubs-docs) | [Product documentation](https://docs.microsoft.com/azure/event-hubs/) +[Source code](.) | [Package (NuGet)](https://www.nuget.org/packages/Azure.Messaging.EventHubs/) | [API reference documentation](https://aka.ms/azsdk-dotnet-eventhubs-docs) | [Product documentation](https://docs.microsoft.com/azure/event-hubs/) | [Migration guide](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/eventhub/Azure.Messaging.EventHubs/MigrationGuide.md) ## Getting started diff --git a/sdk/keyvault/Azure.Security.KeyVault.Certificates/MigrationGuide.md b/sdk/keyvault/Azure.Security.KeyVault.Certificates/MigrationGuide.md new file mode 100644 index 0000000000000..4b6f7b74b7148 --- /dev/null +++ b/sdk/keyvault/Azure.Security.KeyVault.Certificates/MigrationGuide.md @@ -0,0 +1,399 @@ +# Migrate from Microsoft.Azure.KeyVault to Azure.Security.KeyVault.Certificates + +This guide is intended to assist in the migration to version 4 of the Key Vault client library [`Azure.Security.KeyVault.Certificates`](https://www.nuget.org/packages/Azure.Security.KeyVault.Certificates) from version 3 of [`Microsoft.Azure.KeyVault`](https://www.nuget.org/packages/Microsoft.Azure.KeyVault). It will focus on side-by-side comparisons for similar operations between the two packages. + +Familiarity with the `Microsoft.Azure.KeyVault` library is assumed. For those new to the Key Vault client library for .NET, please refer to the [`Azure.Security.KeyVault.Certificates` README](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/keyvault/Azure.Security.KeyVault.Certificates/README.md) and [`Azure.Security.KeyVault.Certificates` samples](https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/keyvault/Azure.Security.KeyVault.Certificates/samples) for the `Azure.Security.KeyVault.Certificates` library rather than this guide. + +## Table of contents + +- [Migration benefits](#migration-benefits) +- [General changes](#general-changes) + - [Package and namespaces](#package-and-namespaces) + - [Separate clients](#separate-clients) + - [Client constructors](#client-constructors) + - [Creating certificate policies](#creating-certificate-policies) + - [Creating certificates](#creating-certificates) + - [Importing certificates](#importing-certificates) + - [Listing certificates](#listing-certificates) + - [Deleting certificates](#deleting-certificates) +- [Additional samples](#additional-samples) + +## Migration benefits + +A natural question to ask when considering whether or not to adopt a new version or library is what the benefits of doing so would be. As Azure has matured and been embraced by a more diverse group of developers, we have been focused on learning the patterns and practices to best support developer productivity and to understand the gaps that the .NET client libraries have. + +There were several areas of consistent feedback expressed across the Azure client library ecosystem. One of the most important is that the client libraries for different Azure services have not had a consistent approach to organization, naming, and API structure. Additionally, many developers have felt that the learning curve was difficult, and the APIs did not offer a good, approachable, and consistent onboarding story for those learning Azure or exploring a specific Azure service. + +To try and improve the development experience across Azure services, including Key Vault, a set of uniform [design guidelines](https://azure.github.io/azure-sdk/general_introduction.html) was created for all languages to drive a consistent experience with established API patterns for all services. A set of [.NET-specific guidelines](https://azure.github.io/azure-sdk/dotnet_introduction.html) was also introduced to ensure that .NET clients have a natural and idiomatic feel that mirrors that of the .NET base class libraries. Further details are available in the guidelines for those interested. + +The new Key Vault certificates library `Azure.Security.KeyVault.Certificates` provides the ability to share in some of the cross-service improvements made to the Azure development experience, such as using the new `Azure.Identity` library to share a single authentication between clients and a unified diagnostics pipeline offering a common view of the activities across each of the client libraries. + +## General changes + +### Package and namespaces + +Package names and the namespace root for the modern Azure client libraries for .NET have changed. Each will follow the pattern `Azure.[Area].[Services]` where the legacy clients followed the pattern `Microsoft.Azure.[Service]`. This provides a quick and accessible means to help understand, at a glance, whether you are using the modern or legacy clients. + +In the case of Key Vault, the modern client libraries have packages and namespaces that begin with `Azure.Security.KeyVault` and were released beginning with version 4. The legacy client libraries have packages and namespaces that begin with `Microsoft.Azure.KeyVault` and a version of 3.x.x or below. + +### Separate clients + +In the interest of simplifying the API we've split `KeyVaultClient` into separate packages and clients: + +- `Azure.Security.KeyVault.Certificates` contains `CertificateClient` for working with certificates. +- `Azure.Security.KeyVault.Keys` contains `KeyClient` for working with keys and `CryptographyClient` for performing cryptographic operations. +- `Azure.Security.KeyVault.Secrets` contains `SecretClient` for working with secrets. + +These clients also share a single connection pool by default despite being separated, resolving an issue with the old `KeyVaultClient` that created a new connection pool with each new instance and could exhaust socket connections. + +### Client constructors + +Across all new Azure client libraries, clients consistently take an endpoint or connection string along with token credentials. This differs from `KeyVaultClient` that took an authentication delegate and could be used for multiple Key Vault endpoints. + +#### Authenticating + +Previously in `Microsoft.Azure.KeyVault`, you could create a `KeyVaultClient` along with the `AzureServiceTokenProvider` from the package `Microsoft.Azure.Services.AppAuthentication`: + +```C# Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_Create +AzureServiceTokenProvider provider = new AzureServiceTokenProvider(); +KeyVaultClient client = new KeyVaultClient( + new KeyVaultClient.AuthenticationCallback(provider.KeyVaultTokenCallback)); +``` + +Now in `Azure.Security.KeyVault.Certificates`, you create a `CertificateClient` along with the `DefaultAzureCredential` from the package `Azure.Identity`: + +```C# Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_Create +CertificateClient client = new CertificateClient( + new Uri("https://myvault.vault.azure.net"), + new DefaultAzureCredential()); +``` + +[`DefaultAzureCredential`](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/README.md#defaultazurecredential) is optimized for both production and development environments without having to change your source code. + +#### Sharing an HttpClient + +In `Microsoft.Azure.KeyVault` with `KeyVaultClient`, a new `HttpClient` was created with each instance but could be shared to prevent connection starvation: + +```C# Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_CreateWithOptions +using (HttpClient httpClient = new HttpClient()) +{ + AzureServiceTokenProvider provider = new AzureServiceTokenProvider(); + KeyVaultClient client = new KeyVaultClient( + new KeyVaultClient.AuthenticationCallback(provider.KeyVaultTokenCallback), + httpClient); +} +``` + +In `Azure.Security.KeyVault.Certificates` by default, all client libraries built on `Azure.Core` that communicate over HTTP share a single `HttpClient`. If you want to share an your own `HttpClient` instance with Azure client libraries and other clients you use or implement in your projects, you can pass it via `CertificateClientOptions`: + +```C# Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateWithOptions +using (HttpClient httpClient = new HttpClient()) +{ + CertificateClientOptions options = new CertificateClientOptions + { + Transport = new HttpClientTransport(httpClient) + }; + + CertificateClient client = new CertificateClient( + new Uri("https://myvault.vault.azure.net"), + new DefaultAzureCredential(), + options); +} +``` + +[`ClientOptions`](https://azure.github.io/azure-sdk/dotnet_introduction.html#dotnet-usage-options) classes are another common feature of Azure client libraries to configure clients, including diagnostics, retry options, and transport options including your pipeline policies. + +### Creating certificate policies + +Before creating or importing a certificate, you need to define a certificate policy that defines the subject (e.g. web site, email address), lifetime management properties, and [more](https://docs.microsoft.com/azure/key-vault/certificates/about-certificates#certificate-policy). You can define your own policy or, as is common in testing applications, use a self-signed certificate policy. + +#### Custom policy + +Previously in `Microsoft.Azure.KeyVault`, you could create a custom policy if you also knew all the various string values you needed: + +```C# Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_CreateCustomPolicy +CertificatePolicy policy = new CertificatePolicy +{ + IssuerParameters = new IssuerParameters("issuer-name"), + SecretProperties = new SecretProperties("application/x-pkcs12"), + KeyProperties = new KeyProperties + { + KeyType = "RSA", + KeySize = 2048, + ReuseKey = true + }, + X509CertificateProperties = new X509CertificateProperties("CN=customdomain.com") + { + KeyUsage = new[] + { + KeyUsageType.CRLSign, + KeyUsageType.DataEncipherment, + KeyUsageType.DigitalSignature, + KeyUsageType.KeyEncipherment, + KeyUsageType.KeyAgreement, + KeyUsageType.KeyCertSign + }, + ValidityInMonths = 12 + }, + LifetimeActions = new[] + { + new LifetimeAction( + new Trigger + { + DaysBeforeExpiry = 90 + }, + new Models.Action(ActionType.AutoRenew)) + } +}; +``` + +Now in `Azure.Security.KeyVault.Certificates`, you can create a custom policy using more enumerations and less code: + +```C# Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateCustomPolicy +CertificatePolicy policy = new CertificatePolicy("issuer-name", "CN=customdomain.com") +{ + ContentType = CertificateContentType.Pkcs12, + KeyType = CertificateKeyType.Rsa, + ReuseKey = true, + KeyUsage = + { + CertificateKeyUsage.CrlSign, + CertificateKeyUsage.DataEncipherment, + CertificateKeyUsage.DigitalSignature, + CertificateKeyUsage.KeyEncipherment, + CertificateKeyUsage.KeyAgreement, + CertificateKeyUsage.KeyCertSign + }, + ValidityInMonths = 12, + LifetimeActions = + { + new LifetimeAction(CertificatePolicyAction.AutoRenew) + { + DaysBeforeExpiry = 90, + } + } +}; +``` + +#### Self-signed policy + +Previously in `Microsoft.Azure.KeyVault`, you could create a self-signed policy much like a custom policy but with the right value for the issuer name: + +```C# Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_CreateSelfSignedPolicy +CertificatePolicy policy = new CertificatePolicy +policy = new CertificatePolicy +{ + IssuerParameters = new IssuerParameters("Self"), + X509CertificateProperties = new X509CertificateProperties("CN=DefaultPolicy") +}; +``` + +Now in `Azure.Security.KeyVault.Certificates`, you can get a copy of the default policy simply: + +```C# Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateSelfSignedPolicy +CertificatePolicy policy = CertificatePolicy.Default; +``` + +### Creating certificates + +Previously in `Microsoft.Azure.KeyVault`, you could create a certificate and poll for status using the `KeyVaultClient`, a specific key Vault endpoint, and a certificate policy you created earlier: + +```C# Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_CreateCertificate +CertificateBundle certificate = null; + +// Start certificate creation. +// Depending on the policy and your business process, this could even take days for manual signing. +CertificateOperation createOperation = await client.CreateCertificateAsync("https://myvault.vault.azure.net", "certificate-name", policy); +while (true) +{ + if ("InProgress".Equals(createOperation.Status, StringComparison.OrdinalIgnoreCase)) + { + await Task.Delay(TimeSpan.FromSeconds(20)); + + createOperation = await client.GetCertificateOperationAsync("https://myvault.vault.azure.net", "certificate-name"); + continue; + } + + if ("Completed".Equals(createOperation.Status, StringComparison.OrdinalIgnoreCase)) + { + certificate = await client.GetCertificateAsync(createOperation.Id); + break; + } + + throw new Exception(string.Format( + CultureInfo.InvariantCulture, + "Polling on pending certificate returned an unexpected result. Error code = {0}, Error message = {1}", + createOperation.Error.Code, + createOperation.Error.Message)); +} + +// If you need to restart the application you can recreate the operation and continue awaiting. +do +{ + createOperation = await client.GetCertificateOperationAsync("https://myvault.vault.azure.net", "certificate-name"); + + if ("InProgress".Equals(createOperation.Status, StringComparison.OrdinalIgnoreCase)) + { + await Task.Delay(TimeSpan.FromSeconds(20)); + continue; + } + + if ("Completed".Equals(createOperation.Status, StringComparison.OrdinalIgnoreCase)) + { + certificate = await client.GetCertificateAsync(createOperation.Id); + break; + } + + throw new Exception(string.Format( + CultureInfo.InvariantCulture, + "Polling on pending certificate returned an unexpected result. Error code = {0}, Error message = {1}", + createOperation.Error.Code, + createOperation.Error.Message)); +} while (true); +``` + +Now in `Azure.Security.KeyVault.Certificates`, you can create a certificate and await or poll status on an operation to complete: + +```C# Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateCertificate +// Start certificate creation. +// Depending on the policy and your business process, this could even take days for manual signing. +CertificateOperation createOperation = await client.StartCreateCertificateAsync("certificate-name", policy); +KeyVaultCertificateWithPolicy certificate = await createOperation.WaitForCompletionAsync(TimeSpan.FromSeconds(20), CancellationToken.None); + +// If you need to restart the application you can recreate the operation and continue awaiting. +createOperation = new CertificateOperation(client, "certificate-name"); +certificate = await createOperation.WaitForCompletionAsync(TimeSpan.FromSeconds(20), CancellationToken.None); +``` + +Synchronous methods are also available on `CertificateClient`, though we recommend you use asynchronous methods throughout your projects when possible for better performing applications. + +### Importing certificates + +Previously in `Microsoft.Azure.KeyVault`, you could import a certificate and poll for status using the `KeyVaultClient`, a specific key Vault endpoint, and a certificate policy you created earlier: + +```C# Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_ImportCertificate +byte[] cer = File.ReadAllBytes("certificate.pfx"); +string cerBase64 = Convert.ToBase64String(cer); + +CertificateBundle certificate = await client.ImportCertificateAsync( + "https://myvault.vault.azure.net", + "certificate-name", + cerBase64, + certificatePolicy: policy); +``` + +Now in `Azure.Security.KeyVault.Certificates`, you can import a certificate and await or poll status on an operation to complete: + +```C# Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_ImportCertificate +byte[] cer = File.ReadAllBytes("certificate.pfx"); +ImportCertificateOptions importCertificateOptions = new ImportCertificateOptions("certificate-name", cer) +{ + Policy = policy +}; + +KeyVaultCertificateWithPolicy certificate = await client.ImportCertificateAsync(importCertificateOptions); +``` + +Synchronous methods are also available on `CertificateClient`, though we recommend you use asynchronous methods throughout your projects when possible for better performing applications. + +### Listing certificates + +Previously in `Microsoft.Azure.KeyVault`, you could list certificates' properties using the `KeyVaultClient` and a specific Key Vault endpoint: + +```C# Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_ListCertificates +IPage page = await client.GetCertificatesAsync("https://myvault.vault.azure.net"); +foreach (CertificateItem item in page) +{ + CertificateIdentifier certificateId = item.Identifier; + CertificateBundle certificate = await client.GetCertificateAsync(certificateId.Vault, certificateId.Name); +} + +while (page.NextPageLink != null) +{ + page = await client.GetCertificatesNextAsync(page.NextPageLink); + foreach (CertificateItem item in page) + { + CertificateIdentifier certificateId = item.Identifier; + CertificateBundle certificate = await client.GetCertificateAsync(certificateId.Vault, certificateId.Name); + } +} +``` + +Now in `Azure.Security.KeyVault.Certificates`, you list certificates' properties in the Key Vault you specified when constructing the `CertificateClient`. This returns an enumerable that enumerates all certificates across any number of pages. If you want to enumerate pages, call the `AsPages` method on the returned enumerable. + +```C# Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_ListCertificates +// List all certificates asynchronously. +await foreach (CertificateProperties item in client.GetPropertiesOfCertificatesAsync()) +{ + KeyVaultCertificateWithPolicy certificate = await client.GetCertificateAsync(item.Name); +} + +// List all certificates synchronously. +foreach (CertificateProperties item in client.GetPropertiesOfCertificates()) +{ + KeyVaultCertificateWithPolicy certificate = client.GetCertificate(item.Name); +} +``` + +### Deleting certificates + +Previously in `Microsoft.Azure.KeyVault`, you could delete a certificate using the `KeyVaultClient` and a specific Key Vault endpoint: + +```C# Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_DeleteCertificate +// Delete the certificate. +DeletedCertificateBundle deletedCertificate = await client.DeleteCertificateAsync("https://myvault.vault.azure.net", "certificate-name"); + +// Purge or recover the deleted certificate if soft delete is enabled. +if (deletedCertificate.RecoveryId != null) +{ + DeletedCertificateIdentifier deletedCertificateId = deletedCertificate.RecoveryIdentifier; + + // Deleting a certificate does not happen immediately. Wait a while and check if the deleted certificate exists. + while (true) + { + try + { + await client.GetDeletedCertificateAsync(deletedCertificateId.Vault, deletedCertificateId.Name); + + // Finally deleted. + break; + } + catch (KeyVaultErrorException ex) when (ex.Response.StatusCode == HttpStatusCode.NotFound) + { + // Not yet deleted... + } + } + + // Purge the deleted certificate. + await client.PurgeDeletedCertificateAsync(deletedCertificateId.Vault, deletedCertificateId.Name); + + // You can also recover the deleted certificate using RecoverDeletedCertificateAsync. +} +``` + +Now in `Azure.Security.KeyVault.Certificates`, you delete a certificate in the Key Vault you specified when constructing the `CertificateClient` and succinctly await or poll status on an operation to complete: + +```C# Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_DeleteCertificate +// Delete the certificate. +DeleteCertificateOperation deleteOperation = await client.StartDeleteCertificateAsync("certificate-name"); + +// Purge or recover the deleted certificate if soft delete is enabled. +if (deleteOperation.Value.RecoveryId != null) +{ + // Deleting a certificate does not happen immediately. Wait for the certificate to be deleted. + DeletedCertificate deletedCertificate = await deleteOperation.WaitForCompletionAsync(); + + // Purge the deleted certificate. + await client.PurgeDeletedCertificateAsync(deletedCertificate.Name); + + // You can also recover the deleted certificate using StartRecoverDeletedCertificateAsync, + // which returns RecoverDeletedCertificateOperation you can await like DeleteCertificateOperation above. +} +``` + +Synchronous methods are also available on `CertificateClient`, though we recommend you use asynchronous methods throughout your projects when possible for better performing applications. + +## Additional samples + +- [Key Vault certificates samples for .NET](https://docs.microsoft.com/samples/azure/azure-sdk-for-net/azuresecuritykeyvaultcertificates-samples/) +- [All Key Vault samples for .NET](https://docs.microsoft.com/samples/browse/?products=azure-key-vault&languages=csharp) diff --git a/sdk/keyvault/Azure.Security.KeyVault.Certificates/README.md b/sdk/keyvault/Azure.Security.KeyVault.Certificates/README.md index 9e48b281877ad..7402c08209882 100644 --- a/sdk/keyvault/Azure.Security.KeyVault.Certificates/README.md +++ b/sdk/keyvault/Azure.Security.KeyVault.Certificates/README.md @@ -3,7 +3,7 @@ Azure Key Vault is a cloud service that provides secure storage and automated ma The Azure Key Vault certificates client library enables programmatically managing certificates, offering methods to create, update, list, and delete certificates, policies, issuers, and contacts. The library also supports managing pending certificate operations and management of deleted certificates. -[Source code][certificate_client_src] | [Package (NuGet)][certificate_client_nuget_package] | [API reference documentation][API_reference] | [Product documentation][keyvault_docs] | [Samples][certificate_client_samples] +[Source code][certificate_client_src] | [Package (NuGet)][certificate_client_nuget_package] | [API reference documentation][API_reference] | [Product documentation][keyvault_docs] | [Samples][certificate_client_samples] | [Migration guide][migration_guide] ## Getting started @@ -183,8 +183,8 @@ while (!operation.HasCompleted) operation.UpdateStatus(); } -DeletedCertificate secret = operation.Value; -client.PurgeDeletedCertificate(secret.Name); +DeletedCertificate certificate = operation.Value; +client.PurgeDeletedCertificate(certificate.Name); ``` ### Create a certificate asynchronously @@ -222,8 +222,8 @@ DeleteCertificateOperation operation = await client.StartDeleteCertificateAsync( // You only need to wait for completion if you want to purge or recover the certificate. await operation.WaitForCompletionAsync(); -DeletedCertificate secret = operation.Value; -await client.PurgeDeletedCertificateAsync(secret.Name); +DeletedCertificate certificate = operation.Value; +await client.PurgeDeletedCertificateAsync(certificate.Name); ``` ## Troubleshooting @@ -311,7 +311,7 @@ This project has adopted the [Microsoft Open Source Code of Conduct][code_of_con [azure_cli]: https://docs.microsoft.com/cli/azure [certificate_client_class]: src/CertificateClient.cs [soft_delete]: https://docs.microsoft.com/azure/key-vault/key-vault-ovw-soft-delete -[azure_identity]: https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/identity/Azure.Identity +[azure_identity]: https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/identity/Azure.Identity#defaultazurecredential [keyvault_rest]: https://docs.microsoft.com/rest/api/keyvault/ [secrets_client_library]: https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/keyvault/Azure.Security.KeyVault.Secrets [keys_client_library]: https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/keyvault/Azure.Security.KeyVault.Keys @@ -321,5 +321,6 @@ This project has adopted the [Microsoft Open Source Code of Conduct][code_of_con [DefaultAzureCredential]: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/README.md [contributing]: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/keyvault/CONTRIBUTING.md [coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/ +[migration_guide]: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/keyvault/Azure.Security.KeyVault.Certificates/MigrationGuide.md ![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-net%2Fsdk%2Fkeyvault%2FAzure.Security.KeyVault.Certificates%2FREADME.png) diff --git a/sdk/keyvault/Azure.Security.KeyVault.Certificates/tests/samples/SampleSnippets.cs b/sdk/keyvault/Azure.Security.KeyVault.Certificates/tests/samples/SampleSnippets.cs index d7db3f8704f5f..b4f7381e213fb 100644 --- a/sdk/keyvault/Azure.Security.KeyVault.Certificates/tests/samples/SampleSnippets.cs +++ b/sdk/keyvault/Azure.Security.KeyVault.Certificates/tests/samples/SampleSnippets.cs @@ -1,9 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using Azure.Core.Pipeline; using Azure.Identity; using NUnit.Framework; using System; +using System.IO; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Azure.Security.KeyVault.Tests; @@ -141,8 +144,8 @@ public async Task DeleteAndPurgeCertificateAsync() // You only need to wait for completion if you want to purge or recover the certificate. await operation.WaitForCompletionAsync(); - DeletedCertificate secret = operation.Value; - await client.PurgeDeletedCertificateAsync(secret.Name); + DeletedCertificate certificate = operation.Value; + await client.PurgeDeletedCertificateAsync(certificate.Name); #endregion } @@ -161,9 +164,127 @@ public void DeleteAndPurgeCertificate() operation.UpdateStatus(); } - DeletedCertificate secret = operation.Value; - client.PurgeDeletedCertificate(secret.Name); + DeletedCertificate certificate = operation.Value; + client.PurgeDeletedCertificate(certificate.Name); #endregion } + + [Ignore("Used only for the migration guide")] + private async Task MigrationGuide() + { + #region Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_Create + CertificateClient client = new CertificateClient( + new Uri("https://myvault.vault.azure.net"), + new DefaultAzureCredential()); + #endregion Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_Create + + #region Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateWithOptions + using (HttpClient httpClient = new HttpClient()) + { + CertificateClientOptions options = new CertificateClientOptions + { + Transport = new HttpClientTransport(httpClient) + }; + + //@@CertificateClient client = new CertificateClient( + /*@@*/ CertificateClient _ = new CertificateClient( + new Uri("https://myvault.vault.azure.net"), + new DefaultAzureCredential(), + options); + } + #endregion Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateWithOptions + + #region Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateCustomPolicy + CertificatePolicy policy = new CertificatePolicy("issuer-name", "CN=customdomain.com") + { + ContentType = CertificateContentType.Pkcs12, + KeyType = CertificateKeyType.Rsa, + ReuseKey = true, + KeyUsage = + { + CertificateKeyUsage.CrlSign, + CertificateKeyUsage.DataEncipherment, + CertificateKeyUsage.DigitalSignature, + CertificateKeyUsage.KeyEncipherment, + CertificateKeyUsage.KeyAgreement, + CertificateKeyUsage.KeyCertSign + }, + ValidityInMonths = 12, + LifetimeActions = + { + new LifetimeAction(CertificatePolicyAction.AutoRenew) + { + DaysBeforeExpiry = 90, + } + } + }; + #endregion Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateSelfSignedPolicy + + #region Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateSelfSignedPolicy + //@@CertificatePolicy policy = CertificatePolicy.Default; + /*@@*/ policy = CertificatePolicy.Default; + #endregion Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateSelfSignedPolicy + + { + #region Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateCertificate + // Start certificate creation. + // Depending on the policy and your business process, this could even take days for manual signing. + CertificateOperation createOperation = await client.StartCreateCertificateAsync("certificate-name", policy); + KeyVaultCertificateWithPolicy certificate = await createOperation.WaitForCompletionAsync(TimeSpan.FromSeconds(20), CancellationToken.None); + + // If you need to restart the application you can recreate the operation and continue awaiting. + createOperation = new CertificateOperation(client, "certificate-name"); + certificate = await createOperation.WaitForCompletionAsync(TimeSpan.FromSeconds(20), CancellationToken.None); + #endregion Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateCertificate + } + + { + #region Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_ImportCertificate + byte[] cer = File.ReadAllBytes("certificate.pfx"); + ImportCertificateOptions importCertificateOptions = new ImportCertificateOptions("certificate-name", cer) + { + Policy = policy + }; + + KeyVaultCertificateWithPolicy certificate = await client.ImportCertificateAsync(importCertificateOptions); + #endregion Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_ImportCertificate + } + + { + #region Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_ListCertificates + // List all certificates asynchronously. + await foreach (CertificateProperties item in client.GetPropertiesOfCertificatesAsync()) + { + KeyVaultCertificateWithPolicy certificate = await client.GetCertificateAsync(item.Name); + } + + // List all certificates synchronously. + foreach (CertificateProperties item in client.GetPropertiesOfCertificates()) + { + KeyVaultCertificateWithPolicy certificate = client.GetCertificate(item.Name); + } + #endregion Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_ListCertificates + } + + { + #region Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_DeleteCertificate + // Delete the certificate. + DeleteCertificateOperation deleteOperation = await client.StartDeleteCertificateAsync("certificate-name"); + + // Purge or recover the deleted certificate if soft delete is enabled. + if (deleteOperation.Value.RecoveryId != null) + { + // Deleting a certificate does not happen immediately. Wait for the certificate to be deleted. + DeletedCertificate deletedCertificate = await deleteOperation.WaitForCompletionAsync(); + + // Purge the deleted certificate. + await client.PurgeDeletedCertificateAsync(deletedCertificate.Name); + + // You can also recover the deleted certificate using StartRecoverDeletedCertificateAsync, + // which returns RecoverDeletedCertificateOperation you can await like DeleteCertificateOperation above. + } + #endregion Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_DeleteCertificate + } + } } } diff --git a/sdk/keyvault/Azure.Security.KeyVault.Keys/MigrationGuide.md b/sdk/keyvault/Azure.Security.KeyVault.Keys/MigrationGuide.md new file mode 100644 index 0000000000000..da435d37f8736 --- /dev/null +++ b/sdk/keyvault/Azure.Security.KeyVault.Keys/MigrationGuide.md @@ -0,0 +1,345 @@ +# Migrate from Microsoft.Azure.KeyVault to Azure.Security.KeyVault.Keys + +This guide is intended to assist in the migration to version 4 of the Key Vault client library [`Azure.Security.KeyVault.Keys`](https://www.nuget.org/packages/Azure.Security.KeyVault.Keys) from version 3 of [`Microsoft.Azure.KeyVault`](https://www.nuget.org/packages/Microsoft.Azure.KeyVault). It will focus on side-by-side comparisons for similar operations between the two packages. + +Familiarity with the `Microsoft.Azure.KeyVault` library is assumed. For those new to the Key Vault client library for .NET, please refer to the [`Azure.Security.KeyVault.Keys` README](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/keyvault/Azure.Security.KeyVault.Keys/README.md) and [`Azure.Security.KeyVault.Keys` samples](https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/keyvault/Azure.Security.KeyVault.Keys/samples) for the `Azure.Security.KeyVault.Keys` library rather than this guide. + +## Table of contents + +- [Migration benefits](#migration-benefits) +- [General changes](#general-changes) + - [Package and namespaces](#package-and-namespaces) + - [Separate clients](#separate-clients) + - [Client constructors](#client-constructors) + - [Creating keys](#creating-keys) + - [Listing keys](#listing-keys) + - [Deleting keys](#deleting-keys) + - [Encrypting data](#encrypting-data) + - [Wrapping keys](#wrapping-keys) +- [Additional samples](#additional-samples) + +## Migration benefits + +A natural question to ask when considering whether or not to adopt a new version or library is what the benefits of doing so would be. As Azure has matured and been embraced by a more diverse group of developers, we have been focused on learning the patterns and practices to best support developer productivity and to understand the gaps that the .NET client libraries have. + +There were several areas of consistent feedback expressed across the Azure client library ecosystem. One of the most important is that the client libraries for different Azure services have not had a consistent approach to organization, naming, and API structure. Additionally, many developers have felt that the learning curve was difficult, and the APIs did not offer a good, approachable, and consistent onboarding story for those learning Azure or exploring a specific Azure service. + +To try and improve the development experience across Azure services, including Key Vault, a set of uniform [design guidelines](https://azure.github.io/azure-sdk/general_introduction.html) was created for all languages to drive a consistent experience with established API patterns for all services. A set of [.NET-specific guidelines](https://azure.github.io/azure-sdk/dotnet_introduction.html) was also introduced to ensure that .NET clients have a natural and idiomatic feel that mirrors that of the .NET base class libraries. Further details are available in the guidelines for those interested. + +The new Key Vault keys library `Azure.Security.KeyVault.Keys` provides the ability to share in some of the cross-service improvements made to the Azure development experience, such as using the new `Azure.Identity` library to share a single authentication between clients and a unified diagnostics pipeline offering a common view of the activities across each of the client libraries. + +## General changes + +### Package and namespaces + +Package names and the namespace root for the modern Azure client libraries for .NET have changed. Each will follow the pattern `Azure.[Area].[Services]` where the legacy clients followed the pattern `Microsoft.Azure.[Service]`. This provides a quick and accessible means to help understand, at a glance, whether you are using the modern or legacy clients. + +In the case of Key Vault, the modern client libraries have packages and namespaces that begin with `Azure.Security.KeyVault` and were released beginning with version 4. The legacy client libraries have packages and namespaces that begin with `Microsoft.Azure.KeyVault` and a version of 3.x.x or below. + +### Separate clients + +In the interest of simplifying the API we've split `KeyVaultClient` into separate packages and clients: + +- `Azure.Security.KeyVault.Certificates` contains `CertificateClient` for working with certificates. +- `Azure.Security.KeyVault.Keys` contains `KeyClient` for working with keys and `CryptographyClient` for performing cryptographic operations. +- `Azure.Security.KeyVault.Secrets` contains `SecretClient` for working with secrets. + +These clients also share a single connection pool by default despite being separated, resolving an issue with the old `KeyVaultClient` that created a new connection pool with each new instance and could exhaust socket connections. + +### Client constructors + +Across all new Azure client libraries, clients consistently take an endpoint or connection string along with token credentials. This differs from `KeyVaultClient` that took an authentication delegate and could be used for multiple Key Vault endpoints. + +#### Authenticating + +Previously in `Microsoft.Azure.KeyVault`, you could create a `KeyVaultClient` along with the `AzureServiceTokenProvider` from the package `Microsoft.Azure.Services.AppAuthentication`: + +```C# Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_Create +AzureServiceTokenProvider provider = new AzureServiceTokenProvider(); +KeyVaultClient client = new KeyVaultClient( + new KeyVaultClient.AuthenticationCallback(provider.KeyVaultTokenCallback)); +``` + +Now in `Azure.Security.KeyVault.Keys`, you create a `KeyClient` along with the `DefaultAzureCredential` from the package `Azure.Identity`: + +```C# Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_Create +KeyClient client = new KeyClient( + new Uri("https://myvault.vault.azure.net"), + new DefaultAzureCredential()); + +CryptographyClient cryptoClient = new CryptographyClient( + new Uri("https://myvault.vault.azure.net"), + new DefaultAzureCredential()); +``` + +[`DefaultAzureCredential`](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/README.md#defaultazurecredential) is optimized for both production and development environments without having to change your source code. + +#### Sharing an HttpClient + +In `Microsoft.Azure.KeyVault` with `KeyVaultClient`, a new `HttpClient` was created with each instance but could be shared to prevent connection starvation: + +```C# Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_CreateWithOptions +using (HttpClient httpClient = new HttpClient()) +{ + AzureServiceTokenProvider provider = new AzureServiceTokenProvider(); + KeyVaultClient client = new KeyVaultClient( + new KeyVaultClient.AuthenticationCallback(provider.KeyVaultTokenCallback), + httpClient); +} +``` + +In `Azure.Security.KeyVault.Keys` by default, all client libraries built on `Azure.Core` that communicate over HTTP share a single `HttpClient`. If you want to share an your own `HttpClient` instance with Azure client libraries and other clients you use or implement in your projects, you can pass it via `KeyClientOptions`: + +```C# Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_CreateWithOptions +using (HttpClient httpClient = new HttpClient()) +{ + KeyClientOptions options = new KeyClientOptions + { + Transport = new HttpClientTransport(httpClient) + }; + + KeyClient client = new KeyClient( + new Uri("https://myvault.vault.azure.net"), + new DefaultAzureCredential(), + options); + + CryptographyClientOptions cryptoOptions = new CryptographyClientOptions + { + Transport = new HttpClientTransport(httpClient) + }; + + CryptographyClient cryptoClient = new CryptographyClient( + new Uri("https://myvault.vault.azure.net"), + new DefaultAzureCredential(), + cryptoOptions); +} +``` + +[`ClientOptions`](https://azure.github.io/azure-sdk/dotnet_introduction.html#dotnet-usage-options) classes are another common feature of Azure client libraries to configure clients, including diagnostics, retry options, and transport options including your pipeline policies. + +### Creating keys + +Previously in `Microsoft.Azure.KeyVault`, you could create keys using the `KeyVaultClient` and a specific Key Vault endpoint: + +```C# Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_CreateKey +// Create RSA key. +NewKeyParameters createRsaParameters = new NewKeyParameters +{ + Kty = JsonWebKeyType.Rsa, + KeySize = 4096 +}; + +KeyBundle rsaKey = await client.CreateKeyAsync("https://myvault.vault.azure.net", "rsa-key-name", createRsaParameters); + +// Create Elliptic-Curve key. +NewKeyParameters createEcParameters = new NewKeyParameters +{ + Kty = JsonWebKeyType.EllipticCurve, + CurveName = "P-256" +}; + +KeyBundle ecKey = await client.CreateKeyAsync("https://myvault.vault.azure.net", "ec-key-name", createEcParameters); +``` + +Now in `Azure.Security.KeyVault.Keys`, you can create keys in the Key Vault you specified when constructing the `KeyClient`. There are different methods for different key types to help identify which properties are relevant to the key type: + +```C# Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_CreateKeys +// Create RSA key. +CreateRsaKeyOptions createRsaOptions = new CreateRsaKeyOptions("rsa-key-name") +{ + KeySize = 4096 +}; + +KeyVaultKey rsaKey = await client.CreateRsaKeyAsync(createRsaOptions); + +// Create Elliptic-Curve key. +CreateEcKeyOptions createEcOptions = new CreateEcKeyOptions("ec-key-name") +{ + CurveName = KeyCurveName.P256 +}; + +KeyVaultKey ecKey = await client.CreateEcKeyAsync(createEcOptions); +``` + +Synchronous methods are also available on `KeyClient`, though we recommend you use asynchronous methods throughout your projects when possible for better performing applications. + +### Listing keys + +Previously in `Microsoft.Azure.KeyVault`, you could list keys' properties using the `KeyVaultClient` and a specific Key Vault endpoint: + +```C# Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_ListKeys +IPage page = await client.GetKeysAsync("https://myvault.vault.azure.net"); +foreach (KeyItem item in page) +{ + KeyIdentifier keyId = item.Identifier; + KeyBundle key = await client.GetKeyAsync(keyId.Vault, keyId.Name); +} + +while (page.NextPageLink != null) +{ + page = await client.GetKeysNextAsync(page.NextPageLink); + foreach (KeyItem item in page) + { + KeyIdentifier keyId = item.Identifier; + KeyBundle key = await client.GetKeyAsync(keyId.Vault, keyId.Name); + } +} +``` + +Now in `Azure.Security.KeyVault.Keys`, you list keys' properties in the Key Vault you specified when constructing the `KeyClient`. This returns an enumerable that enumerates all keys across any number of pages. If you want to enumerate pages, call the `AsPages` method on the returned enumerable. + +```C# Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_ListKeys +// List all keys asynchronously. +await foreach (KeyProperties item in client.GetPropertiesOfKeysAsync()) +{ + KeyVaultKey key = await client.GetKeyAsync(item.Name); +} + +// List all keys synchronously. +foreach (KeyProperties item in client.GetPropertiesOfKeys()) +{ + KeyVaultKey key = client.GetKey(item.Name); +} +``` + +### Deleting keys + +Previously in `Microsoft.Azure.KeyVault`, you could delete a key using the `KeyVaultClient` and a specific Key Vault endpoint: + +```C# Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_DeleteKey +// Delete the key. +DeletedKeyBundle deletedKey = await client.DeleteKeyAsync("https://myvault.vault.azure.net", "key-name"); + +// Purge or recover the deleted key if soft delete is enabled. +if (deletedKey.RecoveryId != null) +{ + DeletedKeyIdentifier deletedKeyId = deletedKey.RecoveryIdentifier; + + // Deleting a key does not happen immediately. Wait a while and check if the deleted key exists. + while (true) + { + try + { + await client.GetDeletedKeyAsync(deletedKeyId.Vault, deletedKeyId.Name); + + // Finally deleted. + break; + } + catch (KeyVaultErrorException ex) when (ex.Response.StatusCode == HttpStatusCode.NotFound) + { + // Not yet deleted... + } + } + + // Purge the deleted key. + await client.PurgeDeletedKeyAsync(deletedKeyId.Vault, deletedKeyId.Name); + + // You can also recover the deleted key using RecoverDeletedKeyAsync. +} +``` + +Now in `Azure.Security.KeyVault.Keys`, you delete a key in the Key Vault you specified when constructing the `KeyClient` and succinctly await or poll status on an operation to complete: + +```C# Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_DeleteKey +// Delete the key. +DeleteKeyOperation deleteOperation = await client.StartDeleteKeyAsync("key-name"); + +// Purge or recover the deleted key if soft delete is enabled. +if (deleteOperation.Value.RecoveryId != null) +{ + // Deleting a key does not happen immediately. Wait for the key to be deleted. + DeletedKey deletedKey = await deleteOperation.WaitForCompletionAsync(); + + // Purge the deleted key. + await client.PurgeDeletedKeyAsync(deletedKey.Name); + + // You can also recover the deleted key using StartRecoverDeletedKeyAsync, + // which returns RecoverDeletedKeyOperation you can await like DeleteKeyOperation above. +} +``` + +Synchronous methods are also available on `KeyClient`, though we recommend you use asynchronous methods throughout your projects when possible for better performing applications. + +### Encrypting data + +Previously in `Microsoft.Azure.KeyVault`, you could encrypt and decrypt data using the `KeyVaultClient` and a specific Key Vault endpoint. The constants you could use for the various `string` parameters are not obvious and you may have had to resort to samples or REST API documentation to find what is supported: + +```C# Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_Encrypt +// Encrypt a message. The plaintext must be small enough for the chosen algorithm. +byte[] plaintext = Encoding.UTF8.GetBytes("Small message to encrypt"); +KeyOperationResult encrypted = await client.EncryptAsync("rsa-key-name", JsonWebKeyEncryptionAlgorithm.RSAOAEP256, plaintext); + +// Decrypt the message. +KeyOperationResult decrypted = await client.DecryptAsync("rsa-key-name", JsonWebKeyEncryptionAlgorithm.RSAOAEP256, encrypted.Result); +string message = Encoding.UTF8.GetString(decrypted.Result); +``` + +Now in `Azure.Security.KeyVault.Keys`, you can encrypt and decrypt data using the Key Vault and key name you specified when constructing the `CryptographyClient`. Encrypting and other operations that require only the public key attempt to download the public key and perform the operations locally if supported by the machine for increased throughput: + +```C# Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_Encrypt +// Encrypt a message. The plaintext must be small enough for the chosen algorithm. +byte[] plaintext = Encoding.UTF8.GetBytes("Small message to encrypt"); +EncryptResult encrypted = await cryptoClient.EncryptAsync(EncryptionAlgorithm.RsaOaep256, plaintext); + +// Decrypt the message. +DecryptResult decrypted = await cryptoClient.DecryptAsync(encrypted.Algorithm, encrypted.Ciphertext); +string message = Encoding.UTF8.GetString(decrypted.Plaintext); +``` + +Synchronous methods are also available on `CryptographyClient`, though we recommend you use asynchronous methods throughout your projects when possible for better performing applications. + +### Wrapping keys + +Previously in `Microsoft.Azure.KeyVault`, you could wrap and unwrap keys using the `KeyVaultClient` and a specific Key Vault endpoint. This is useful for wrapping a symmetric key used for encrypting large amounts of data, possibly while streaming. The constants you could use for the various `string` parameters are not obvious and you may have had to resort to samples or REST API documentation to find what is supported: + +```C# Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_Wrap +using (Aes aes = Aes.Create()) +{ + // Use a symmetric key to encrypt large amounts of data, possibly streamed... + + // Now wrap the key and store the encrypted key and plaintext IV to later decrypt the key to decrypt the data. + KeyOperationResult wrapped = await client.WrapKeyAsync( + "https://myvault.vault.azure.net", + "rsa-key-name", + null, + JsonWebKeyEncryptionAlgorithm.RSAOAEP256, + aes.Key); + + // Read the IV and the encrypted key from the payload, then unwrap the key. + KeyOperationResult unwrapped = await client.UnwrapKeyAsync( + "https://myvault.vault.azure.net", + "rsa-key-name", + null, + JsonWebKeyEncryptionAlgorithm.RSAOAEP256, + wrapped.Result); + + aes.Key = unwrapped.Result; + + // Decrypt the payload with the symmetric key. +} +``` + +Now in `Azure.Security.KeyVault.Keys`, you can wrap and unwrap keys using the Key Vault and key name you specified when constructing the `CryptographyClient`. Wrapping keys and other operations that require only the public key attempt to download the public key and perform the operations locally if supported by the machine for increased throughput: + +```C# Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_Wrap +using (Aes aes = Aes.Create()) +{ + // Use a symmetric key to encrypt large amounts of data, possibly streamed... + + // Now wrap the key and store the encrypted key and plaintext IV to later decrypt the key to decrypt the data. + WrapResult wrapped = await cryptoClient.WrapKeyAsync(KeyWrapAlgorithm.RsaOaep256, aes.Key); + + // Read the IV and the encrypted key from the payload, then unwrap the key. + UnwrapResult unwrapped = await cryptoClient.UnwrapKeyAsync(wrapped.Algorithm, wrapped.EncryptedKey); + aes.Key = unwrapped.Key; + + // Decrypt the payload with the symmetric key. +} +``` + +Synchronous methods are also available on `CryptographyClient`, though we recommend you use asynchronous methods throughout your projects when possible for better performing applications. + +## Additional samples + +- [Key Vault keys samples for .NET](https://docs.microsoft.com/samples/azure/azure-sdk-for-net/azuresecuritykeyvaultkeys-samples/) +- [All Key Vault samples for .NET](https://docs.microsoft.com/samples/browse/?products=azure-key-vault&languages=csharp) diff --git a/sdk/keyvault/Azure.Security.KeyVault.Keys/README.md b/sdk/keyvault/Azure.Security.KeyVault.Keys/README.md index 97a0525bec792..02039815bcc21 100644 --- a/sdk/keyvault/Azure.Security.KeyVault.Keys/README.md +++ b/sdk/keyvault/Azure.Security.KeyVault.Keys/README.md @@ -3,7 +3,7 @@ Azure Key Vault is a cloud service that provides secure storage of keys for encr The Azure Key Vault keys library client supports RSA keys and Elliptic Curve (EC) keys, each with corresponding support in hardware security modules (HSM). It offers operations to create, retrieve, update, delete, purge, backup, restore, and list the keys and its versions. -[Source code][key_client_src] | [Package (NuGet)][key_client_nuget_package] | [API reference documentation][API_reference] | [Product documentation][keyvault_docs] | [Samples][key_client_samples] +[Source code][key_client_src] | [Package (NuGet)][key_client_nuget_package] | [API reference documentation][API_reference] | [Product documentation][keyvault_docs] | [Samples][key_client_samples] | [Migration guide][migration_guide] ## Getting started @@ -90,7 +90,7 @@ key = client.GetKey("key-name"); Once you've created a `KeyVaultKey` in the Azure Key Vault, you can also create the [CryptographyClient][crypto_client_class]: ```C# Snippet:CreateCryptographyClient -// Create a new certificate client using the default credential from Azure.Identity using environment variables previously set, +// Create a new cryptography client using the default credential from Azure.Identity using environment variables previously set, // including AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, and AZURE_TENANT_ID. var cryptoClient = new CryptographyClient(keyId: key.Id, credential: new DefaultAzureCredential()); ``` @@ -401,8 +401,9 @@ This project has adopted the [Microsoft Open Source Code of Conduct][code_of_con [nuget]: https://www.nuget.org/ [secrets_client_library]: https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/keyvault/Azure.Security.KeyVault.Secrets [soft_delete]: https://docs.microsoft.com/azure/key-vault/key-vault-ovw-soft-delete -[DefaultAzureCredential]: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/README.md +[DefaultAzureCredential]: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/README.md#defaultazurecredential [contributing]: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/keyvault/CONTRIBUTING.md [coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/ +[migration_guide]: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/keyvault/Azure.Security.KeyVault.Keys/MigrationGuide.md ![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-net%2Fsdk%2Fkeyvault%2FAzure.Security.KeyVault.Keys%2FREADME.png) diff --git a/sdk/keyvault/Azure.Security.KeyVault.Keys/tests/samples/SampleSnippets.cs b/sdk/keyvault/Azure.Security.KeyVault.Keys/tests/samples/SampleSnippets.cs index 5c020d6ed209a..300c7c74e82d8 100644 --- a/sdk/keyvault/Azure.Security.KeyVault.Keys/tests/samples/SampleSnippets.cs +++ b/sdk/keyvault/Azure.Security.KeyVault.Keys/tests/samples/SampleSnippets.cs @@ -1,15 +1,18 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using Azure.Core.Pipeline; using Azure.Identity; using Azure.Security.KeyVault.Keys.Cryptography; using NUnit.Framework; using System; +using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; using Azure.Core.TestFramework; using Azure.Security.KeyVault.Tests; +using System.Security.Cryptography; namespace Azure.Security.KeyVault.Keys.Samples { @@ -42,7 +45,7 @@ public void CreateClient() #endregion #region Snippet:CreateCryptographyClient - // Create a new certificate client using the default credential from Azure.Identity using environment variables previously set, + // Create a new cryptography client using the default credential from Azure.Identity using environment variables previously set, // including AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, and AZURE_TENANT_ID. var cryptoClient = new CryptographyClient(keyId: key.Id, credential: new DefaultAzureCredential()); #endregion @@ -259,5 +262,132 @@ public void DeleteAndPurge() client.PurgeDeletedKey(key.Name); #endregion } + + [Ignore("Used only for the migration guide")] + private async Task MigrationGuide() + { + #region Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_Create + KeyClient client = new KeyClient( + new Uri("https://myvault.vault.azure.net"), + new DefaultAzureCredential()); + + CryptographyClient cryptoClient = new CryptographyClient( + new Uri("https://myvault.vault.azure.net"), + new DefaultAzureCredential()); + #endregion Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_Create + + #region Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_CreateWithOptions + using (HttpClient httpClient = new HttpClient()) + { + KeyClientOptions options = new KeyClientOptions + { + Transport = new HttpClientTransport(httpClient) + }; + + //@@KeyClient client = new KeyClient( + /*@@*/ client = new KeyClient( + new Uri("https://myvault.vault.azure.net"), + new DefaultAzureCredential(), + options); + + CryptographyClientOptions cryptoOptions = new CryptographyClientOptions + { + Transport = new HttpClientTransport(httpClient) + }; + + //@@CryptographyClient cryptoClient = new CryptographyClient( + /*@@*/ cryptoClient = new CryptographyClient( + new Uri("https://myvault.vault.azure.net"), + new DefaultAzureCredential(), + cryptoOptions); + } + #endregion Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_CreateWithOptions + + { + #region Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_CreateKeys + // Create RSA key. + CreateRsaKeyOptions createRsaOptions = new CreateRsaKeyOptions("rsa-key-name") + { + KeySize = 4096 + }; + + KeyVaultKey rsaKey = await client.CreateRsaKeyAsync(createRsaOptions); + + // Create Elliptic-Curve key. + CreateEcKeyOptions createEcOptions = new CreateEcKeyOptions("ec-key-name") + { + CurveName = KeyCurveName.P256 + }; + + KeyVaultKey ecKey = await client.CreateEcKeyAsync(createEcOptions); + #endregion Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_CreateKeys + } + + { + #region Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_ListKeys + // List all keys asynchronously. + await foreach (KeyProperties item in client.GetPropertiesOfKeysAsync()) + { + KeyVaultKey key = await client.GetKeyAsync(item.Name); + } + + // List all keys synchronously. + foreach (KeyProperties item in client.GetPropertiesOfKeys()) + { + KeyVaultKey key = client.GetKey(item.Name); + } + #endregion Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_ListKeys + } + + { + #region Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_DeleteKey + // Delete the key. + DeleteKeyOperation deleteOperation = await client.StartDeleteKeyAsync("key-name"); + + // Purge or recover the deleted key if soft delete is enabled. + if (deleteOperation.Value.RecoveryId != null) + { + // Deleting a key does not happen immediately. Wait for the key to be deleted. + DeletedKey deletedKey = await deleteOperation.WaitForCompletionAsync(); + + // Purge the deleted key. + await client.PurgeDeletedKeyAsync(deletedKey.Name); + + // You can also recover the deleted key using StartRecoverDeletedKeyAsync, + // which returns RecoverDeletedKeyOperation you can await like DeleteKeyOperation above. + } + #endregion Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_DeleteKey + } + + { + #region Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_Encrypt + // Encrypt a message. The plaintext must be small enough for the chosen algorithm. + byte[] plaintext = Encoding.UTF8.GetBytes("Small message to encrypt"); + EncryptResult encrypted = await cryptoClient.EncryptAsync(EncryptionAlgorithm.RsaOaep256, plaintext); + + // Decrypt the message. + DecryptResult decrypted = await cryptoClient.DecryptAsync(encrypted.Algorithm, encrypted.Ciphertext); + string message = Encoding.UTF8.GetString(decrypted.Plaintext); + #endregion Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_Encrypt + } + + { + #region Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_Wrap + using (Aes aes = Aes.Create()) + { + // Use a symmetric key to encrypt large amounts of data, possibly streamed... + + // Now wrap the key and store the encrypted key and plaintext IV to later decrypt the key to decrypt the data. + WrapResult wrapped = await cryptoClient.WrapKeyAsync(KeyWrapAlgorithm.RsaOaep256, aes.Key); + + // Read the IV and the encrypted key from the payload, then unwrap the key. + UnwrapResult unwrapped = await cryptoClient.UnwrapKeyAsync(wrapped.Algorithm, wrapped.EncryptedKey); + aes.Key = unwrapped.Key; + + // Decrypt the payload with the symmetric key. + } + #endregion Snippet:Azure_Security_KeyVault_Keys_Snippets_MigrationGuide_Wrap + } + } } } diff --git a/sdk/keyvault/Azure.Security.KeyVault.Secrets/MigrationGuide.md b/sdk/keyvault/Azure.Security.KeyVault.Secrets/MigrationGuide.md index 0d2896304e6a3..8aff95291922e 100644 --- a/sdk/keyvault/Azure.Security.KeyVault.Secrets/MigrationGuide.md +++ b/sdk/keyvault/Azure.Security.KeyVault.Secrets/MigrationGuide.md @@ -54,7 +54,7 @@ Across all new Azure client libraries, clients consistently take an endpoint or Previously in `Microsoft.Azure.KeyVault`, you could create a `KeyVaultClient` along with the `AzureServiceTokenProvider` from the package `Microsoft.Azure.Services.AppAuthentication`: -```C# Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_Create +```C# Snippet:Microsoft_Azure_KeyVault_Secrets_Snippets_MigrationGuide_Create AzureServiceTokenProvider provider = new AzureServiceTokenProvider(); KeyVaultClient client = new KeyVaultClient( new KeyVaultClient.AuthenticationCallback(provider.KeyVaultTokenCallback)); @@ -74,7 +74,7 @@ SecretClient client = new SecretClient( In `Microsoft.Azure.KeyVault` with `KeyVaultClient`, a new `HttpClient` was created with each instance but could be shared to prevent connection starvation: -```C# Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_CreateWithOptions +```C# Snippet:Microsoft_Azure_KeyVault_Secrets_Snippets_MigrationGuide_CreateWithOptions using (HttpClient httpClient = new HttpClient()) { AzureServiceTokenProvider provider = new AzureServiceTokenProvider(); @@ -107,7 +107,7 @@ using (HttpClient httpClient = new HttpClient()) Previously in `Microsoft.Azure.KeyVault`, you could set a secret value using the `KeyVaultClient` and a specific Key Vault endpoint: -```C# Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_SetSecret +```C# Snippet:Microsoft_Azure_KeyVault_Secrets_Snippets_MigrationGuide_SetSecret SecretBundle secret = await client.SetSecretAsync("https://myvault.vault.azure.net", "secret-name", "secret-value"); ``` @@ -125,7 +125,7 @@ Synchronous methods are also available on `SecretClient`, though we recommend yo Previously in `Microsoft.Azure.KeyVault`, you could get a secret value using the `KeyVaultClient` and a specific Key Vault endpoint: -```C# Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_GetSecret +```C# Snippet:Microsoft_Azure_KeyVault_Secrets_Snippets_MigrationGuide_GetSecret // Get the latest secret value. SecretBundle secret = await client.GetSecretAsync("https://myvault.vault.azure.net", "secret-name", null); @@ -149,7 +149,7 @@ Synchronous methods are also available on `SecretClient`, though we recommend yo Previously in `Microsoft.Azure.KeyVault`, you could list secrets' properties using the `KeyVaultClient` and a specific Key Vault endpoint: -```C# Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_ListSecrets +```C# Snippet:Microsoft_Azure_KeyVault_Secrets_Snippets_MigrationGuide_ListSecrets IPage page = await client.GetSecretsAsync("https://myvault.vault.azure.net"); foreach (SecretItem item in page) { @@ -188,7 +188,7 @@ foreach (SecretProperties item in client.GetPropertiesOfSecrets()) Previously in `Microsoft.Azure.KeyVault`, you could delete a secret using the `KeyVaultClient` and a specific Key Vault endpoint: -```C# Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_DeleteSecret +```C# Snippet:Microsoft_Azure_KeyVault_Secrets_Snippets_MigrationGuide_DeleteSecret // Delete the secret. DeletedSecretBundle deletedSecret = await client.DeleteSecretAsync("https://myvault.vault.azure.net", "secret-name"); diff --git a/sdk/keyvault/Azure.Security.KeyVault.Secrets/README.md b/sdk/keyvault/Azure.Security.KeyVault.Secrets/README.md index b9970b9567450..c1f25184deaec 100644 --- a/sdk/keyvault/Azure.Security.KeyVault.Secrets/README.md +++ b/sdk/keyvault/Azure.Security.KeyVault.Secrets/README.md @@ -3,7 +3,7 @@ Azure Key Vault is a cloud service that provides a secure storage of secrets, su The Azure Key Vault secrets client library allows you to securely store and control the access to tokens, passwords, API keys, and other secrets. This library offers operations to create, retrieve, update, delete, purge, backup, restore, and list the secrets and its versions. -[Source code][secret_client_src] | [Package (NuGet)][secret_client_nuget_package] | [API reference documentation][API_reference] | [Product documentation][keyvault_docs] | [Samples][secret_client_samples] +[Source code][secret_client_src] | [Package (NuGet)][secret_client_nuget_package] | [API reference documentation][API_reference] | [Product documentation][keyvault_docs] | [Samples][secret_client_samples] | [Migration guide][migration_guide] ## Getting started @@ -333,8 +333,9 @@ This project has adopted the [Microsoft Open Source Code of Conduct][code_of_con [secret_client_samples]: https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/keyvault/Azure.Security.KeyVault.Secrets/samples [secret_client_src]: https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/keyvault/Azure.Security.KeyVault.Secrets/src [soft_delete]: https://docs.microsoft.com/azure/key-vault/key-vault-ovw-soft-delete -[DefaultAzureCredential]: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/README.md +[DefaultAzureCredential]: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/README.md#defaultazurecredential [contributing]: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/keyvault/CONTRIBUTING.md [coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/ +[migration_guide]: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/keyvault/Azure.Security.KeyVault.Secrets/MigrationGuide.md ![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-net%2Fsdk%2Fkeyvault%2FAzure.Security.KeyVault.Secrets%2FREADME.png) diff --git a/sdk/keyvault/Microsoft.Azure.KeyVault/tests/SampleSnippets.cs b/sdk/keyvault/Microsoft.Azure.KeyVault/tests/SampleSnippets.cs index c4b79bcf4c7b9..2990cb82280c2 100644 --- a/sdk/keyvault/Microsoft.Azure.KeyVault/tests/SampleSnippets.cs +++ b/sdk/keyvault/Microsoft.Azure.KeyVault/tests/SampleSnippets.cs @@ -5,26 +5,31 @@ namespace Microsoft.Azure.KeyVault.Tests { using System; + using System.Globalization; + using System.IO; using System.Net; using System.Net.Http; + using System.Security.Cryptography; + using System.Text; using System.Threading.Tasks; using Microsoft.Rest.Azure; using Microsoft.Azure.KeyVault; using Microsoft.Azure.KeyVault.Models; + using Microsoft.Azure.KeyVault.WebKey; using Microsoft.Azure.Services.AppAuthentication; - // Used to compile sample snippets used in Azure.Security.KeyVault.Secrets' MigrationGuide.md. + // Used to compile sample snippets used in MigrationGuide.md documents for track 1. internal class SampleSnippets { - private async Task MigrationGuide() + private async Task CertificatesMigrationGuide() { - #region Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_Create + #region Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_Create AzureServiceTokenProvider provider = new AzureServiceTokenProvider(); KeyVaultClient client = new KeyVaultClient( new KeyVaultClient.AuthenticationCallback(provider.KeyVaultTokenCallback)); - #endregion Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_Create + #endregion Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_Create - #region Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_CreateWithOptions + #region Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_CreateWithOptions using (HttpClient httpClient = new HttpClient()) { //@@AzureServiceTokenProvider provider = new AzureServiceTokenProvider(); @@ -34,26 +39,357 @@ private async Task MigrationGuide() new KeyVaultClient.AuthenticationCallback(provider.KeyVaultTokenCallback), httpClient); } - #endregion Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_CreateWithOptions + #endregion Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_CreateWithOptions + #region Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_CreateCustomPolicy + CertificatePolicy policy = new CertificatePolicy { - #region Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_SetSecret + IssuerParameters = new IssuerParameters("issuer-name"), + SecretProperties = new SecretProperties("application/x-pkcs12"), + KeyProperties = new KeyProperties + { + KeyType = "RSA", + KeySize = 2048, + ReuseKey = true + }, + X509CertificateProperties = new X509CertificateProperties("CN=customdomain.com") + { + KeyUsage = new[] + { + KeyUsageType.CRLSign, + KeyUsageType.DataEncipherment, + KeyUsageType.DigitalSignature, + KeyUsageType.KeyEncipherment, + KeyUsageType.KeyAgreement, + KeyUsageType.KeyCertSign + }, + ValidityInMonths = 12 + }, + LifetimeActions = new[] + { + new LifetimeAction( + new Trigger + { + DaysBeforeExpiry = 90 + }, + new Models.Action(ActionType.AutoRenew)) + } + }; + #endregion Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_CreateCustomPolicy + + { + #region Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_CreateCertificate + CertificateBundle certificate = null; + + // Start certificate creation. + // Depending on the policy and your business process, this could even take days for manual signing. + CertificateOperation createOperation = await client.CreateCertificateAsync("https://myvault.vault.azure.net", "certificate-name", policy); + while (true) + { + if ("InProgress".Equals(createOperation.Status, StringComparison.OrdinalIgnoreCase)) + { + await Task.Delay(TimeSpan.FromSeconds(20)); + + createOperation = await client.GetCertificateOperationAsync("https://myvault.vault.azure.net", "certificate-name"); + continue; + } + + if ("Completed".Equals(createOperation.Status, StringComparison.OrdinalIgnoreCase)) + { + certificate = await client.GetCertificateAsync(createOperation.Id); + break; + } + + throw new Exception(string.Format( + CultureInfo.InvariantCulture, + "Polling on pending certificate returned an unexpected result. Error code = {0}, Error message = {1}", + createOperation.Error.Code, + createOperation.Error.Message)); + } + + // If you need to restart the application you can recreate the operation and continue awaiting. + do + { + createOperation = await client.GetCertificateOperationAsync("https://myvault.vault.azure.net", "certificate-name"); + + if ("InProgress".Equals(createOperation.Status, StringComparison.OrdinalIgnoreCase)) + { + await Task.Delay(TimeSpan.FromSeconds(20)); + continue; + } + + if ("Completed".Equals(createOperation.Status, StringComparison.OrdinalIgnoreCase)) + { + certificate = await client.GetCertificateAsync(createOperation.Id); + break; + } + + throw new Exception(string.Format( + CultureInfo.InvariantCulture, + "Polling on pending certificate returned an unexpected result. Error code = {0}, Error message = {1}", + createOperation.Error.Code, + createOperation.Error.Message)); + } while (true); + #endregion Snippet:Azure_Security_KeyVault_Certificates_Snippets_MigrationGuide_CreateCertificate + } + + { + #region Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_ImportCertificate + byte[] cer = File.ReadAllBytes("certificate.pfx"); + string cerBase64 = Convert.ToBase64String(cer); + + CertificateBundle certificate = await client.ImportCertificateAsync( + "https://myvault.vault.azure.net", + "certificate-name", + cerBase64, + certificatePolicy: policy); + #endregion Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_ImportCertificate + } + + #region Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_CreateSelfSignedPolicy + //@@CertificatePolicy policy = new CertificatePolicy + /*@@*/ + policy = new CertificatePolicy + { + IssuerParameters = new IssuerParameters("Self"), + X509CertificateProperties = new X509CertificateProperties("CN=DefaultPolicy") + }; + #endregion Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_CreateSelfSignedPolicy + // TODO + + { + #region Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_ListCertificates + IPage page = await client.GetCertificatesAsync("https://myvault.vault.azure.net"); + foreach (CertificateItem item in page) + { + CertificateIdentifier certificateId = item.Identifier; + CertificateBundle certificate = await client.GetCertificateAsync(certificateId.Vault, certificateId.Name); + } + + while (page.NextPageLink != null) + { + page = await client.GetCertificatesNextAsync(page.NextPageLink); + foreach (CertificateItem item in page) + { + CertificateIdentifier certificateId = item.Identifier; + CertificateBundle certificate = await client.GetCertificateAsync(certificateId.Vault, certificateId.Name); + } + } + #endregion Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_ListCertificates + } + + { + #region Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_DeleteCertificate + // Delete the certificate. + DeletedCertificateBundle deletedCertificate = await client.DeleteCertificateAsync("https://myvault.vault.azure.net", "certificate-name"); + + // Purge or recover the deleted certificate if soft delete is enabled. + if (deletedCertificate.RecoveryId != null) + { + DeletedCertificateIdentifier deletedCertificateId = deletedCertificate.RecoveryIdentifier; + + // Deleting a certificate does not happen immediately. Wait a while and check if the deleted certificate exists. + while (true) + { + try + { + await client.GetDeletedCertificateAsync(deletedCertificateId.Vault, deletedCertificateId.Name); + + // Finally deleted. + break; + } + catch (KeyVaultErrorException ex) when (ex.Response.StatusCode == HttpStatusCode.NotFound) + { + // Not yet deleted... + } + } + + // Purge the deleted certificate. + await client.PurgeDeletedCertificateAsync(deletedCertificateId.Vault, deletedCertificateId.Name); + + // You can also recover the deleted certificate using RecoverDeletedCertificateAsync. + } + #endregion Snippet:Microsoft_Azure_KeyVault_Certificates_Snippets_MigrationGuide_DeleteCertificate + } + } + + private async Task KeysMigrationGuide() + { + #region Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_Create + AzureServiceTokenProvider provider = new AzureServiceTokenProvider(); + KeyVaultClient client = new KeyVaultClient( + new KeyVaultClient.AuthenticationCallback(provider.KeyVaultTokenCallback)); + #endregion Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_Create + + #region Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_CreateWithOptions + using (HttpClient httpClient = new HttpClient()) + { + //@@AzureServiceTokenProvider provider = new AzureServiceTokenProvider(); + /*@@*/ provider = new AzureServiceTokenProvider(); + //@@KeyVaultClient client = new KeyVaultClient( + /*@@*/ client = new KeyVaultClient( + new KeyVaultClient.AuthenticationCallback(provider.KeyVaultTokenCallback), + httpClient); + } + #endregion Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_CreateWithOptions + + { + #region Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_CreateKey + // Create RSA key. + NewKeyParameters createRsaParameters = new NewKeyParameters + { + Kty = JsonWebKeyType.Rsa, + KeySize = 4096 + }; + + KeyBundle rsaKey = await client.CreateKeyAsync("https://myvault.vault.azure.net", "rsa-key-name", createRsaParameters); + + // Create Elliptic-Curve key. + NewKeyParameters createEcParameters = new NewKeyParameters + { + Kty = JsonWebKeyType.EllipticCurve, + CurveName = "P-256" + }; + + KeyBundle ecKey = await client.CreateKeyAsync("https://myvault.vault.azure.net", "ec-key-name", createEcParameters); + #endregion Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_CreateKey + } + + { + #region Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_ListKeys + IPage page = await client.GetKeysAsync("https://myvault.vault.azure.net"); + foreach (KeyItem item in page) + { + KeyIdentifier keyId = item.Identifier; + KeyBundle key = await client.GetKeyAsync(keyId.Vault, keyId.Name); + } + + while (page.NextPageLink != null) + { + page = await client.GetKeysNextAsync(page.NextPageLink); + foreach (KeyItem item in page) + { + KeyIdentifier keyId = item.Identifier; + KeyBundle key = await client.GetKeyAsync(keyId.Vault, keyId.Name); + } + } + #endregion Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_ListKeys + } + + { + #region Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_DeleteKey + // Delete the key. + DeletedKeyBundle deletedKey = await client.DeleteKeyAsync("https://myvault.vault.azure.net", "key-name"); + + // Purge or recover the deleted key if soft delete is enabled. + if (deletedKey.RecoveryId != null) + { + DeletedKeyIdentifier deletedKeyId = deletedKey.RecoveryIdentifier; + + // Deleting a key does not happen immediately. Wait a while and check if the deleted key exists. + while (true) + { + try + { + await client.GetDeletedKeyAsync(deletedKeyId.Vault, deletedKeyId.Name); + + // Finally deleted. + break; + } + catch (KeyVaultErrorException ex) when (ex.Response.StatusCode == HttpStatusCode.NotFound) + { + // Not yet deleted... + } + } + + // Purge the deleted key. + await client.PurgeDeletedKeyAsync(deletedKeyId.Vault, deletedKeyId.Name); + + // You can also recover the deleted key using RecoverDeletedKeyAsync. + } + #endregion Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_DeleteKey + } + + { + #region Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_Encrypt + // Encrypt a message. The plaintext must be small enough for the chosen algorithm. + byte[] plaintext = Encoding.UTF8.GetBytes("Small message to encrypt"); + KeyOperationResult encrypted = await client.EncryptAsync("rsa-key-name", JsonWebKeyEncryptionAlgorithm.RSAOAEP256, plaintext); + + // Decrypt the message. + KeyOperationResult decrypted = await client.DecryptAsync("rsa-key-name", JsonWebKeyEncryptionAlgorithm.RSAOAEP256, encrypted.Result); + string message = Encoding.UTF8.GetString(decrypted.Result); + #endregion Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_Encrypt + } + + { + #region Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_Wrap + using (Aes aes = Aes.Create()) + { + // Use a symmetric key to encrypt large amounts of data, possibly streamed... + + // Now wrap the key and store the encrypted key and plaintext IV to later decrypt the key to decrypt the data. + KeyOperationResult wrapped = await client.WrapKeyAsync( + "https://myvault.vault.azure.net", + "rsa-key-name", + null, + JsonWebKeyEncryptionAlgorithm.RSAOAEP256, + aes.Key); + + // Read the IV and the encrypted key from the payload, then unwrap the key. + KeyOperationResult unwrapped = await client.UnwrapKeyAsync( + "https://myvault.vault.azure.net", + "rsa-key-name", + null, + JsonWebKeyEncryptionAlgorithm.RSAOAEP256, + wrapped.Result); + + aes.Key = unwrapped.Result; + + // Decrypt the payload with the symmetric key. + } + #endregion Snippet:Microsoft_Azure_KeyVault_Keys_Snippets_MigrationGuide_Wrap + } + } + + private async Task SecretsMigrationGuide() + { + #region Snippet:Microsoft_Azure_KeyVault_Secrets_Snippets_MigrationGuide_Create + AzureServiceTokenProvider provider = new AzureServiceTokenProvider(); + KeyVaultClient client = new KeyVaultClient( + new KeyVaultClient.AuthenticationCallback(provider.KeyVaultTokenCallback)); + #endregion Snippet:Microsoft_Azure_KeyVault_Secrets_Snippets_MigrationGuide_Create + + #region Snippet:Microsoft_Azure_KeyVault_Secrets_Snippets_MigrationGuide_CreateWithOptions + using (HttpClient httpClient = new HttpClient()) + { + //@@AzureServiceTokenProvider provider = new AzureServiceTokenProvider(); + /*@@*/ provider = new AzureServiceTokenProvider(); + //@@KeyVaultClient client = new KeyVaultClient( + /*@@*/ client = new KeyVaultClient( + new KeyVaultClient.AuthenticationCallback(provider.KeyVaultTokenCallback), + httpClient); + } + #endregion Snippet:Microsoft_Azure_KeyVault_Secrets_Snippets_MigrationGuide_CreateWithOptions + + { + #region Snippet:Microsoft_Azure_KeyVault_Secrets_Snippets_MigrationGuide_SetSecret SecretBundle secret = await client.SetSecretAsync("https://myvault.vault.azure.net", "secret-name", "secret-value"); - #endregion Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_SetSecret + #endregion Snippet:Microsoft_Azure_KeyVault_Secrets_Snippets_MigrationGuide_SetSecret } { - #region Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_GetSecret + #region Snippet:Microsoft_Azure_KeyVault_Secrets_Snippets_MigrationGuide_GetSecret // Get the latest secret value. SecretBundle secret = await client.GetSecretAsync("https://myvault.vault.azure.net", "secret-name", null); // Get a specific secret value. SecretBundle secretVersion = await client.GetSecretAsync("https://myvault.vault.azure.net", "secret-name", "e43af03a7cbc47d4a4e9f11540186048"); - #endregion Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_GetSecret + #endregion Snippet:Microsoft_Azure_KeyVault_Secrets_Snippets_MigrationGuide_GetSecret } { - #region Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_ListSecrets + #region Snippet:Microsoft_Azure_KeyVault_Secrets_Snippets_MigrationGuide_ListSecrets IPage page = await client.GetSecretsAsync("https://myvault.vault.azure.net"); foreach (SecretItem item in page) { @@ -70,11 +406,11 @@ private async Task MigrationGuide() SecretBundle secret = await client.GetSecretAsync(secretId.Vault, secretId.Name); } } - #endregion Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_ListSecrets + #endregion Snippet:Microsoft_Azure_KeyVault_Secrets_Snippets_MigrationGuide_ListSecrets } { - #region Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_DeleteSecret + #region Snippet:Microsoft_Azure_KeyVault_Secrets_Snippets_MigrationGuide_DeleteSecret // Delete the secret. DeletedSecretBundle deletedSecret = await client.DeleteSecretAsync("https://myvault.vault.azure.net", "secret-name"); @@ -104,7 +440,7 @@ private async Task MigrationGuide() // You can also recover the deleted secret using RecoverDeletedSecretAsync. } - #endregion Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_DeleteSecret + #endregion Snippet:Microsoft_Azure_KeyVault_Secrets_Snippets_MigrationGuide_DeleteSecret } } } diff --git a/sdk/servicebus/Azure.Messaging.ServiceBus/README.md b/sdk/servicebus/Azure.Messaging.ServiceBus/README.md index 758be2ed6964c..48cb3739a1076 100755 --- a/sdk/servicebus/Azure.Messaging.ServiceBus/README.md +++ b/sdk/servicebus/Azure.Messaging.ServiceBus/README.md @@ -12,7 +12,7 @@ Use the client library for Azure Service Bus to: - Implement complex workflows: message sessions support scenarios that require message ordering or message deferral. -[Source code](.) | [Package (NuGet)](https://www.nuget.org/packages/Azure.Messaging.ServiceBus/) | [API reference documentation](https://azure.github.io/azure-sdk-for-net/servicebus.html) | [Product documentation](https://docs.microsoft.com/en-us/azure/service-bus/) +[Source code](.) | [Package (NuGet)](https://www.nuget.org/packages/Azure.Messaging.ServiceBus/) | [API reference documentation](https://azure.github.io/azure-sdk-for-net/servicebus.html) | [Product documentation](https://docs.microsoft.com/en-us/azure/service-bus/) | [Migration guide](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/servicebus/Azure.Messaging.ServiceBus/MigrationGuide.md) ## Getting started