Private Endpoint & Direct Line App Service Extension Configuration with Bot Services and App Service

This post has been republished via RSS; it originally appeared at: New blog articles in Microsoft Community Hub.

Private Endpoint and Direct Line App Service Extension Configuration with Azure Bot Service and Azure App Service.

We must place all the resources in the same region and under the same resource group.

Let's first create a simple Azure Bot and App Service and get the Bot working.

Please follow the steps below to create and configure Bot Service and App Service.

 

Create an App Service:

 

  • create app service.png

     Here I am creating a new resource group (directlineextension-RG) which we will use for all other resources we will create.

  • Runtime Stack: .NET 7 because I am going to use Bot sample code of .NET
  • OS - Windows
  • Region: East US
  • Keep rest of the settings default and Review + Create.

Create a Bot Service:

create bot service.png

  • Resource Group: directlineextension-RG
  • Type of App: Single Tenant (You can use Multi-Tenant or User Assigned Managed Identity)
  • Keep rest of the settings default and Review + Create.

Update the Messaging Endpoint of Bot:

Download the sample Bot code from below GitHub repository:

GitHub - microsoft/BotBuilder-Samples: Welcome to the Bot Framework samples repository. Here you will find task-focused samples in C#, JavaScript and TypeScript to help you get started with the Bot Framework SDK!

 

I am going to use Echo-Bot sample for .NET Core.

Open the code in your editor (I am using VS code) and update below 4 property values available at appsettings.json file:

 

 

 

 

 

 

 

 

 

 

 

 

{ "MicrosoftAppType": "", "MicrosoftAppId": "", "MicrosoftAppPassword": "", "MicrosoftAppTenantId": "" }

 

 

 

 

 

 

 

 

 

 

 

 

Please follow below steps to get the values for above properties:

  • Go to Bot Service -> Configuration
  • Bot Properties.png

     Copy Bot Type as value for "MicrosoftAppType"

  • Copy Microsoft App ID as value for "MicrosoftAppId"
  • Copy App Tenant ID as value for "MicrosoftAppTenantId"
  • To get the value for "MicrosoftAppPassword" (Needed only when Bot Type is either Single-Tenant or Multi-Tenant):
    • Go to Manage PasswordGenerate Secret.png
    • Generate a new secret and copy the valueAdd Secret.png

    • Save appsettings.json file and deploy the code to App Service.

Once code is deployed successfully to App Service, test the Bot using "Test in Web Chat".

Test in Web Chat.png

 

If everything is working as expected then we are good to go to next step.

 

Configure .NET bot for extension:

We will follow below article to configure .NET bot for extension:

Configure .NET bots for the Direct Line App Service extension in the Bot Framework SDK - Bot Service | Microsoft Learn

 

If your requirement is to use Nodejs bot then you must follow below document to configure Nodejs bot for extension:

Configure Node.js bots for Direct Line App Service extension in the Bot Framework SDK - Bot Service | Microsoft Learn

Prerequisites

 

  • A .NET bot deployed in Azure.
  • Bot Framework SDK for .NET, 4.14.1 or later.

We have fullfilled the prerequirsites.

 

Enable Direct Line App Service extension:

This section describes how to enable the Direct Line App Service extension using the App Service extension key from your bot's Direct Line channel configuration.

Update bot code

 

 Note

The Microsoft.Bot.Builder.StreamingExtensions NuGet preview packages have been deprecated. Starting with v4.8, the SDK contains a Microsoft.Bot.Builder.Streaming namespace. If a bot previously made use of the preview packages, they must be removed before following the steps below.

  • open your bot project.
  • Allow your app to use named pipes:
    • Open the Startup.cs file.

    • Add a reference to the Microsoft.Bot.Builder.Integration.AspNet.Core NuGet package.using Microsoft.Bot.Builder.Integration.AspNet.Core;
    •  add a call to the UseNamedPipes method as below:public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseDefaultFiles() .UseStaticFiles() .UseWebSockets() // Allow the bot to use named pipes. .UseNamedPipes(System.Environment.GetEnvironmentVariable("APPSETTING_WEBSITE_SITE_NAME") + ".directline") .UseRouting() .UseAuthorization() .UseEndpoints(endpoints => { endpoints.MapControllers(); }); // app.UseHttpsRedirection(); }
    • Save the Startup.cs file.

    • Now we need to change the hosting model from inproc to outofproc, please follow below steps:
    • Open .csproj file -> Add below line to the PropertyGroup<AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
    • As below: <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> <LangVersion>latest</LangVersion> <AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel> </PropertyGroup>
    • Save the .csproj file.
  • Deploy your updated bot to Azure.

