diff --git a/docs/database/includes/postgresql-flexible-server.md b/docs/database/includes/postgresql-flexible-server.md index 8a101852a1..32313c51cf 100644 --- a/docs/database/includes/postgresql-flexible-server.md +++ b/docs/database/includes/postgresql-flexible-server.md @@ -55,3 +55,123 @@ The preceding call to `AddAzurePostgresFlexibleServer` configures the PostgresSQ > [!TIP] > When you call , it implicitly calls —which adds support for generating Azure resources dynamically during app startup. The app must configure the appropriate subscription and location. For more information, see [Local provisioning: Configuration](../../azure/local-provisioning.md#configuration). + +#### Generated provisioning Bicep + +If you're new to [Bicep](/azure/azure-resource-manager/bicep/overview), it's a domain-specific language for defining Azure resources. With .NET Aspire, you don't need to write Bicep by hand, because the provisioning APIs generate Bicep for you. When you publish your app, the generated Bicep is output alongside the manifest file. When you add an Azure PostgreSQL resource, the following Bicep is generated: + + +
+
+Toggle Azure PostgreSQL Bicep. +

+ +:::code language="bicep" source="../../snippets/azure/AppHost/postgres-flexible.module.bicep"::: + +

+
+ + +The preceding Bicep is a module that provisions an Azure PostgreSQL flexible server with the following defaults: + +- `authConfig`: The authentication configuration of the PostgreSQL server. The default is `ActiveDirectoryAuth` enabled and `PasswordAuth` disabled. +- `availabilityZone`: The availability zone of the PostgreSQL server. The default is `1`. +- `backup`: The backup configuration of the PostgreSQL server. The default is `BackupRetentionDays` set to `7` and `GeoRedundantBackup` set to `Disabled`. +- `highAvailability`: The high availability configuration of the PostgreSQL server. The default is `Disabled`. +- `storage`: The storage configuration of the PostgreSQL server. The default is `StorageSizeGB` set to `32`. +- `version`: The version of the PostgreSQL server. The default is `16`. +- `sku`: The SKU of the PostgreSQL server. The default is `Standard_B1ms`. +- `tags`: The tags of the PostgreSQL server. The default is `aspire-resource-name` set to the name of the Aspire resource, in this case `postgres-flexible`. + +In addition to the PostgreSQL flexible server, it also provisions an Azure Firewall rule to allow all Azure IP addresses. Finally, an administrator is created for the PostgreSQL server, and the connection string is outputted as an output variable. The generated Bicep is a starting point and can be customized to meet your specific requirements. + +#### Customize provisioning infrastructure + +All .NET Aspire Azure resources are subclasses of the type. This type enables the customization of the generated Bicep by providing a fluent API to configure the Azure resources by using the API. For example, you can configure the `kind`, `consistencyPolicy`, `locations`, and more. The following example demonstrates how to customize the PostgreSQL server resource: + +:::code language="csharp" source="../../snippets/azure/AppHost/Program.ConfigurePostgresSQLInfra.cs" id="configure"::: + +The preceding code: + +- Chains a call to the API: + - The `infra` parameter is an instance of the type. + - The provisionable resources are retrieved by calling the method. + - The single is retrieved. + - The `sku` is set with . + - The high availability properties are set with in standby availability zone `"2"`. + - A tag is added to the flexible server with a key of `ExampleKey` and a value of `Example value`. + +There are many more configuration options available to customize the PostgreSQL flexible server resource. For more information, see and [Azure.Provisioning customization](../../azure/integrations-overview.md#azureprovisioning-customization). + +### Connect to an existing Azure PostgreSQL flexible server + +You might have an existing Azure PostgreSQL flexible server that you want to connect to. Instead of representing a new Azure PostgreSQL flexible server resource, you can add a connection string to the app host. To add a connection to an existing Azure PostgreSQL flexible server, call the method: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var postgres = builder.AddConnectionString("postgres"); + +builder.AddProject("web") + .WithReference(postgres); + +// After adding all resources, run the app... +``` + +[!INCLUDE [connection-strings-alert](../../includes/connection-strings-alert.md)] + +The connection string is configured in the app host's configuration, typically under [User Secrets](/aspnet/core/security/app-secrets), under the `ConnectionStrings` section. The app host injects this connection string as an environment variable into all dependent resources, for example: + +```json +{ + "ConnectionStrings": { + "postgres": "Server=.postgres.database.azure.com;Database=;Port=5432;Ssl Mode=Require;User Id=;" + } +} +``` + +The dependent resource can access the injected connection string by calling the method, and passing the connection name as the parameter, in this case `"postgres"`. The `GetConnectionString` API is shorthand for `IConfiguration.GetSection("ConnectionStrings")[name]`. + +### Run Azure PostgreSQL resource as a container + +The Azure PostgreSQL hosting integration supports running the PostgreSQL server as a local container. This is beneficial for situations where you want to run the PostgreSQL server locally for development and testing purposes, avoiding the need to provision an Azure resource or connect to an existing Azure PostgreSQL server. + +To run the PostgreSQL server as a container, call the method: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var postgres = builder.AddAzurePostgresFlexibleServer("postgres") + .RunAsContainer(); + +var postgresdb = postgres.AddDatabase("postgresdb"); + +var exampleProject = builder.AddProject() + .WithReference(postgresdb); +``` + +The preceding code configures an Azure PostgreSQL Flexible Server resource to run locally in a container. + +> [!TIP] +> The `RunAsContainer` method is useful for local development and testing. The API exposes an optional delegate that enables you to customize the underlying configuration. For example, you can add pgAdmin and pgWeb, add a data volume or data bind mount, and add an init bind mount. For more information, see the [.NET Aspire PostgreSQL hosting integration](../postgresql-integration.md#add-postgresql-pgadmin-resource) section. + +### Configure the Azure PostgreSQL server to use password authentication + +By default, the Azure PostgreSQL server is configured to use [Microsoft Entra ID](/azure/postgresql/flexible-server/concepts-azure-ad-authentication) authentication. If you want to use password authentication, you can configure the server to use password authentication by calling the method: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var username = builder.AddParameter("username", secret: true); +var password = builder.AddParameter("password", secret: true); + +var postgres = builder.AddAzurePostgresFlexibleServer("postgres") + .WithPasswordAuthentication(username, password); + +var postgresdb = postgres.AddDatabase("postgresdb"); + +var exampleProject = builder.AddProject() + .WithReference(postgresdb); +``` + +The preceding code configures the Azure PostgreSQL server to use password authentication. The `username` and `password` parameters are added to the app host as parameters, and the `WithPasswordAuthentication` method is called to configure the Azure PostgreSQL server to use password authentication. For more information, see [External parameters](../../fundamentals/external-parameters.md). diff --git a/docs/security/azure-security-key-vault-integration.md b/docs/security/azure-security-key-vault-integration.md index 180446a232..419b6555c5 100644 --- a/docs/security/azure-security-key-vault-integration.md +++ b/docs/security/azure-security-key-vault-integration.md @@ -1,28 +1,30 @@ --- title: .NET Aspire Azure Key Vault integration -description: Lean about the .NET Aspire Azure Key Vault integration. -ms.topic: how-to -ms.date: 08/12/2024 +description: Learn about the .NET Aspire Azure Key Vault integration. +ms.date: 02/07/2025 +uid: security/azure-security-key-vault-integration --- # .NET Aspire Azure Key Vault integration -In this article, you learn how to use the .NET Aspire Azure Key Vault integration. The `Aspire.Azure.Key.Vault` integration library is used to register a in the DI container for connecting to Azure Key Vault. It also enables corresponding health checks, logging and telemetry. +[!INCLUDE [includes-hosting-and-client](../includes/includes-hosting-and-client.md)] -## Get started +[Azure Key Vault](/azure/key-vault/) is a cloud service for securely storing and accessing secrets. The .NET Aspire Azure Key Vault integration enables you to connect to Azure Key Vault instances from your .NET applications. -To get started with the .NET Aspire Azure Key Vault integration, install the [📦 Aspire.Azure.Security.KeyVault](https://www.nuget.org/packages/Aspire.Azure.Security.KeyVault) NuGet package in the client-consuming project, i.e., the project for the application that uses the Azure Key Vault client. +## Hosting integration + +The Azure Key Vault hosting integration models a Key Vault resource as the type. To access this type and APIs for expressing them within your [app host](xref:dotnet/aspire/app-host) project, install the [📦 Aspire.Hosting.Azure.KeyVault](https://www.nuget.org/packages/Aspire.Hosting.Azure.KeyVault) NuGet package: ### [.NET CLI](#tab/dotnet-cli) ```dotnetcli -dotnet add package Aspire.Azure.Security.KeyVault +dotnet add package Aspire.Hosting.Azure.KeyVault ``` ### [PackageReference](#tab/package-reference) ```xml - ``` @@ -30,84 +32,238 @@ dotnet add package Aspire.Azure.Security.KeyVault For more information, see [dotnet add package](/dotnet/core/tools/dotnet-add-package) or [Manage package dependencies in .NET applications](/dotnet/core/tools/dependencies). -## Example usage +### Add Azure Key Vault resource -THe following sections describe various example usages. +In your app host project, call on the builder instance to add an Azure Key Vault resource: -### Add secrets to configuration +```csharp +var builder = DistributedApplication.CreateBuilder(args); -In the _:::no-loc text="Program.cs":::_ file of your client-consuming project, call the extension to add the secrets in the Azure Key Vault to the application's Configuration. The method takes a connection name parameter. +var keyVault = builder.AddAzureKeyVault("key-vault"); -```csharp -builder.Configuration.AddAzureKeyVaultSecrets("secrets"); +builder.AddProject() + .WithReference(keyVault); + +// After adding all resources, run the app... ``` -You can then retrieve a secret through normal APIs. For example, to retrieve a secret from a service: +The method configures a connection in the `ExampleProject` named `"key-vault"`. -```csharp -public class ExampleService(IConfiguration configuration) -{ - string secretValue = configuration["secretKey"]; - // Use secretValue ... -} -``` +> [!IMPORTANT] +> By default, `AddAzureKeyVault` configures a [Key Vault Administrator built-in role](/azure/role-based-access-control/built-in-roles/security#key-vault-administrator). + +> [!TIP] +> When you call , it implicitly calls , which adds support for generating Azure resources dynamically during app startup. The app must configure the appropriate subscription and location. For more information, see [Local provisioning: Configuration](../azure/local-provisioning.md#configuration). + +#### Generated provisioning Bicep + +If you're new to [Bicep](/azure/azure-resource-manager/bicep/overview), it's a domain-specific language for defining Azure resources. With .NET Aspire, you don't need to write Bicep by-hand, instead the provisioning APIs generate Bicep for you. When you publish your app, the generated Bicep is output alongside the manifest file. When you add an Azure Key Vault resource, the following Bicep is generated: + + +
+
+Toggle Azure Key Vault Bicep. +

+ +:::code language="bicep" source="../snippets/azure/AppHost/key-vault.module.bicep"::: + +

+
+ + +The preceding Bicep is a module that provisions an Azure Key Vault resource with the following defaults: + +- `location`: The location of the resource group. +- `principalId`: The principal ID of the user or service principal. +- `principalType`: The principal type of the user or service principal. +- `key_vault`: The Azure Key Vault resource: + - `name`: A unique name for the Azure Key Vault. + - `properties`: The Azure Key Vault properties: + - `tenantId`: The tenant ID of the Azure Key Vault. + - `sku`: The Azure Key Vault SKU: + - `family`: The SKU family. + - `name`: The SKU name. + - `enableRbacAuthorization`: A boolean value that indicates whether the Azure Key Vault has role-based access control (RBAC) authorization enabled. + - `tags`: The Azure Key Vault tags. +- `key_vault_KeyVaultAdministrator`: The Azure Key Vault administrator role assignment: + - `name`: A unique name for the role assignment. + - `properties`: The role assignment properties: + - `principalId`: The principal ID of the user or service principal. + - `roleDefinitionId`: The role definition ID of the Azure Key Vault administrator role. + - `principalType`: The principal type of the user or service principal. + - `scope`: The scope of the role assignment. +- `output`: The Azure Key Vault URI. + +The generated Bicep is a starting point and can be customized to meet your specific requirements. -### Use `SecretClient` +#### Customize provisioning infrastructure -Alternatively, you can use a `SecretClient` to retrieve the secrets on demand. In the _:::no-loc text="Program.cs":::_ file of your client-consuming project, call the extension to register a `SecretClient` for use via the dependency injection container. +All .NET Aspire Azure resources are subclasses of the type. This type enables the customization of the generated Bicep by providing a fluent API to configure the Azure resources by using the API. For example, you can configure the `sku`, `RBAC`, `tags`, and more. The following example demonstrates how to customize the Azure Key Vault resource: + +:::code language="csharp" source="../snippets/azure/AppHost/Program.ConfigureKeyVaultInfra.cs" id="configure"::: + +The preceding code: + +- Chains a call to the API: + - The `infra` parameter is an instance of the type. + - The provisionable resources are retrieved by calling the method. + - The single resource is retrieved. + - The `Sku` property is set to a new instance. + - The property is set to `true`. + - A tag is added to the resource with a key of `ExampleKey` and a value of `Example value`. + +There are many more configuration options available to customize the Key Vault resource. For more information, see and [Azure.Provisioning customization](../azure/integrations-overview.md#azureprovisioning-customization). + +### Connect to an existing Azure Key Vault instance + +You might have an existing Azure Key Vault instance that you want to connect to. Instead of representing a new Azure Key Vault resource, you can add a connection string to the app host. To add a connection to an existing Azure Key Vault resource, call the method: ```csharp -builder.AddAzureKeyVaultClient("secrets"); +var builder = DistributedApplication.CreateBuilder(args); + +var keyVault = builder.AddConnectionString("key-vault"); + +builder.AddProject("web") + .WithReference(keyVault); + +// After adding all resources, run the app... ``` -You can then retrieve the instance using dependency injection. For example, to retrieve the client from a service: +[!INCLUDE [connection-strings-alert](../includes/connection-strings-alert.md)] -```csharp -public class ExampleService(SecretClient client) +The connection string is configured in the app host's configuration, typically under [User Secrets](/aspnet/core/security/app-secrets), under the `ConnectionStrings` section. The app host injects this connection string as an environment variable into all dependent resources, for example: + +```json { - // Use client... + "ConnectionStrings": { + "key-vault": "https://{account_name}.vault.azure.net/" + } } ``` -## App host usage +The dependent resource can access the injected connection string by calling the method, and passing the connection name as the parameter, in this case `"key-vault"`. The `GetConnectionString` API is shorthand for `IConfiguration.GetSection("ConnectionStrings")[name]`. + +## Client integration -To add Azure Key Vault hosting support to your , install the [📦 Aspire.Hosting.Azure.KeyVault](https://www.nuget.org/packages/Aspire.Hosting.Azure.KeyVault) NuGet package in the [app host](xref:dotnet/aspire/app-host) project. +To get started with the .NET Aspire Azure Key Vault client integration, install the [📦 Aspire.Azure.Security.KeyVault](https://www.nuget.org/packages/Aspire.Azure.Security.KeyVault) NuGet package in the client-consuming project, that is, the project for the application that uses the Azure Key Vault client. ### [.NET CLI](#tab/dotnet-cli) ```dotnetcli -dotnet add package Aspire.Hosting.Azure.KeyVault +dotnet add package Aspire.Azure.Security.KeyVault ``` ### [PackageReference](#tab/package-reference) ```xml - ``` --- -In your app host project, register the Azure Key Vault integration and consume the service using the following methods: +The client integration provides two ways to access secrets from Azure Key Vault: + +- Add secrets to app configuration, using either the `IConfiguration` or the `IOptions` pattern. +- Use a `SecretClient` to retrieve secrets on demand. + +### Add secrets to configuration + +In the :::no-loc text="Program.cs"::: file of your client-consuming project, call the extension method on the to add the secrets as part of your app's configuration. The method takes a connection name parameter. ```csharp -var builder = DistributedApplication.CreateBuilder(args); +builder.Configuration.AddAzureKeyVaultSecrets(connectionName: "key-vault"); +``` -var secrets = builder.ExecutionContext.IsPublishMode - ? builder.AddAzureKeyVault("secrets") - : builder.AddConnectionString("secrets"); +> [!NOTE] +> The `AddAzureKeyVaultSecrets` API name has caused a bit of confusion. The method is used to configure the `SecretClient` based on the given connection name, and _it's not used_ to add secrets to the configuration. -builder.AddProject() - .WithReference(secrets) +> [!TIP] +> The `connectionName` parameter must match the name used when adding the Azure Key Vault resource in the app host project. For more information, see [Add Azure Key Vault resource](#add-azure-key-vault-resource). + +You can then retrieve a secret-based configuration value through the normal APIs, or even by binding to strongly-typed classes with the [options pattern](/dotnet/core/extensions/options). To retrieve a secret from an example service class that's been registered with the dependency injection container, consider the following snippets: + +#### Retrieve `IConfiguration` instance + +```csharp +public class ExampleService(IConfiguration configuration) +{ + // Use configuration... + private string _secretValue = configuration["SecretKey"]; +} +``` + +The preceding example assumes that you've also registered the `IConfiguration` instance for dependency injection. For more information, see [Dependency injection in .NET](/dotnet/core/extensions/dependency-injection). + +#### Retrieve `IOptions` instance + +```csharp +public class ExampleService(IOptions options) +{ + // Use options... + private string _secretValue = options.Value.SecretKey; +} ``` -The preceding code conditionally adds the Azure Key Vault resource to the project based on the execution context. If the app host is executing in publish mode, the resource is added otherwise the connection string to an existing resource is added. +The preceding example assumes that you've configured a `SecretOptions` class for use with the options pattern. For more information, see [Options pattern in .NET](/dotnet/core/extensions/options). + +Additional `AddAzureKeyVaultSecrets` API parameters are available optionally for the following scenarios: + +- `Action? configureSettings`: To set up some or all the options inline. +- `Action? configureClientOptions`: To set up the inline. +- `AzureKeyVaultConfigurationOptions? options`: To configure the inline. + +### Add an Azure Secret client -## Configuration +Alternatively, you can use the directly to retrieve the secrets on demand. This requires a slightly different registration API. + +In the :::no-loc text="Program.cs"::: file of your client-consuming project, call the extension on the instance to register a `SecretClient` for use via the dependency injection container. + +```csharp +builder.AddAzureKeyVaultClient(connectionName: "key-vault"); +``` + +> [!TIP] +> The `connectionName` parameter must match the name used when adding the Azure Key Vault resource in the app host project. For more information, see [Add Azure Key Vault resource](#add-azure-key-vault-resource). + +After adding the `SecretClient` to the builder, you can get the instance using dependency injection. For example, to retrieve the client from an example service define it as a constructor parameter and ensure the `ExampleService` class is registered with the dependency injection container: + +```csharp +public class ExampleService(SecretClient client) +{ + // Use client... +} +``` + +For more information on dependency injection, see [.NET dependency injection](/dotnet/core/extensions/dependency-injection). + +### Add keyed Azure Key Vault client + +There might be situations where you want to register multiple `SecretClient` instances with different connection names. To register keyed Azure Key Vault clients, call the method: + +```csharp +builder.AddKeyedAzureKeyVaultClient(name: "feature-toggles"); +builder.AddKeyedAzureKeyVaultClient(name: "admin-portal"); +``` + +Then you can retrieve the `SecretClient` instances using dependency injection. For example, to retrieve the client from an example service: + +```csharp +public class ExampleService( + [FromKeyedServices("feature-toggles")] SecretClient featureTogglesClient, + [FromKeyedServices("admin-portal")] SecretClient adminPortalClient) +{ + // Use clients... +} +``` + +For more information on keyed services, see [.NET dependency injection: Keyed services](/dotnet/core/extensions/dependency-injection#keyed-services). + +### Configuration The .NET Aspire Azure Key Vault integration provides multiple options to configure the `SecretClient` based on the requirements and conventions of your project. -### Use configuration providers +#### Use configuration providers The .NET Aspire Azure Key Vault integration supports . It loads the from _:::no-loc text="appsettings.json":::_ or other configuration files using `Aspire:Azure:Security:KeyVault` key. @@ -117,11 +273,12 @@ The .NET Aspire Azure Key Vault integration supports ` delegate to set up some or all the options inline, for example to set the `VaultUri`: +You can also pass the `Action` delegate to set up some or all the options inline, for example to set the : ```csharp builder.AddAzureKeyVaultSecrets( - "secrets", - static settings => settings.VaultUri = new Uri("YOUR_VAULTURI")); + connectionName: "key-vault", + configureSettings: settings => settings.VaultUri = new Uri("KEY_VAULT_URI")); ``` -> [!TIP] -> The `AddAzureKeyVaultSecrets` API name has caused a bit of confusion. The method is used to configure the `SecretClient` and not to add secrets to the configuration. - -You can also set up the using `Action>` delegate, the second parameter of the `AddAzureKeyVaultSecrets` method. For example to set the ID to identify the client: +You can also set up the using `Action` delegate, which is an optional parameter of the `AddAzureKeyVaultSecrets` method. For example to set the ID to identify the client: ```csharp builder.AddAzureKeyVaultSecrets( - "secrets", - static clientBuilder => - clientBuilder.ConfigureOptions( - static options => options.DisableChallengeResourceVerification = true)) + connectionName: "key-vault", + configureClientOptions: options => options.DisableChallengeResourceVerification = true)) ``` ### Configuration options The following configurable options are exposed through the class: -| Name | Description | -|-----------------------|----------------------------------------------------------------------------------------------| -| `VaultUri` | A URI to the vault on which the client operates. Appears as "DNS Name" in the Azure portal. | -| `Credential` | The credential used to authenticate to the Azure Key Vault. | -| `DisableHealthChecks` | A boolean value that indicates whether the Key Vault health check is disabled or not. | -| `DisableTracing` | A boolean value that indicates whether the OpenTelemetry tracing is disabled or not. | +| Name | Description | +|--|--| +| | The credential used to authenticate to the Azure Key Vault. | +| | A boolean value that indicates whether the Key Vault health check is disabled or not. | +| | A boolean value that indicates whether the OpenTelemetry tracing is disabled or not. | +| | A URI to the vault on which the client operates. Appears as "DNS Name" in the Azure portal. | [!INCLUDE [client-integration-health-checks](../includes/client-integration-health-checks.md)] @@ -186,7 +340,7 @@ The .NET Aspire Azure Key Vault integration uses the following log categories: The .NET Aspire Azure Key Vault integration will emit the following tracing activities using OpenTelemetry: -- "Azure.Security.KeyVault.Secrets.SecretClient" +- `Azure.Security.KeyVault.Secrets.SecretClient` ### Metrics @@ -195,5 +349,7 @@ The .NET Aspire Azure Key Vault integration currently does not support metrics b ## See also - [Azure Key Vault docs](/azure/key-vault/general/) -- [.NET Aspire integrations](../fundamentals/integrations-overview.md) +- [Video: Introduction to Azure Key Vault and .NET Aspire](https://www.youtube.com/watch?v=1K5riRctUIg) +- [.NET Aspire Azure integrations overview](../azure/integrations-overview.md) +- [.NET Aspire integrations overview](../fundamentals/integrations-overview.md) - [.NET Aspire GitHub repo](https://github.com/dotnet/aspire) diff --git a/docs/snippets/azure/AppHost/Program.ConfigureKeyVaultInfra.cs b/docs/snippets/azure/AppHost/Program.ConfigureKeyVaultInfra.cs new file mode 100644 index 0000000000..90c3aaa5bf --- /dev/null +++ b/docs/snippets/azure/AppHost/Program.ConfigureKeyVaultInfra.cs @@ -0,0 +1,24 @@ +using Azure.Provisioning.KeyVault; +internal static partial class Program +{ + public static void ConfigureKeyVaultInfra(IDistributedApplicationBuilder builder) + { + // + builder.AddAzureKeyVault("key-vault") + .ConfigureInfrastructure(infra => + { + var keyVault = infra.GetProvisionableResources() + .OfType() + .Single(); + + keyVault.Properties.Sku = new() + { + Family = KeyVaultSkuFamily.A, + Name = KeyVaultSkuName.Premium, + }; + keyVault.Properties.EnableRbacAuthorization = true; + keyVault.Tags.Add("ExampleKey", "Example value"); + }); + // + } +}