Skip to content

Commit d5b8343

Browse files
authored
Use entra app id and certificate for authentication (#8262)
* Use certificate for bot authentication * Updated deployment template
1 parent 2f5685c commit d5b8343

7 files changed

Lines changed: 70 additions & 4 deletions

File tree

tools/sdk-ai-bots/AzureSdkQaBot/.editorconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,3 +338,6 @@ csharp_style_prefer_primary_constructors = true:suggestion
338338

339339
# CS8618: Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
340340
dotnet_diagnostic.CS8618.severity = none
341+
342+
# CS8604: Possible null reference argument.
343+
dotnet_diagnostic.CS8604.severity = none

tools/sdk-ai-bots/AzureSdkQaBot/AzureSdkQaBot.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
<ItemGroup>
1414
<PackageReference Include="AdaptiveCards" Version="3.0.0" />
1515
<PackageReference Include="AdaptiveCards.Templating" Version="1.4.0" />
16+
<PackageReference Include="Azure.Identity" Version="1.11.2" />
1617
<PackageReference Include="Azure.Monitor.OpenTelemetry.AspNetCore" Version="1.1.0" />
18+
<PackageReference Include="Azure.Security.KeyVault.Certificates" Version="4.6.0" />
1719
<PackageReference Include="Microsoft.Bot.Builder" Version="4.20.0" />
1820
<PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Version="4.20.0" />
1921
<PackageReference Include="Microsoft.Bot.Connector" Version="4.20.0" />

tools/sdk-ai-bots/AzureSdkQaBot/Config.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ public class ConfigOptions
55
public string? BOT_ID { get; set; }
66
public string? BOT_PASSWORD { get; set; }
77
public string? GITHUB_TOKEN { get; set; }
8+
public string? KeyVaultUrl { get; set; }
9+
public string? CertificateName { get; set; }
810
public OpenAIConfigOptions? OpenAI { get; set; }
911
public AzureConfigOptions? Azure { get; set; }
1012
public CognitiveSearchOptions? Search { get; set; }

tools/sdk-ai-bots/AzureSdkQaBot/Program.cs

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
using Microsoft.SemanticKernel.Connectors.Memory.AzureCognitiveSearch;
1313
using AzureSdkQaBot.Model;
1414
using Octokit;
15+
using Azure.Identity;
16+
using Azure.Security.KeyVault.Certificates;
1517

1618
var builder = WebApplication.CreateBuilder(args);
1719

@@ -21,9 +23,44 @@
2123

2224
// Prepare Configuration for ConfigurationBotFrameworkAuthentication
2325
var config = builder.Configuration.Get<ConfigOptions>()!;
24-
builder.Configuration["MicrosoftAppType"] = "MultiTenant";
25-
builder.Configuration["MicrosoftAppId"] = config.BOT_ID;
26-
builder.Configuration["MicrosoftAppPassword"] = config.BOT_PASSWORD;
26+
27+
28+
// Access key vault
29+
if (string.IsNullOrEmpty(config.KeyVaultUrl))
30+
{
31+
throw new Exception("KeyVaultUrl is not set in the configuration.");
32+
}
33+
34+
System.Security.Cryptography.X509Certificates.X509Certificate2? certificate = null;
35+
try
36+
{
37+
CertificateClient client = new(vaultUri: new Uri(config.KeyVaultUrl), credential: new DefaultAzureCredential());
38+
if (client == null)
39+
{
40+
throw new Exception($"Failed to create KeyVault client for {config.KeyVaultUrl}");
41+
}
42+
43+
44+
//Get certificate in X509Certificate format
45+
if (string.IsNullOrEmpty(config.CertificateName))
46+
{
47+
throw new Exception("CertificateName is not set in the configuration.");
48+
}
49+
string certificateName = config.CertificateName;
50+
certificate = client.DownloadCertificate(certificateName).Value;
51+
52+
if (certificate == null)
53+
{
54+
throw new Exception($"Certificate {certificateName} not found in KeyVault {config.KeyVaultUrl}");
55+
}
56+
}
57+
catch (Exception ex)
58+
{
59+
throw new Exception($"Failed to get certificate {config.CertificateName} from KeyVault {config.KeyVaultUrl}", ex);
60+
}
61+
62+
// Create the ClientCredentialsFactory to user certificate authentication
63+
builder.Services.AddSingleton<ServiceClientCredentialsFactory>((e) => new CertificateServiceClientCredentialsFactory(certificate, config.BOT_ID, "72f988bf-86f1-41af-91ab-2d7cd011db47"));
2764

2865
// Create the Bot Framework Authentication to be used with the Bot Adapter.
2966
builder.Services.AddSingleton<BotFrameworkAuthentication, ConfigurationBotFrameworkAuthentication>();
@@ -86,7 +123,7 @@
86123
IPlanner<AppState> planner = new AzureOpenAIPlanner<AppState>(sp.GetService<AzureOpenAIPlannerOptions>(), loggerFactory.CreateLogger<AzureOpenAIPlanner<AppState>>());
87124
//IModerator<AppState> moderator = new AzureContentSafetyModerator<AppState>(sp.GetService<AzureContentSafetyModeratorOptions>(), loggerFactory.CreateLogger<AzureContentSafetyModerator<AppState>>());
88125

89-
ApplicationOptions<AppState, AppStateManager> applicationOptions = new ApplicationOptions<AppState, AppStateManager>()
126+
ApplicationOptions<AppState, AppStateManager> applicationOptions = new()
90127
{
91128
AI = new AIOptions<AppState>(planner, promptManager)
92129
{

tools/sdk-ai-bots/AzureSdkQaBot/appsettings.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
"BOT_PASSWORD": "${botPassword}",
1111
"GITHUB_TOKEN": "",
1212
"APPLICATIONINSIGHTS_CONNECTION_STRING": "",
13+
"KeyVaultUrl": "https://kv-sdk-tools-test.vault.azure.net",
14+
"CertificateName": "AzureSDK-AI-Bot",
1315
"OpenAI": {
1416
"ApiKey": ""
1517
},

tools/sdk-ai-bots/AzureSdkQaBot/infra/azure.bicep

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ param location string = resourceGroup().location
3636

3737
param azureEmbeddingModelDeploymentName string
3838
param azureChatModelDeploymentName string
39+
param keyVaultUrl string
40+
param certificateName string
3941

4042
@secure()
4143
param searchServiceUrl string
@@ -77,6 +79,10 @@ resource webApp 'Microsoft.Web/sites@2021-02-01' = {
7779
name: 'RUNNING_ON_AZURE'
7880
value: '1'
7981
}
82+
{
83+
name: 'WEBSITE_LOAD_USER_PROFILE'
84+
value: '1'
85+
}
8086
{
8187
name: 'BOT_ID'
8288
value: botAadAppClientId
@@ -129,6 +135,14 @@ resource webApp 'Microsoft.Web/sites@2021-02-01' = {
129135
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
130136
value: appInsightConnectionString
131137
}
138+
{
139+
name: 'KeyVaultUrl'
140+
value: keyVaultUrl
141+
}
142+
{
143+
name: 'CertificateName'
144+
value: certificateName
145+
}
132146
]
133147
ftpsState: 'FtpsOnly'
134148
}

tools/sdk-ai-bots/AzureSdkQaBot/infra/azure.parameters.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@
4949
},
5050
"appInsightConnectionString": {
5151
"value": "${{SECRET_APP_INSIGHT_CONNECTION_STRING}}"
52+
},
53+
"keyVaultUrl": {
54+
"value": "${{KEYVAULT_URL}}"
55+
},
56+
"certificateName": {
57+
"value": "${{CERTIFICATE_NAME}}"
5258
}
5359
}
5460
}

0 commit comments

Comments
 (0)