Enable bot Direct Line App Service extension

  •  Go to your Azure Bot resource.
    • Under Settings select Channels to configure the channels your bot accepts messages from.
    • If it isn't already enabled, select the Direct Line channel from the list of Available channels to enable the channel.
    • After enabling Direct Line, select it again from the Channels page.
    • Select the App Service extension tab.
    • Under App Service Extension Keys, select the eye icon next to the corresponding key and copy.
    • Direct Line App Service Extension.png
  • Go to your App Service:
    • In the Settings section, select the Configuration menu item, add below "New application setting"

      Name Value
      DirectLineExtensionKey The value of the App Service extension key you copied earlier.
      DIRECTLINE_EXTENSION_VERSION latest
      DirectLineExtensionABSEndpoint https://<your_azure_bot>.privatelink.directline.botframework.com/v3/extension

       

    • Replace <your_azure_bot> with your Bot Service name (directlineextension in my case)
    • From within the Configuration section, select the General settings section and turn on Web sockets.

    • Enable Web Socket.png

      Select Save to save the settings. This restarts the Azure App Service. 

Confirm the Direct Line extension and the bot are configured

In your browser, go to https://<your_app_service>.azurewebsites.net/.bot. If everything is correct, the page will return the following JSON content:

 

 

 

 

 

 

 

 

 

 

{"v":"123","k":true,"ib":true,"ob":true,"initialized":true}

 

 

 

 

 

 

 

 

 

 

  • v shows the build version of the Direct Line App Service extension.
  • k indicates whether the extension was able to read an extension key from its configuration.
  • initialized indicates whether the extension was able to download bot metadata from Azure Bot Service.
  • ib indicates whether the extension was able to establish an inbound connection to the bot.
  • ob indicates whether the extension was able to establish an outbound connection from the bot.

Troubleshooting

  • If the ib and ob values displayed by the .bot endpoint are false, the bot and the Direct Line App Service extension are unable to connect to each other.

    1. Double check the code for using named pipes has been added to the bot.
    2. Confirm the bot is able to start up and run. Useful tools are Test in WebChat, connecting an additional channel, remote debugging, or logging.
    3. Restart the entire Azure App Service the bot is hosted within, to ensure a clean start up of all processes.
  • If the initialized value of the .bot endpoint is false, the Direct Line App Service extension is unable to validate the App Service extension key added to the bot's Application Settings above.

    1. Confirm the value was correctly entered.
    2. Switch to the alternate extension key shown on your bot's Configure Direct Line page.
  • Enable the bot to use the out of process hosting model; otherwise, you'll receive an HTTP Error 500.34 - ANCM Mixed Hosting error (where ANCM stands for ASP.NET Core Module). This error occurs because the bot template is using the InProcess hosting model by default. To configure out of process hosting, see Out-of-process hosting model. For more information, see Attributes of the aspNetCore element and Configuration with web.config.

  • If you attempt to use OAuth with the Direct Line App Service extension and encounter the error "Unable to get the bot AppId from the audience claim", set ClaimsIdentity to AudienceClaim on the BotFrameworkHttpAdapter. To do so, you can subclass the adapter. For example:

 

 

 

 

 

 

 

 

 

