diff --git a/docs/ai/how-to/app-service-aoai-auth.md b/docs/ai/how-to/app-service-aoai-auth.md index 6e968d54509e1..27cb0e91bd3d4 100644 --- a/docs/ai/how-to/app-service-aoai-auth.md +++ b/docs/ai/how-to/app-service-aoai-auth.md @@ -1,34 +1,30 @@ --- -title: "Authenticate and Authorize App Service to Azure OpenAI using Microsoft Entra and the Semantic Kernel SDK" -description: "Learn how to authenticate and authorize your app service application to an Azure OpenAI resource by using Microsoft Entra managed identities and the Semantic Kernel SDK for .NET." +title: "Authenticate an Azure hosted .NET app to Azure OpenAI using Microsoft Entra ID" +description: "Learn how to authenticate your Azure hosted .NET app to an Azure OpenAI resource using Microsoft Entra ID." author: haywoodsloan ms.topic: how-to ms.custom: devx-track-azurecli -ms.date: 11/24/2024 +ms.date: 01/29/2025 zone_pivot_groups: azure-interface #customer intent: As a .NET developer, I want authenticate and authorize my App Service to Azure OpenAI by using Microsoft Entra so that I can securely use AI in my .NET application. --- -# Authenticate an AI app hosted on Azure App Service to Azure OpenAI using Microsoft Entra ID +# Authenticate to Azure OpenAI from an Azure hosted app using Microsoft Entra ID -This article demonstrates how to use [Microsoft Entra ID managed identities](/azure/app-service/overview-managed-identity) to authenticate and authorize an App Service application to an Azure OpenAI resource. +This article demonstrates how to use [Microsoft Entra ID managed identities](/azure/app-service/overview-managed-identity) and the [Microsoft.Extensions.AI library](/dotnet/ai/ai-extensions) to authenticate an Azure hosted app to an Azure OpenAI resource. -This article also demonstrates how to use the [Semantic Kernel SDK](/semantic-kernel/overview) to easily implement Microsoft Entra authentication in your .NET application. - -By using a managed identity from Microsoft Entra, your App Service application can easily access protected Azure OpenAI resources without having to manually provision or rotate any secrets. +A managed identity from Microsoft Entra ID allows your app to easily access other Microsoft Entra protected resources such as Azure OpenAI. The identity is managed by the Azure platform and doesn't require you to provision, manage, or rotate any secrets. ## Prerequisites * An Azure account that has an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F). * [.NET SDK](https://dotnet.microsoft.com/download/visual-studio-sdks) -* [`Microsoft.SemanticKernel` NuGet package](https://www.nuget.org/packages/Microsoft.SemanticKernel) -* [`Azure.Identity` NuGet package](https://www.nuget.org/packages/Azure.Identity) * [Create and deploy an Azure OpenAI Service resource](/azure/ai-services/openai/how-to/create-resource) * [Create and deploy a .NET application to App Service](/azure/app-service/quickstart-dotnetcore) ## Add a managed identity to App Service -Your application can be granted two types of identities: +Managed identities provide an automatically managed identity in Microsoft Entra ID for applications to use when connecting to resources that support Microsoft Entra authentication. Applications can use managed identities to obtain Microsoft Entra tokens without having to manage any credentials. Your application can be assigned two types of identities: * A **system-assigned identity** is tied to your application and is deleted if your app is deleted. An app can have only one system-assigned identity. * A **user-assigned identity** is a standalone Azure resource that can be assigned to your app. An app can have multiple user-assigned identities. @@ -41,6 +37,11 @@ Your application can be granted two types of identities: 1. Select **Identity**. 1. On the **System assigned** tab, toggle *Status* to **On**, and then select **Save**. + :::image type="content" source="../media/azure-hosted-apps/system-assigned-managed-identity-in-azure-portal.png" alt-text="A screenshot showing how to add a system assigned managed identity to an app."::: + + > [!NOTE] + > The preceding screenshot demonstrates this process on an Azure App Service, but the steps are similar on other hosts such as Azure Container Apps. + ## [User-assigned](#tab/user-assigned) To add a user-assigned identity to your app, create the identity, and then add its resource identifier to your app config. @@ -54,6 +55,11 @@ To add a user-assigned identity to your app, create the identity, and then add i > [!IMPORTANT] > After you select **Add**, the app restarts. + :::image type="content" source="../media/azure-hosted-apps/user-assigned-managed-identity-in-azure-portal.png" alt-text="A screenshot showing how to add a system assigned managed identity to an app."::: + + > [!NOTE] + > The preceding screenshot demonstrates this process on an Azure App Service, but the steps are similar on other hosts such as Azure Container Apps. + --- :::zone-end @@ -86,13 +92,16 @@ az webapp identity assign --name --resource-group :::zone-end -## Add an Azure OpenAI user role to your managed identity +## Add an Azure OpenAI user role to the identity :::zone target="docs" pivot="azure-portal" 1. In the [Azure Portal](https://aka.ms/azureportal), navigate to the scope that you want to grant **Azure OpenAI** access to. The scope can be a **Management group**, **Subscription**, **Resource group**, or a specific **Azure OpenAI** resource. 1. In the left navigation pane, select **Access control (IAM)**. 1. Select **Add**, then select **Add role assignment**. + + :::image type="content" source="../media/azure-hosted-apps/add-entra-role.png" alt-text="A screenshot showing how to add an RBAC role."::: + 1. On the **Role** tab, select the **Cognitive Services OpenAI User** role. 1. On the **Members** tab, select the managed identity. 1. On the **Review + assign** tab, select **Review + assign** to assign the role. @@ -101,7 +110,9 @@ az webapp identity assign --name --resource-group :::zone target="docs" pivot="azure-cli" -**Resource scope** +You can use the Azure CLI to assign the Cognitive Services OpenAI User role to your managed identity at varying scopes. + +# [Resource](#tab/resource) ```azurecli az role assignment create --assignee "" \ @@ -109,7 +120,7 @@ az role assignment create --assignee "" \ --scope "/subscriptions//resourcegroups//providers////" ``` -**Resource group scope** +# [Resource group](#tab/resource-group) ```azurecli az role assignment create --assignee "" \ @@ -117,7 +128,7 @@ az role assignment create --assignee "" \ --scope "/subscriptions//resourcegroups/" ``` -**Subscription scope** +# [Subscription](#tab/subscription) ```azurecli az role assignment create --assignee "" \ @@ -125,7 +136,7 @@ az role assignment create --assignee "" \ --scope "/subscriptions/" ``` -**Management group scope** +# [Management group](#tab/management-group) ```azurecli az role assignment create --assignee "" \ @@ -133,21 +144,44 @@ az role assignment create --assignee "" \ --scope "/providers/Microsoft.Management/managementGroups/" ``` +--- + :::zone-end -## Implement token-based authentication using Semantic Kernel SDK +## Implement identity authentication in your app code + +1. Add the following NuGet packages to your app: + + ```dotnetcli + dotnet add package Azure.Identity + dotnet add package Azure.AI.OpenAI + dotnet add package Microsoft.Extensions.Azure + dotnet add package Microsoft.Extensions.AI + dotnet add package Microsoft.Extensions.AI.OpenAI + ``` + + The preceding packages each handle the following concerns for this scenario: + + - **[Azure.Identity](https://www.nuget.org/packages/Azure.Identity)**: Provides core functionality to work with Microsoft Entra ID + - **[Azure.AI.OpenAI](https://www.nuget.org/packages/Azure.AI.OpenAI)**: Enables your app to interface with the Azure OpenAI service + - **[Microsoft.Extensions.Azure](https://www.nuget.org/packages/Microsoft.Extensions.Azure)**: Provides helper extensions to register services for dependency injection + - **[Microsoft.Extensions.AI](https://www.nuget.org/packages/Microsoft.Extensions.AI)**: Provides AI abstractions for common AI tasks + - **[Microsoft.Extensions.AI.OpenAI](https://www.nuget.org/packages/Microsoft.Extensions.AI.OpenAI)**: Enables you to use OpenAI service types as AI abstractions provided by **Microsoft.Extensions.AI** + +1. In the `Program.cs` file of your app, create a `DefaultAzureCredential` object to discover and configure available credentials: -1. Initialize a `DefaultAzureCredential` object to assume your app's managed identity: + :::code language="csharp" source="./snippets/hosted-app-auth/program.cs" range="13-22"::: - :::code language="csharp" source="./snippets/semantic-kernel/IdentityExamples.cs" id="tokenCredential"::: +1. Create an AI service and register it with the service collection: -1. Build a `Kernel` object that includes the Azure OpenAI Chat Completion Service, and use the previously created credentials: + :::code language="csharp" source="./snippets/hosted-app-auth/program.cs" range="24-30"::: - :::code language="csharp" source="./snippets/semantic-kernel/IdentityExamples.cs" id="kernelBuild"::: +1. Inject the registered service for use in your endpoints: -1. Use the `Kernel` object to invoke prompt completion through Azure OpenAI: + :::code language="csharp" source="./snippets/hosted-app-auth/program.cs" range="41-46"::: - :::code language="csharp" source="./snippets/semantic-kernel/IdentityExamples.cs" id="invokePrompt"::: + > [!TIP] + > Learn more about ASP.NET Core dependency injection and how to register other AI services types in the Azure SDK for .NET [dependency injection](/dotnet/azure/sdk/dependency-injection) documentation. ## Related content diff --git a/docs/ai/how-to/snippets/hosted-app-auth/Program.cs b/docs/ai/how-to/snippets/hosted-app-auth/Program.cs new file mode 100644 index 0000000000000..deb2850199b8e --- /dev/null +++ b/docs/ai/how-to/snippets/hosted-app-auth/Program.cs @@ -0,0 +1,47 @@ +using Azure.AI.OpenAI; +using Azure.Identity; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.Azure; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container +// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi +builder.Services.AddOpenApi(); + +// DefaultAzureCredential attempts several auth flows in order until one is available +// For example, will discover Visual Studio or Azure CLI credentials +// in local environments and managed identity credentials in production deployments +var credential = new DefaultAzureCredential( + new DefaultAzureCredentialOptions + { + // If necessary, specify the tenant ID, + // user-assigned identity client or resource ID, or other options + } +); + +// Retrieve the Azure OpenAI endpoint and deployment name +string endpoint = builder.Configuration["AZURE_OPENAI_ENDPOINT"]; +string deployment = builder.Configuration["AZURE_OPENAI_GPT_NAME"]; + +builder.Services.AddChatClient( + new AzureOpenAIClient(new Uri(endpoint), credential) + .AsChatClient(deployment)); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.MapOpenApi(); +} + +app.UseHttpsRedirection(); + +app.MapGet("/test-prompt", async (IChatClient chatClient) => +{ + return await chatClient.CompleteAsync("Test prompt", new ChatOptions()); +}) +.WithName("Test prompt"); + +app.Run(); diff --git a/docs/ai/how-to/snippets/hosted-app-auth/Properties/launchSettings.json b/docs/ai/how-to/snippets/hosted-app-auth/Properties/launchSettings.json new file mode 100644 index 0000000000000..ca4a4a5e90fc3 --- /dev/null +++ b/docs/ai/how-to/snippets/hosted-app-auth/Properties/launchSettings.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "http://localhost:5140", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "https://localhost:7137;http://localhost:5140", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/docs/ai/how-to/snippets/hosted-app-auth/appsettings.Development.json b/docs/ai/how-to/snippets/hosted-app-auth/appsettings.Development.json new file mode 100644 index 0000000000000..1af9f1b2ba45a --- /dev/null +++ b/docs/ai/how-to/snippets/hosted-app-auth/appsettings.Development.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AZURE_OPENAI_ENDPOINT": "your-azure-openai-endpoint", + "AZURE_OPENAI_GPT_NAME": "your-azure-openai-deployment-name" +} diff --git a/docs/ai/how-to/snippets/hosted-app-auth/appsettings.json b/docs/ai/how-to/snippets/hosted-app-auth/appsettings.json new file mode 100644 index 0000000000000..10f68b8c8b4f7 --- /dev/null +++ b/docs/ai/how-to/snippets/hosted-app-auth/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/docs/ai/how-to/snippets/hosted-app-auth/hosted-app-auth.csproj b/docs/ai/how-to/snippets/hosted-app-auth/hosted-app-auth.csproj new file mode 100644 index 0000000000000..d709d70b6dbe9 --- /dev/null +++ b/docs/ai/how-to/snippets/hosted-app-auth/hosted-app-auth.csproj @@ -0,0 +1,19 @@ + + + + net9.0 + enable + enable + hosted_app_auth + + + + + + + + + + + + diff --git a/docs/ai/how-to/snippets/hosted-app-auth/hosted-app-auth.http b/docs/ai/how-to/snippets/hosted-app-auth/hosted-app-auth.http new file mode 100644 index 0000000000000..2d59beb1465a8 --- /dev/null +++ b/docs/ai/how-to/snippets/hosted-app-auth/hosted-app-auth.http @@ -0,0 +1,6 @@ +@hosted_app_auth_HostAddress = http://localhost:5140 + +GET {{hosted_app_auth_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/docs/ai/media/azure-hosted-apps/add-entra-role.png b/docs/ai/media/azure-hosted-apps/add-entra-role.png new file mode 100644 index 0000000000000..1bafa64cc1c01 Binary files /dev/null and b/docs/ai/media/azure-hosted-apps/add-entra-role.png differ diff --git a/docs/ai/media/azure-hosted-apps/system-assigned-managed-identity-in-azure-portal.png b/docs/ai/media/azure-hosted-apps/system-assigned-managed-identity-in-azure-portal.png new file mode 100644 index 0000000000000..39d40fe153df7 Binary files /dev/null and b/docs/ai/media/azure-hosted-apps/system-assigned-managed-identity-in-azure-portal.png differ diff --git a/docs/ai/media/azure-hosted-apps/user-assigned-managed-identity-in-azure-portal.png b/docs/ai/media/azure-hosted-apps/user-assigned-managed-identity-in-azure-portal.png new file mode 100644 index 0000000000000..f71cb6c1965d0 Binary files /dev/null and b/docs/ai/media/azure-hosted-apps/user-assigned-managed-identity-in-azure-portal.png differ diff --git a/docs/ai/toc.yml b/docs/ai/toc.yml index e212d2d65dfc2..5b6cd69921699 100644 --- a/docs/ai/toc.yml +++ b/docs/ai/toc.yml @@ -51,7 +51,7 @@ items: href: conceptual/understanding-openai-functions.md - name: How-to articles items: - - name: Authenticate App Service to Azure OpenAI + - name: Authenticate to Azure OpenAI from an Azure hosted app href: how-to/app-service-aoai-auth.md - name: Authenticate App Service to a vector database href: how-to/app-service-db-auth.md