├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── SECURITY.md ├── azuredeploy.json ├── azuredeploy.parameters.json ├── cert-deploy.json ├── cert-deploy.parameters.json ├── cert-update.json └── images ├── A-01.jpg ├── A-02.jpg ├── A-03.jpg ├── A-04.jpg ├── A-05.jpg ├── A-06.jpg ├── A-07.jpg └── DeployArch-v10.jpg /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deploy Reference Architecture for Microsoft Healthcare Bot and QnA Maker 2 | 3 | 10 | 11 | This GitHub repo. contains the ARM template for deploying Health Bot reference architecture. 12 | 13 | ## Contents 14 | 15 | | File/Folder | Description | 16 | |-------------------|--------------------------------------------| 17 | | `ARM Template` | `azuredeploy.json` and `cert-deploy.json` provision the Azure resources in the reference architecture.| 18 | | `CHANGELOG.md` | List of changes to the template.| 19 | | `CONTRIBUTING.md` | Guidelines for contributing to the template.| 20 | | `README.md` | This README file.| 21 | | `LICENSE` | The license for the template.| 22 | 23 | ## Prerequisites 24 | 25 | 1. A **GitHub** Account to clone and/or fork this repository. 26 | 27 | 2. An Azure **Resource Group** with **Owner** *Role* permission. All Azure resources will be deployed into this resource group. 28 | 29 | 3. A **Health Bot** instance. Refer to [Create your first Healthcare Bot](https://docs.microsoft.com/en-us/healthbot/quickstart-createyourhealthcarebot) quickstart in the Health Bot documentation. 30 | 31 | 3. Review the **ARM template** `azuredeploy.json` before proceeding. Update the resource configuration parameters to meet your requirements. 32 | 33 | 4. (Optional) The following CLI tools are preinstalled in Azure Cloud Shell. In case you are planning to use a workstation or a VM to deploy the ARM template, install the CLI tools before proceeding. Links for downloading the tools are provided in the next section. 34 | 35 | - Azure CLI 36 | - GitHub CLI 37 | 38 | ## Reference Architecture 39 | 40 | The aim of this reference architecture is multifold. 41 | 42 | - Help customers quickly deploy Microsoft **Health Bot** and **Cognitive Services** resources in **Production** region on Azure. 43 | 44 | - Describe the integration touch points between the Health Bot, Azure Cognitive Services and Web Chat Client application. Azure Cognitive Services includes Congitive Search, QnA Maker and other AI services. 45 | 46 | - Guide customers to provision the Microsoft Health Bot resources in a highly available fault tolerant configuration. Core services of the solution such as the Web Chat Client, QnA Maker runtime and Azure Cognitive Search are deployed in two separate Azure regions to provide for automatic failover. 47 | 48 | ![alt tag](./images/DeployArch-v10.jpg) 49 | 50 | Readers are advised to refer to the following resources as needed. 51 | 52 | - [Azure CLI 2.2+](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest) 53 | - [Git SCM Docs](https://git-scm.com/book/en/v2) 54 | - [Azure Resource Manager Documentation](https://docs.microsoft.com/en-us/azure/azure-resource-manager/) 55 | - [Azure Resource Manager Template Reference](https://docs.microsoft.com/en-us/azure/templates/) 56 | - [Microsoft Health Bot Documentation](https://docs.microsoft.com/en-us/healthbot/) 57 | - [Web Chat Client GitHub Repository](https://github.com/ganrad/HealthBotContainerSample) 58 | - [Azure Cognitive Services Documentation](https://docs.microsoft.com/en-us/azure/cognitive-services/) 59 | - [Azure QnA Maker Documentation](https://docs.microsoft.com/en-us/azure/cognitive-services/qnamaker/) 60 | - [Business Continuity Plan for QnA Maker Service](https://docs.microsoft.com/en-us/azure/cognitive-services/qnamaker/how-to/business-continuity-plan) 61 | - [Azure Cognitive Search Documentation](https://docs.microsoft.com/en-us/azure/search/) 62 | - [Synchronize Azure Search Indexes](https://github.com/ganrad/AzSearchSyncIndexes) 63 | - [Azure Function Documentation](https://docs.microsoft.com/en-us/azure/azure-functions/) 64 | 65 | ## Important Notes 66 | 67 | - Unless otherwise noted explicitly, the first **region** listed in the **locations** parameter (array) will represent the **primary** region and the second will denote the **secondary** region. 68 | - The ARM template parameter **name** has to be unique for each Health Bot deployment. Use an alpha numberic value for this name parameter. All Azure resources deployed by the ARM template will have names prefixed with this deployment name. 69 | - Azure Traffic Manager is used to shift the **Web Chat Client** and **QnA Maker** API traffic across the individual Azure App Service instances deployed in the two regions. The end user (customer) is responsible for configuring the respective traffic routing algorithm in the Traffic Manager to ensure the traffic is split evenly between the App Service instances as per their requirements. 70 | 71 | ## A] Deploy ARM Template to provision Health Bot resources 72 | 73 | Follow the steps below to deploy the Health Bot resources on Azure. 74 | 75 | 1. Review and update template parameters in the `azuredeploy.parameters.json` file 76 | 77 | Refer to the table below for a description of the template parameters. Configure the values as per your requirements. 78 | 79 | Parameter Name | Type | Description 80 | -------------- | ---- | ----------- 81 | name | string | A **unique name** for this deployment. All provisioned resource names will be prefixed with this name. This includes the web site and traffic manager FQDN's. 82 | locations | array (of strings) | Specify Azure region names (max. 2) where the resources need to be provisioned. The resources can be provisioned in a max. of 2 regions. 83 | WEBCHAT_SECRET | string | Health Bot instance **webchat_secret**. Retrieve this secret value from the Health Bot Portal. Refer to the Health Bot documentation [here](https://docs.microsoft.com/en-us/healthbot/channels/webchat). 84 | APP_SECRET | string | Health Bot instance **app_secret**. Obtain this secret value from the Health Bot Portal. 85 | appServicePlanSku | object | Use this object to specify the SKU size for the Azure App Service Plans. 86 | workerSize | string | Specify the number of workers in the Azure App Service Plan. 87 | qnaMakerServiceLocation | string | QnA Maker resource location. This should be set to **westus** for all commercial deployments. 88 | qnaMakerServiceSku | string | Specify the SKU size for the Cognitive Services account. 89 | qnaMakerSearchSku | string | Specify the SKU size for the Cognitive Search instances. 90 | webchatRepoUrl | string | Web Chat Client GitHub repository uri. Use the default value as-is. 91 | webchatRepoBranch | string | Web Chat Client GitHub repository branch. Use the default value (`master`). If Web Chat Client **v3** is desired, then set the value to **webchat_v3**. 92 | funcRepoUrl | string | GitHub repository uri for Azure Functions. The functions synchronize the knowledge bases (indexs) between the Azure Search instances deployed in two different regions. 93 | funcRepoBranch | string | GitHub repository branch for Azure Functions. Use the default value (`master`). 94 | 95 | 2. Login to Azure 96 | 97 | Open a terminal window or login to the Azure [Cloud Shell](http://shell.azure.com). 98 | 99 | Refer to the commands below to login to Azure from a command prompt in a VM. You can skip this step if you are using the Azure Cloud shell. 100 | 101 | ```bash 102 | # Login to Azure 103 | $ az login 104 | # 105 | ``` 106 | 107 | 3. Clone this repository 108 | 109 | Clone this GitHub repository to your local VM or cloud shell. Refer to the command snippet below. 110 | 111 | ```bash 112 | # Create a directory to store all Git projects 113 | $ mkdir git-repos 114 | # 115 | # Switch to the 'git-repos' directory 116 | $ cd git-repos 117 | # 118 | # Clone this GitHub repository. 119 | $ git clone https://github.com/microsoft/HealthBotRefArchDeploy.git 120 | # 121 | # Switch to the Health Bot project root directory 122 | $ cd HealthBotRefArchDeploy 123 | # 124 | ``` 125 | 126 | 4. Validate the ARM template 127 | 128 | Follow the steps in the command snippet below to validate the ARM template. 129 | 130 | ```bash 131 | # (Optional) Create a resource group 132 | # Substitute correct values for the following 133 | # - group-name: Name of the resource group 134 | # - region-name: Azure region for the resource group 135 | # 136 | $ az group create -n -l 137 | # 138 | # Validate the ARM template. Make sure there are no errors. 139 | # 140 | $ az deployment group validate --verbose --resource-group --template-file azuredeploy.json --parameters @./azuredeploy.parameters.json 141 | # 142 | ``` 143 | 144 | 5. Run the ARM deployment 145 | 146 | Follow the steps in the command snippet below to run the ARM template and provision the Health Bot resources on Azure. 147 | 148 | ```bash 149 | # Deploy resources defined in the ARM template 150 | # Substitute correct values for the following 151 | # - group-name: Name of the resource group 152 | # 153 | $ az deployment group create --verbose --resource-group --template-file azuredeploy.json --parameters @./azuredeploy.parameters.json 154 | # 155 | ``` 156 | >**NOTE:** The ARM template will run for approximately 15 - 20 minutes. Be patient and treat yourself to a cookie. 157 | 158 | 6. Verify Azure Resources 159 | 160 | Login to the Azure portal. Confirm all resources were provisioned in the resource group correctly. 161 | 162 | ## B] Deploy ARM Template to configure TLS/SSL certificates for Azure App Services 163 | 164 | >**NOTE:** For configuring a custom domain and TLS certificates, skip the steps below and refer to the section at the end of this section (links to App Service documentation). 165 | 166 | Follow the steps below to configure **App Service Managed Certificate** for the *Web Chat Client* and *QnA Maker* App Services. 167 | 168 | 1. Review and update template parameters in the `cert-deploy.parameters.json` file 169 | 170 | Refer to the table below for a description of the template parameters. Configure the values as per your requirements. 171 | 172 | Parameter Name | Type | Description 173 | -------------- | ---- | ----------- 174 | name | string | A **unique name** for this deployment. All provisioned resource names will be prefixed with this name. Specify the same deployment **name** as in Section **A**. 175 | locations | array (of strings) | Specify Azure region names (max. 2) where the resources need to be provisioned. The resources can be provisioned in a max. of 2 regions. Specify the same locations which were specified in Section **A**. 176 | tmDomainSuffix | string | The default DNS suffix for Azure Traffic Manager is **.trafficmanager.net**. 177 | 178 | 2. Validate the ARM template 179 | 180 | After making the required changes to the template parameters file, follow the steps in the command snippet below to validate the ARM template. 181 | 182 | ```bash 183 | # Validate the ARM template. Make sure there are no errors. 184 | # Substitute correct values for 185 | # - group-name: Name of the Azure Resource Group 186 | # 187 | $ az deployment group validate --verbose --resource-group --template-file cert-deploy.json --parameters @./cert-deploy.parameters.json 188 | # 189 | ``` 190 | 191 | 3. Run the ARM deployment 192 | 193 | Refer to the command snippet below to run the ARM template. 194 | 195 | ```bash 196 | # Deploy resources defined in the ARM template 197 | # Substitute correct values for the following 198 | # - group-name: Name of the resource group 199 | # 200 | $ az deployment group create --verbose --resource-group --template-file cert-deploy.json --parameters @./cert-deploy.parameters.json 201 | # 202 | ``` 203 | 204 | 4. Verify TLS/SSL and Custom domain configurations for App Services 205 | 206 | Login to the Azure Portal. Go to the *App Service* and click on **Custom domains** and **TLS/SSL settings** blades. Verify the custom domain, TLS/SSL certificate and bindings have been configured properly. 207 | 208 | For configuring custom domains and TLS certificates with the App Services, refer to the articles below. 209 | 210 | - [Add an SSL certificate in Azure App Service](https://docs.microsoft.com/en-us/azure/app-service/configure-ssl-certificate) 211 | - [Secure a custom DNS name with SSL binding in Azure App Service](https://docs.microsoft.com/en-us/azure/app-service/configure-ssl-bindings) 212 | 213 | ## C] Post-deployment Configuration 214 | 215 | The following steps have to be completed manually once the ARM template is deployed and all required resources have been provisioned on Azure. 216 | 217 | 1. Generate the QnA Maker **Knowledge Base** for **COVID-19 FAQs** in the **Health Bot Service** Portal 218 | 219 | Login to *Azure Portal* and retrieve the QnA Maker **Subscription Key** by accessing the *Cognitive Service*. The Cognitive Service resource should have a name that ends with **-qna**. See screenshot below. 220 | 221 | ![alt tag](./images/A-01.jpg) 222 | 223 | Login to *Health Bot Service Portal*, access the **Scenario Template Catalog** and create a QnA Model using **COVID-19 FAQs** template. See screenshots below. 224 | 225 | ![alt tag](./images/A-02.jpg) 226 | 227 | Specify the QnA Maker Subscription Key which you retrieved in the previous step. Then click on **Import template**. 228 | 229 | ![alt tag](./images/A-03.jpg) 230 | 231 | Exit out of the *Scenario Editor*. The previous step creates the following resources which can be viewed by accessing the respective portals. See below. 232 | 233 | **Health Bot Service Portal** 234 | - **Scenario** : COVID-19 FAQs 235 | 236 | ![alt tag](./images/A-04.jpg) 237 | 238 | - **Model** : COVID-19 FAQs 239 | 240 | ![alt tag](./images/A-05.jpg) 241 | 242 | **Azure Portal** 243 | - **Cognitive Search** : Name ends with **-search0**. Verify search **indexes** has been created. 244 | 245 | ![alt tag](./images/A-06.jpg) 246 | 247 | **QnA Maker Portal** 248 | - **Knowledge Base** : Healthcare Bot COVID-19 CDC 249 | 250 | ![alt tag](./images/A-07.jpg) 251 | 252 | Review the above resources. 253 | 254 | 2. Back up the QnA Maker runtime in **primary** region and restore it in the **secondary** region 255 | 256 | The ARM template deploys one **Cognitive Services** resource and two QnA Maker **App Service** instances, one in each region. The template deploys the **QnA Maker** runtime only in the App Service instance deployed in the primary region. As a consequence, the QnA Maker runtime has to be deployed in the secondary region. The quickest and easiest way is to take a back up of the QnA Maker App Service instance in the primary region and restore it in the secondary region. 257 | 258 | Refer to [Back up an app](https://docs.microsoft.com/en-us/azure/app-service/manage-backup) to take a back up of the QnA Maker App Service in the **primary** region. The QnA Maker App Service in the primary region would have a name ending with **-qnahost0**. 259 | 260 | Refer to [Restore a backup](https://docs.microsoft.com/en-us/azure/app-service/web-sites-restore) to restore the back up from primary into the secondary region. The QnA Maker App Service in the secondary region would have a name ending with **-qnahost1**. 261 | 262 | 3. Reconfigure the QnA Maker runtime in **secondary** region 263 | 264 | Update QnA Maker App Service application settings in **secondary** region. 265 | 266 | 267 | In Azure Portal, access the QnA Maker App Service instance in **secondary** region. The name for this resource should end with **-qnahost1**. Access the **Configuration** blade of the App Service and update application settings values listed in the table below. 268 | 269 | Parameter Name | Description 270 | -------------- | ----------- 271 | AzureSearchName | Specify the name of the Cognitive Search resource. Name of this resource should end with **-search1**. 272 | AzureSearchAdminKey | Specify the value of Cognitive Search Admin key (Primary admin key). You can retrieve this key by accessing the **Keys** blade of the Cognitive Search instance. 273 | UserAppInsightsAppId | Application Insights App ID 274 | UserAppInsightsKey | Application Insights Instrumentation Key 275 | UserAppInsightsName | Application Insights resource name 276 | 277 | >**NOTE:** Remember to specify the names of the resources and application insights keys deployed in the **secondary** region. 278 | 279 | Click **Save** and this will restart the QnA Maker App Service in the **secondary** region. 280 | 281 | 4. Synchronize the Azure Search **Indexes** in the **primary** and **secondary** regions 282 | 283 | Finally, invoke the *Azure Function* to copy the search **indexes** from the Cognitive Search instance in primary to secondary. 284 | 285 | The Azure Function name ends with **-qnakb-sync** and is deployed in **primary** region. This Function is configured with both an **HTTP** and **Timer** trigger. 286 | 287 | To initiate the synchronization process manually, issue a HTTP `GET` API call to the Function's HTTP endpoint (below) from a web browser or a terminal window (using `curl` command). 288 | 289 | http://[**name**]-qnakb-sync.azurewebsites.net/api/httpcogsearchkbsync 290 | 291 | Substitute the deployment **name** in the `name` placeholder above. 292 | 293 | >**NOTE:** The source code for the Azure Search [synchronization function](https://github.com/ganrad/AzSearchSyncIndexes) is available on GitHub. The synchronization code can also be run as a standalone program. The source code for the [standalone](https://github.com/pchoudhari/QnAMakerBackupRestore) program is also available on GitHub. 294 | 295 | ## Contributing 296 | 297 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 298 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 299 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 300 | 301 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 302 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 303 | provided by the bot. You will only need to do this once across all repos using our CLA. 304 | 305 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 306 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 307 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 308 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | -------------------------------------------------------------------------------- /azuredeploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json", 3 | "contentVersion": "1.0.0.0", 4 | "metadata" : { 5 | "comments": "This ARM template deploys Azure resources included in the Health Bot Reference Architecture", 6 | "author": "Microsoft Healthcare CSU" 7 | }, 8 | "parameters": { 9 | "name": { 10 | "type": "string", 11 | "metadata":{ 12 | "description":"Base name for all services." 13 | } 14 | }, 15 | "locations": { 16 | "type": "array", 17 | "defaultValue": [ 18 | "westus", 19 | "eastus" 20 | ], 21 | "minLength": 2, 22 | "maxLength": 2, 23 | "metadata":{ 24 | "description":"Array of Azure regions to deploy resources to." 25 | } 26 | }, 27 | "APP_SECRET": { 28 | "type": "string", 29 | "metadata":{ 30 | "description":"App Secret from Health Bot Portal." 31 | } 32 | }, 33 | "WEBCHAT_SECRET": { 34 | "type": "string", 35 | "metadata":{ 36 | "description":"Web Chat Secret from Health Bot Portal." 37 | } 38 | }, 39 | "appServicePlanSku": { 40 | "type": "object", 41 | "defaultValue": { 42 | "tier": "Standard", 43 | "name": "S1" 44 | }, 45 | "metadata":{ 46 | "description":"App service plan SKU." 47 | } 48 | }, 49 | "workerSize": { 50 | "type": "string", 51 | "allowedValues": [ 52 | "0", 53 | "1", 54 | "2" 55 | ], 56 | "defaultValue": "1", 57 | "metadata": { 58 | "description": "The instance size of the hosting plan (small, medium, or large)." 59 | } 60 | }, 61 | "qnaMakerServiceLocation": { 62 | "type": "string", 63 | "defaultValue": "westus", 64 | "metadata":{ 65 | "description":"QnA Maker subscription resource location (should be westus for all commercial deployments)." 66 | } 67 | }, 68 | "qnaMakerServiceSku": { 69 | "type": "string", 70 | "defaultValue": "S0", 71 | "metadata":{ 72 | "description":"QnA Maker subscription resource SKU." 73 | } 74 | }, 75 | "qnaMakerSearchSku": { 76 | "type": "string", 77 | "defaultValue": "standard", 78 | "metadata":{ 79 | "description":"QnA Maker Azure Search SKU." 80 | } 81 | }, 82 | "webchatRepoUrl": { 83 | "type": "string", 84 | "defaultValue": "https://github.com/microsoft/HealthBotContainerSample", 85 | "metadata":{ 86 | "description":"Healthcare Bot Web Chat client GitHub repo. URL" 87 | } 88 | }, 89 | "webchatRepoBranch": { 90 | "type": "string", 91 | "defaultValue": "master", 92 | "metadata":{ 93 | "description":"Healthcare Bot Web Chat client GitHub repo. branch" 94 | } 95 | }, 96 | "funcRepoUrl": { 97 | "type": "string", 98 | "defaultValue": "https://github.com/ganrad/AzSearchSyncIndexes.git", 99 | "metadata":{ 100 | "description":"Azure Search KB synchronization function GitHub repo. URL" 101 | } 102 | }, 103 | "funcRepoBranch": { 104 | "type": "string", 105 | "defaultValue": "master", 106 | "metadata":{ 107 | "description":"Azure Search KB synchronization function GitHub repo. branch" 108 | } 109 | }, 110 | "tmDomainSuffix": { 111 | "type": "string", 112 | "defaultValue": ".trafficmanager.net", 113 | "metadata":{ 114 | "description":"Azure Traffic Manager DNS suffix" 115 | } 116 | }, 117 | "templateUrl": { 118 | "type": "string", 119 | "defaultValue": "https://grstore.blob.core.windows.net/armtemplates/cert-update.json", 120 | "metadata":{ 121 | "description":"Azure Storage URL used to download linked ARM templates" 122 | } 123 | } 124 | }, 125 | "variables": { 126 | "appServicePlanName": "[concat(parameters('name'), '-appServicePlan')]", 127 | "appInsightsName": "[concat(parameters('name'), '-insights')]", 128 | "webAppClientName": "[concat(parameters('name'), '-webClient')]", 129 | "qnaMakerServiceName": "[concat(parameters('name'), '-qna')]", 130 | "trafficManagerDnsName": "[concat(parameters('name'), '-webclient')]", 131 | "customDomainWebAppSvc": "[concat(parameters('name'), '-webclient', parameters('tmDomainSuffix'))]", 132 | "qnaTrafficManagerDnsName": "[concat(parameters('name'), '-qna')]", 133 | "customDomainQnaAppSvc": "[concat(parameters('name'), '-qna', parameters('tmDomainSuffix'))]", 134 | "functionAppName": "[concat(parameters('name'), '-qnakb-sync')]", 135 | "qnaMakerSearchName": "[toLower(replace(concat(parameters('name'), '-search'), '_', ''))]", 136 | "qnaMakerWebAppName": "[replace(concat(parameters('name'), '-qnahost'), '_', '')]", 137 | "storageAccountName": "[toLower(take(replace(replace(concat(parameters('name'), 'storage'), '-', ''), '_', ''), 24))]", 138 | "storageAccountId": "[concat(resourceGroup().id, '/providers/','Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]" 139 | }, 140 | "resources": [ 141 | { 142 | "comments": "App service plan", 143 | "type": "Microsoft.Web/serverFarms", 144 | "apiVersion": "2018-11-01", 145 | "name": "[concat(variables('appServicePlanName'), copyIndex())]", 146 | "location": "[parameters('locations')[copyIndex()]]", 147 | "sku": "[parameters('appServicePlanSku')]", 148 | "properties": { 149 | "workerSize": "[parameters('workerSize')]", 150 | "numberOfWorkers": 1 151 | }, 152 | "copy": { 153 | "name": "locationLoop", 154 | "count": "[length(parameters('locations'))]" 155 | } 156 | }, 157 | { 158 | "comments": "Application Insights", 159 | "type": "Microsoft.Insights/components", 160 | "kind": "web", 161 | "apiVersion": "2015-05-01", 162 | "name": "[concat(variables('appInsightsName'), copyIndex())]", 163 | "location": "[parameters('locations')[copyIndex()]]", 164 | "properties": { 165 | "Application_Type": "web" 166 | }, 167 | "copy": { 168 | "name": "locationLoop", 169 | "count": "[length(parameters('locations'))]" 170 | } 171 | }, 172 | { 173 | "comments": "Web app client", 174 | "type": "Microsoft.Web/sites", 175 | "apiVersion": "2018-02-01", 176 | "name": "[concat(variables('webAppClientName'), copyIndex())]", 177 | "location": "[parameters('locations')[copyIndex()]]", 178 | "properties": { 179 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', concat(variables('appServicePlanName'), copyIndex()))]", 180 | "siteConfig": { 181 | "appSettings": [ 182 | { 183 | "name": "APP_SECRET", 184 | "value": "[parameters('APP_SECRET')]" 185 | }, 186 | { 187 | "name": "WEBCHAT_SECRET", 188 | "value": "[parameters('WEBCHAT_SECRET')]" 189 | }, 190 | { 191 | "name": "WEBSITE_NODE_DEFAULT_VERSION", 192 | "value": "6.9.1" 193 | }, 194 | { 195 | "name": "UserAppInsightsKey", 196 | "value": "[reference(resourceId('Microsoft.Insights/components/', concat(variables('appInsightsName'), copyIndex())), '2015-05-01').InstrumentationKey]" 197 | }, 198 | { 199 | "name": "UserAppInsightsName", 200 | "value": "[concat(variables('appInsightsName'), copyIndex())]" 201 | }, 202 | { "name": "UserAppInsightsAppId", 203 | "value": "[reference(resourceId('Microsoft.Insights/components/', concat(variables('appInsightsName'), copyIndex())), '2015-05-01').AppId]" 204 | } 205 | ] 206 | }, 207 | "httpsOnly": "true" 208 | }, 209 | "resources": [ 210 | { 211 | "type": "sourcecontrols", 212 | "apiVersion": "2018-02-01", 213 | "name": "web", 214 | "location": "[parameters('locations')[copyIndex()]]", 215 | "dependsOn": [ 216 | "[resourceId('Microsoft.Web/sites', concat(variables('webAppClientName'), copyIndex()))]" 217 | ], 218 | "properties": { 219 | "repoUrl": "[parameters('webchatRepoUrl')]", 220 | "branch": "[parameters('webchatRepoBranch')]", 221 | "isManualIntegration": true 222 | } 223 | } 224 | ], 225 | "dependsOn": [ 226 | "[resourceId('Microsoft.Web/serverfarms', concat(variables('appServicePlanName'), copyIndex()))]" 227 | ], 228 | "copy": { 229 | "name": "locationLoop", 230 | "count": "[length(parameters('locations'))]" 231 | } 232 | }, 233 | { 234 | "comments": "Cognitive service key for all QnA Maker knowledgebases.", 235 | "type": "Microsoft.CognitiveServices/accounts", 236 | "kind": "QnAMaker", 237 | "apiVersion": "2017-04-18", 238 | "name": "[variables('qnaMakerServiceName')]", 239 | "location": "[parameters('qnaMakerServiceLocation')]", 240 | "sku": { 241 | "name": "[parameters('qnaMakerServiceSku')]" 242 | }, 243 | "properties": { 244 | "apiProperties": { 245 | "qnaRuntimeEndpoint": "[concat('https://', reference(resourceId('Microsoft.Web/sites', concat(variables('qnaMakerWebAppName'), '0'))).hostNames[0])]" 246 | } 247 | }, 248 | "dependsOn": [ 249 | "[resourceId('Microsoft.Web/Sites', concat(variables('qnaMakerWebAppName'), '0'))]", 250 | "[resourceId('Microsoft.Search/searchServices/', concat(variables('qnaMakerSearchName'), '0'))]", 251 | "[resourceId('microsoft.insights/components/', concat(variables('appInsightsName'), '0'))]" 252 | ] 253 | }, 254 | { 255 | "comments": "Search service for QnA Maker service.", 256 | "type": "Microsoft.Search/searchServices", 257 | "apiVersion": "2015-08-19", 258 | "name": "[concat(variables('qnaMakerSearchName'), copyIndex())]", 259 | "location": "[parameters('locations')[copyIndex()]]", 260 | "sku": { 261 | "name": "[parameters('qnaMakerSearchSku')]" 262 | }, 263 | "properties": { 264 | "replicaCount": 3, 265 | "partitionCount": 1, 266 | "hostingMode": "default" 267 | }, 268 | "copy": { 269 | "name": "locationLoop", 270 | "count": "[length(parameters('locations'))]" 271 | } 272 | }, 273 | { 274 | "comments": "Web app for QnA Maker service.", 275 | "type": "Microsoft.Web/sites", 276 | "apiVersion": "2016-08-01", 277 | "name": "[concat(variables('qnaMakerWebAppName'), copyIndex())]", 278 | "location": "[parameters('locations')[copyIndex()]]", 279 | "properties": { 280 | "enabled": true, 281 | "name": "[concat(variables('qnaMakerWebAppName'), copyIndex())]", 282 | "hostingEnvironment": "", 283 | "serverFarmId": "[concat('/subscriptions/', Subscription().SubscriptionId,'/resourcegroups/', resourceGroup().name, '/providers/Microsoft.Web/serverfarms/', concat(variables('appServicePlanName'), copyIndex()))]", 284 | "siteConfig": { 285 | "cors": { 286 | "allowedOrigins": [ 287 | "*" 288 | ] 289 | } 290 | }, 291 | "httpsOnly": "true" 292 | }, 293 | "dependsOn": [ 294 | "[concat('Microsoft.Web/serverfarms/', concat(variables('appServicePlanName'), copyIndex()))]" 295 | ], 296 | "resources": [ 297 | { 298 | "apiVersion": "2016-08-01", 299 | "name": "appsettings", 300 | "type": "config", 301 | "dependsOn": [ 302 | "[resourceId('Microsoft.Web/Sites', concat(variables('qnaMakerWebAppName'), copyIndex()))]", 303 | "[resourceId('Microsoft.Insights/components', concat(variables('appInsightsName'), copyIndex()))]", 304 | "[resourceId('Microsoft.Search/searchServices/', concat(variables('qnaMakerSearchName'), copyIndex()))]" 305 | ], 306 | "properties": { 307 | "AzureSearchName": "[concat(variables('qnaMakerSearchName'), copyIndex())]", 308 | "AzureSearchAdminKey": "[listAdminKeys(resourceId('Microsoft.Search/searchServices/', concat(variables('qnaMakerSearchName'), copyIndex())), '2015-08-19').primaryKey]", 309 | "UserAppInsightsKey": "[reference(resourceId('Microsoft.Insights/components/', concat(variables('appInsightsName'), copyIndex())), '2015-05-01').InstrumentationKey]", 310 | "UserAppInsightsName": "[concat(variables('appInsightsName'), copyIndex())]", 311 | "UserAppInsightsAppId": "[reference(resourceId('Microsoft.Insights/components/', concat(variables('appInsightsName'), copyIndex())), '2015-05-01').AppId]", 312 | "PrimaryEndpointKey": "[concat(concat(variables('qnaMakerWebAppName'), copyIndex()), '-PrimaryEndpointKey')]", 313 | "SecondaryEndpointKey": "[concat(concat(variables('qnaMakerWebAppName'), copyIndex()), '-SecondaryEndpointKey')]", 314 | "DefaultAnswer": "No good match found in KB.", 315 | "QNAMAKER_EXTENSION_VERSION": "latest" 316 | } 317 | } 318 | ], 319 | "copy": { 320 | "name": "locationLoop", 321 | "count": "[length(parameters('locations'))]" 322 | } 323 | }, 324 | { 325 | "apiVersion": "2015-11-01", 326 | "type": "Microsoft.Network/trafficManagerProfiles", 327 | "name": "WebClientTMProfile", 328 | "location": "global", 329 | "properties": { 330 | "profileStatus": "Enabled", 331 | "trafficRoutingMethod": "Performance", 332 | "dnsConfig": { 333 | "relativeName": "[variables('trafficManagerDnsName')]", 334 | "ttl": 30 335 | }, 336 | "monitorConfig": { 337 | "protocol": "HTTPS", 338 | "port": 443, 339 | "path": "/" 340 | } 341 | } 342 | }, 343 | { 344 | "apiVersion": "2015-11-01", 345 | "type": "Microsoft.Network/trafficManagerProfiles/azureEndpoints", 346 | "dependsOn": [ 347 | "Microsoft.Network/trafficManagerProfiles/WebClientTMProfile", 348 | "[concat('Microsoft.Web/sites/', variables('webAppClientName'), copyindex())]" 349 | ], 350 | "location": "global", 351 | "name": "[concat('WebClientTMProfile/Endpoint', copyIndex())]", 352 | "copy": { 353 | "name": "endpointloop", 354 | "count": "[length(parameters('locations'))]" 355 | }, 356 | "properties": { 357 | "targetResourceId": "[resourceId('Microsoft.Web/sites/', concat(variables('webAppClientName'), copyIndex()))]", 358 | "endpointLocation": "[parameters('locations')[copyIndex()]]", 359 | "endpointStatus": "Enabled" 360 | } 361 | }, 362 | { 363 | "apiVersion": "2015-11-01", 364 | "type": "Microsoft.Network/trafficManagerProfiles", 365 | "name": "QnAHostTMProfile", 366 | "location": "global", 367 | "properties": { 368 | "profileStatus": "Enabled", 369 | "trafficRoutingMethod": "Weighted", 370 | "dnsConfig": { 371 | "relativeName": "[variables('qnaTrafficManagerDnsName')]", 372 | "ttl": 30 373 | }, 374 | "monitorConfig": { 375 | "protocol": "HTTPS", 376 | "port": 443, 377 | "path": "/" 378 | } 379 | } 380 | }, 381 | { 382 | "apiVersion": "2015-11-01", 383 | "type": "Microsoft.Network/trafficManagerProfiles/azureEndpoints", 384 | "dependsOn": [ 385 | "Microsoft.Network/trafficManagerProfiles/QnAHostTMProfile", 386 | "[concat('Microsoft.Web/sites/', variables('qnaMakerWebAppName'), copyindex())]" 387 | ], 388 | "location": "global", 389 | "name": "[concat('QnAHostTMProfile/Endpoint', copyIndex())]", 390 | "copy": { 391 | "name": "endpointloop", 392 | "count": "[length(parameters('locations'))]" 393 | }, 394 | "properties": { 395 | "targetResourceId": "[resourceId('Microsoft.Web/sites/', concat(variables('qnaMakerWebAppName'), copyIndex()))]", 396 | "weight": 1, 397 | "endpointStatus": "Enabled" 398 | } 399 | }, 400 | { 401 | "comments": "storage account", 402 | "type": "Microsoft.Storage/storageAccounts", 403 | "kind": "StorageV2", 404 | "apiVersion": "2018-07-01", 405 | "name": "[variables('storageAccountName')]", 406 | "location": "[parameters('locations')[0]]", 407 | "sku": { 408 | "name": "Standard_LRS", 409 | "tier": "Standard" 410 | }, 411 | "properties": { 412 | "accessTier": "Hot" 413 | }, 414 | "resources": [ 415 | { 416 | "name": "[concat('default/',concat(variables('functionAppName'),'-index-store'))]", 417 | "type": "blobServices/containers", 418 | "apiVersion": "2018-07-01", 419 | "properties": { 420 | "publicAccess": "None" 421 | }, 422 | "dependsOn": [ 423 | "[variables('storageAccountName')]" 424 | ] 425 | } 426 | ] 427 | }, 428 | { 429 | "apiVersion": "2018-11-01", 430 | "type": "Microsoft.Web/sites", 431 | "name": "[variables('functionAppName')]", 432 | "location": "[parameters('locations')[0]]", 433 | "kind": "functionapp", 434 | "dependsOn": [ 435 | "[resourceId('Microsoft.Web/serverfarms', concat(variables('appServicePlanName'), '0'))]", 436 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 437 | ], 438 | "properties": { 439 | "name": "[variables('functionAppName')]", 440 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', concat(variables('appServicePlanName'), '0'))]", 441 | "clientAffinityEnabled": false, 442 | "siteConfig": { 443 | "alwaysOn": true, 444 | "cors": { 445 | "allowedOrigins": [ 446 | "*" 447 | ] 448 | }, 449 | "appSettings": [ 450 | { 451 | "name": "AzureWebJobsStorage", 452 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountId'),'2015-05-01-preview').key1)]" 453 | }, 454 | { 455 | "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", 456 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountId'),'2015-05-01-preview').key1)]" 457 | }, 458 | { 459 | "name": "WEBSITE_CONTENTSHARE", 460 | "value": "[toLower(variables('functionAppName'))]" 461 | }, 462 | { 463 | "name": "FUNCTIONS_EXTENSION_VERSION", 464 | "value": "~2" 465 | }, 466 | { 467 | "name": "WEBSITE_NODE_DEFAULT_VERSION", 468 | "value": "~10" 469 | }, 470 | { 471 | "name": "APPINSIGHTS_INSTRUMENTATIONKEY", 472 | "value": "[reference(resourceId('microsoft.insights/components/', concat(variables('appInsightsName'), '0')), '2015-05-01').InstrumentationKey]" 473 | }, 474 | { 475 | "name": "FUNCTIONS_WORKER_RUNTIME", 476 | "value": "dotnet" 477 | }, 478 | { 479 | "name": "AZURE_STORAGE_CONNECTION_STRING", 480 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountId'),'2015-05-01-preview').key1)]" 481 | }, 482 | { 483 | "name": "AzStorageContainerName", 484 | "value": "[concat(variables('functionAppName'),'-index-store')]" 485 | }, 486 | { 487 | "name": "SrcSearchSvcName", 488 | "value": "[concat(variables('qnaMakerSearchName'),'0')]" 489 | }, 490 | { 491 | "name": "SrcSearchApiKey", 492 | "value": "[listAdminKeys(resourceId('Microsoft.Search/searchServices/', concat(variables('qnaMakerSearchName'), '0')), '2015-08-19').primaryKey]" 493 | }, 494 | { 495 | "name": "TgtSearchSvcName", 496 | "value": "[concat(variables('qnaMakerSearchName'),'1')]" 497 | }, 498 | { 499 | "name": "TgtSearchApiKey", 500 | "value": "[listAdminKeys(resourceId('Microsoft.Search/searchServices/', concat(variables('qnaMakerSearchName'), '1')), '2015-08-19').primaryKey]" 501 | } 502 | ] 503 | } 504 | }, 505 | "resources": [ 506 | { 507 | "apiVersion": "2018-11-01", 508 | "name": "web", 509 | "type": "sourcecontrols", 510 | "dependsOn": [ 511 | "[resourceId('Microsoft.Web/Sites',variables('functionAppName'))]" 512 | ], 513 | "properties": { 514 | "repoUrl": "[parameters('funcRepoUrl')]", 515 | "branch": "[parameters('funcRepoBranch')]", 516 | "isManualIntegration": true 517 | } 518 | } 519 | ] 520 | } 521 | ], 522 | "outputs": { 523 | } 524 | } 525 | -------------------------------------------------------------------------------- /azuredeploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "name": { 6 | "value": "hbgrtst" 7 | }, 8 | "locations": { 9 | "value": ["westus","westus2"] 10 | }, 11 | "APP_SECRET": { 12 | "value": "" 13 | }, 14 | "WEBCHAT_SECRET": { 15 | "value": "" 16 | }, 17 | "appServicePlanSku": { 18 | "value": { "tier": "Standard", "name": "S1" } 19 | }, 20 | "workerSize": { 21 | "value": "1" 22 | }, 23 | "qnaMakerServiceLocation": { 24 | "value": "westus" 25 | }, 26 | "qnaMakerServiceSku": { 27 | "value": "S0" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /cert-deploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json", 3 | "contentVersion": "1.0.0.0", 4 | "metadata" : { 5 | "comments": "This ARM template deploys Azure resources included in the Health Bot Reference Architecture", 6 | "author": "Microsoft Healthcare CSU" 7 | }, 8 | "parameters": { 9 | "name": { 10 | "type": "string", 11 | "metadata":{ 12 | "description":"Base name (prefix) for all resources." 13 | } 14 | }, 15 | "locations": { 16 | "type": "array", 17 | "defaultValue": [ 18 | "westus", 19 | "eastus" 20 | ], 21 | "metadata":{ 22 | "description":"Array of Azure deployment regions to deploy to." 23 | } 24 | }, 25 | "tmDomainSuffix": { 26 | "type": "string", 27 | "defaultValue": ".trafficmanager.net", 28 | "metadata":{ 29 | "description":"Azure Traffic Manager DNS suffix" 30 | } 31 | } 32 | }, 33 | "variables": { 34 | "appServicePlanName": "[concat(parameters('name'), '-appServicePlan')]", 35 | "webAppClientName": "[concat(parameters('name'), '-webClient')]", 36 | "customDomainWebAppSvc": "[concat(parameters('name'), '-webclient', parameters('tmDomainSuffix'))]", 37 | "qnaMakerWebAppName": "[replace(concat(parameters('name'), '-qnahost'), '_', '')]", 38 | "customDomainQnaAppSvc": "[concat(parameters('name'), '-qna', parameters('tmDomainSuffix'))]" 39 | }, 40 | "resources": [ 41 | { 42 | "type": "Microsoft.Web/sites/hostnameBindings", 43 | "apiVersion": "2019-08-01", 44 | "name": "[concat(variables('webAppClientName'), copyIndex(), '/', variables('customDomainWebAppSvc'))]", 45 | "location": "[parameters('locations')[copyIndex()]]", 46 | "properties": { 47 | }, 48 | "copy": { 49 | "name": "locationLoop", 50 | "count": "[length(parameters('locations'))]" 51 | } 52 | }, 53 | { 54 | "type": "Microsoft.Web/certificates", 55 | "apiVersion": "2019-08-01", 56 | "name": "[concat(variables('webAppClientName'), copyIndex())]", 57 | "location": "[parameters('locations')[copyIndex()]]", 58 | "properties": { 59 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms/', concat(variables('appServicePlanName'), copyIndex()))]", 60 | "canonicalName": "[variables('customDomainWebAppSvc')]" 61 | }, 62 | "dependsOn": [ 63 | "[concat('Microsoft.Web/sites/', concat(variables('webAppClientName'), copyIndex(), '/hostnameBindings/', variables('customDomainWebAppSvc')))]" 64 | ], 65 | "copy": { 66 | "name": "locationLoop", 67 | "count": "[length(parameters('locations'))]" 68 | } 69 | }, 70 | { 71 | "apiVersion": "2017-05-10", 72 | "name": "nestedTemplate", 73 | "type": "Microsoft.Resources/deployments", 74 | "properties": { 75 | "mode": "Incremental", 76 | "template": { 77 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 78 | "contentVersion": "1.0.0.0", 79 | "resources": [ 80 | { 81 | "type": "Microsoft.Web/sites/hostnameBindings", 82 | "name": "[concat(variables('webAppClientName'),'0','/',variables('customDomainWebAppSvc'))]", 83 | "apiVersion": "2019-08-01", 84 | "location": "[parameters('locations')[0]]", 85 | "properties": { 86 | "sslState": "SniEnabled", 87 | "thumbprint": "[reference(resourceId('Microsoft.Web/certificates', concat(variables('webAppClientName'), '0'))).Thumbprint]" 88 | } 89 | } 90 | ], 91 | "outputs": { 92 | } 93 | } 94 | } 95 | }, 96 | { 97 | "apiVersion": "2017-05-10", 98 | "name": "nestedTemplate0", 99 | "type": "Microsoft.Resources/deployments", 100 | "properties": { 101 | "mode": "Incremental", 102 | "template": { 103 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 104 | "contentVersion": "1.0.0.0", 105 | "resources": [ 106 | { 107 | "type": "Microsoft.Web/sites/hostnameBindings", 108 | "name": "[concat(variables('webAppClientName'),'1','/',variables('customDomainWebAppSvc'))]", 109 | "apiVersion": "2019-08-01", 110 | "location": "[parameters('locations')[1]]", 111 | "properties": { 112 | "sslState": "SniEnabled", 113 | "thumbprint": "[reference(resourceId('Microsoft.Web/certificates', concat(variables('webAppClientName'), '1'))).Thumbprint]" 114 | } 115 | } 116 | ], 117 | "outputs": { 118 | } 119 | } 120 | } 121 | }, 122 | { 123 | "type": "Microsoft.Web/sites/hostnameBindings", 124 | "apiVersion": "2019-08-01", 125 | "name": "[concat(variables('qnaMakerWebAppName'), copyIndex(), '/', variables('customDomainQnaAppSvc'))]", 126 | "location": "[parameters('locations')[copyIndex()]]", 127 | "properties": { 128 | }, 129 | "copy": { 130 | "name": "locationLoop", 131 | "count": "[length(parameters('locations'))]" 132 | } 133 | }, 134 | { 135 | "type": "Microsoft.Web/certificates", 136 | "apiVersion": "2019-08-01", 137 | "name": "[concat(variables('qnaMakerWebAppName'), copyIndex())]", 138 | "location": "[parameters('locations')[copyIndex()]]", 139 | "properties": { 140 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms/', concat(variables('appServicePlanName'), copyIndex()))]", 141 | "canonicalName": "[variables('customDomainQnaAppSvc')]" 142 | }, 143 | "dependsOn": [ 144 | "[concat('Microsoft.Web/sites/', concat(variables('qnaMakerWebAppName'), copyIndex(), '/hostnameBindings/', variables('customDomainQnaAppSvc')))]" 145 | ], 146 | "copy": { 147 | "name": "locationLoop", 148 | "count": "[length(parameters('locations'))]" 149 | } 150 | }, 151 | { 152 | "apiVersion": "2017-05-10", 153 | "name": "nestedTemplate1", 154 | "type": "Microsoft.Resources/deployments", 155 | "properties": { 156 | "mode": "Incremental", 157 | "template": { 158 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 159 | "contentVersion": "1.0.0.0", 160 | "resources": [ 161 | { 162 | "type": "Microsoft.Web/sites/hostnameBindings", 163 | "name": "[concat(variables('qnaMakerWebAppName'),'0','/',variables('customDomainQnaAppSvc'))]", 164 | "apiVersion": "2019-08-01", 165 | "location": "[parameters('locations')[0]]", 166 | "properties": { 167 | "sslState": "SniEnabled", 168 | "thumbprint": "[reference(resourceId('Microsoft.Web/certificates', concat(variables('qnaMakerWebAppName'), '0'))).Thumbprint]" 169 | } 170 | } 171 | ], 172 | "outputs": { 173 | } 174 | } 175 | } 176 | }, 177 | { 178 | "apiVersion": "2017-05-10", 179 | "name": "nestedTemplate2", 180 | "type": "Microsoft.Resources/deployments", 181 | "properties": { 182 | "mode": "Incremental", 183 | "template": { 184 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 185 | "contentVersion": "1.0.0.0", 186 | "resources": [ 187 | { 188 | "type": "Microsoft.Web/sites/hostnameBindings", 189 | "name": "[concat(variables('qnaMakerWebAppName'),'1','/',variables('customDomainQnaAppSvc'))]", 190 | "apiVersion": "2019-08-01", 191 | "location": "[parameters('locations')[1]]", 192 | "properties": { 193 | "sslState": "SniEnabled", 194 | "thumbprint": "[reference(resourceId('Microsoft.Web/certificates', concat(variables('qnaMakerWebAppName'), '1'))).Thumbprint]" 195 | } 196 | } 197 | ], 198 | "outputs": { 199 | } 200 | } 201 | } 202 | } 203 | ], 204 | "outputs": { 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /cert-deploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "name": { 6 | "value": "grtst04" 7 | }, 8 | "locations": { 9 | "value": ["westus","westus2"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /cert-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "webAppName": { 6 | "type": "string" 7 | }, 8 | "customDomain": { 9 | "type": "string" 10 | }, 11 | "location": { 12 | "type": "string" 13 | }, 14 | "certThumbprint": { 15 | "type": "string" 16 | } 17 | }, 18 | "resources": [ 19 | { 20 | "type": "Microsoft.Web/sites/hostnameBindings", 21 | "name": "[concat(parameters('webAppName'), '/', parameters('customDomain'))]", 22 | "apiVersion": "2019-04-01", 23 | "location": "[parameters('location')]", 24 | "properties": { 25 | "sslState": "SniEnabled", 26 | "thumbprint": "[parameters('certThumbprint')]" 27 | } 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /images/A-01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/HealthBotRefArchDeploy/80e5a1355f277fd4d95d31180efd36abdc622bfb/images/A-01.jpg -------------------------------------------------------------------------------- /images/A-02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/HealthBotRefArchDeploy/80e5a1355f277fd4d95d31180efd36abdc622bfb/images/A-02.jpg -------------------------------------------------------------------------------- /images/A-03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/HealthBotRefArchDeploy/80e5a1355f277fd4d95d31180efd36abdc622bfb/images/A-03.jpg -------------------------------------------------------------------------------- /images/A-04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/HealthBotRefArchDeploy/80e5a1355f277fd4d95d31180efd36abdc622bfb/images/A-04.jpg -------------------------------------------------------------------------------- /images/A-05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/HealthBotRefArchDeploy/80e5a1355f277fd4d95d31180efd36abdc622bfb/images/A-05.jpg -------------------------------------------------------------------------------- /images/A-06.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/HealthBotRefArchDeploy/80e5a1355f277fd4d95d31180efd36abdc622bfb/images/A-06.jpg -------------------------------------------------------------------------------- /images/A-07.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/HealthBotRefArchDeploy/80e5a1355f277fd4d95d31180efd36abdc622bfb/images/A-07.jpg -------------------------------------------------------------------------------- /images/DeployArch-v10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/HealthBotRefArchDeploy/80e5a1355f277fd4d95d31180efd36abdc622bfb/images/DeployArch-v10.jpg --------------------------------------------------------------------------------