public class AdapterWithStaticClaimsIdentity : BotFrameworkHttpAdapter { public AdapterWithStaticClaimsIdentity(IConfiguration configuration, ILogger<BotFrameworkHttpAdapter> logger, ConversationState conversationState = null) : base(configuration, logger) { // Manually create the ClaimsIdentity and create a Claim with a valid AudienceClaim and the AppID for a bot using the Direct Line App Service extension. var appId = configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppIdKey)?.Value; ClaimsIdentity = new ClaimsIdentity(new List<Claim>{ new Claim(AuthenticationConstants.AudienceClaim, appId) }); } }

 

 

 

 

 

 

 

 

If everything works as expected till this point then we are good to proceed to next step.

Configure network isolation:

You can add network isolation to an existing Direct Line App Service extension bot. A private endpoint lets your network isolated bot communicate with required Bot Framework services so that the bot can run correctly while being limited to the virtual network.

 

To add network isolation to your bot:

  • Use a virtual network and configure the network to prevent outbound traffic. At this point, your bot will lose the ability to communicate with other Bot Framework services.
  • Configure private endpoints to restore connectivity.
  • Restart you app service and test your bot within your isolated network.
  • Disable public network access to your bot.

Prerequisites

  • A working Direct Line App Service extension bot.
    • Your bot uses the Bot Framework SDK for C# or JavaScript, version 4.16 or later.
    • Your bot has named pipes enabled.
    • Your bot's app service has the Direct Line App Service extension enabled.
  • A Web Chat control connected to your bot's Direct Line client.

To confirm that your existing bot is configured correctly:

  • In a browser, open the Direct Line client endpoint for your bot. For example, https://<your-app_service>.azurewebsites.net/.bot
  • Verify the page displays the following{"v":"123","k":true,"ib":true,"ob":true,"initialized":true}

     

  • v shows the build version of the Direct Line App Service extension.
  • k indicates whether the extension was able to read an extension key from its configuration.
  • initialized indicates whether the extension was able to download bot metadata from Azure Bot Service.
  • ib indicates whether the extension was able to establish an inbound connection to the bot.
  • ob indicates whether the extension was able to establish an outbound connection from the bot.

Create a virtual network

  • Create an Azure Virtual Network resource:Create Virtual Network.png
  •  Resource Group: directlineextension-RG

  • Region: East-US
  • Create 3 subnets (usually 2 is needed but we will create an VM to test the bot, for that we need another subnet):Create subnets.png
  • Open the app service resource for your bot and enable virtual network integration.

  •  Use the virtual network and subnet from the previous step.

    vnet config app service -1.png

    vnet config app service -2.png

 

 

 

Deny outbound traffic from your network

  • Open the network security group associated with your first subnet.
  • Under Settings, select Outbound security rules.
    • In the outbound security rules list, enable DenyAllInternetOutbound.Add Outboud rule.png

       

  • Configure this new NSG to the subnet (subnet-appservice)Configure NSG to subnet.png

     

  • Go to the app service resource for your bot.
  • Restart your app service.

Verify that connectivity is broken

  • In a separate browser tab, open the Direct Line client endpoint for your bot. For example, https://<your-app_service>.azurewebsites.net/.bot.

  • Verify the page displays the following:{"v":"123","k":true,"ib":true,"ob":true,"initialized":false}

     

The value of initialized should be false, because your app service and app service extension are unable to connect to other Bot Framework services to initialize itself. Your bot is now isolated in a virtual network for outbound connections.

 

Create your private endpoint

  • Go to your Azure Bot resource 
  • Under Settings, select Networking.
    • On the Private access tab and select Create a private endpoint.
      • On the Resource tab, for Target sub-resource, select Bot from the list.
      • On the Virtual Network tab, select your virtual network and the second subnet you created.
      • Save your private endpoint.Private endpoint bot 1.png

         

        Private endpoint bot 2.png

         

        Private endpoint bot 3.png

         

        Private endpoint bot 4.png
      •  Keep the rest settings default and Review + Create.

        Private endpoint bot 5.png

         

Add your private endpoint to your bot's app service

  • Go to your App Service
  • Settings -> Configuration
  • On the Application settings tab, select New application setting.
    • Set Name to DirectLineExtensionABSEndpoint.
    • Set Value to the private endpoint URL, for example, https://<your_azure_bot>.privatelink.directline.botframework.com/v3/extension.
    • Replace <your_azure_bot> with your Bot Name.
    • Save the new setting.
  • Settings -> Networking -> Private Endpoint -> Add -> Create Private endpoint and select any subnet from the configured vnet.App Service Private Endpoint 1.png

     

    App Service Private Endpoint 2.png

     

    App Service Private Endpoint 3.png

     

Restart your app service and verify that connectivity is restored

  • Restart the app service for your bot.

  • In a separate browser tab, open the Direct Line client endpoint for your bot. For example, https://<your-app_service>.azurewebsites.net/.bot
  • Verify the page displays the following:{"v":"123","k":true,"ib":true,"ob":true,"initialized":true}​

     

The value of initialized should be true.

If your private endpoint doesn't work correctly, you can add a rule to allow outbound traffic to NSG configured with the App Service subnet (subnet-appservice) specifically to Azure Bot Service.

 

 

 

 

This will make you virtual network a little less isolated.

 

 

 

 

 

  • Open the network security group associated with your first subnet.
  • Under Settings, select Outbound security rules.
    • In the outbound security rules list, enable AllowAzureBotService.
  • Go to the app service resource for your bot.
  • Restart your app service.
  • In a separate browser tab, open the Direct Line client endpoint for your bot again. For example, https://<your-app_service>.azurewebsites.net/.bot.

  • Verify the page displays the following:{"v":"123","k":true,"ib":true,"ob":true,"initialized":true}​

 

Disable public network access to your bot

  • Go to App Service -> Settings -> Networking -> Access restriction -> Uncheck Allow public access checkbox and Save.Disable public access 1.png

     

If you try to browse the App Service URL and the Pipe URL, you would not get any response. 

 

Now, lets create a client to test the Bot. We will use below article to get the required HTML and replace the required values:

Use Web Chat with the Direct Line App Service extension in Bot Framework SDK - Bot Service | Microsoft Learn

 

Copy the provided HTML:

<!DOCTYPE html>
<html lang="en-US">
<head>
<title>Web Chat</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script
crossorigin="anonymous"
src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"
></script>
<style>
html,
body {
background-color: #f7f7f7;
height: 100%;
}

body {
margin: 0;
}

#webchat {
box-shadow: 0 0 10px rgba(0, 0, 0, 0.05);
height: 100%;
margin: auto;
max-width: 480px;
min-width: 360px;
}
</style>
</head>
<body>
<div id="webchat" role="main"></div>
<script>
(async function() {
<!-- NOTE: You should replace the below fetch with a call to your own token service as described in step 2 above, to avoid exposing your channel secret in client side code. -->
const res = await fetch('https://<your_app_service>.azurewebsites.net/.bot/v3/directline/tokens/generate',
{
"method": "POST",
"headers": {
"Authorization": "Bearer " + "<Your Bot's Direct Line channel secret>"
},
"body": "{'user': {'id': 'my_test_id', 'name': 'my_test_name'}}"
}
);
const { token } = await res.json();

window.WebChat.renderWebChat(
{
directLine: await window.WebChat.createDirectLineAppServiceExtension({
domain: 'https://<your_app_service>.azurewebsites.net/.bot/v3/directline',
token
})
},
document.getElementById('webchat')
);

document.querySelector('#webchat > *').focus();
})().catch(err => console.error(err));
</script>
</body>
</html>

 

Replace <your_app_service> with your App Service name in 2 places hightlighed in the HTML above.

Replace <Your Bot's Direct Line channel secret> with the Direct line channel secret:

Direct line client secret.png

 

Now run the client in the machine, which is part of the same vnet, configured here as part of the private endpoint. 

 

For testing purpose, we will create a Virtual Machine and configure this VM to be part of same vnet which is configured with App Service and Bot Service.

 

Create a VM:

Create VM1.png

  • Resource group: directlineextention-RG (same as Bot and App Service).
  • Region: East US (same as Bot and App Service).
  •  
  • Create VM2.png

     In the networking section, configure the same vnet and subnet (subnet-vm) we have created earlier for VM.

  • Keep rest of the settings as default and Review + Create.

Once VM is created successfully, login to VM and take the client HTML created earlier and run inside the VM.

It must work without any issue and you must see the expected response from the Bot.

Bot response in VM.png

 

You must be albe to use pipe URL too, inside the VM:

Pipe response in VM.png

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.