Related
I created an Azure custom provider by following the documentation in the link below:
https://learn.microsoft.com/en-us/azure/azure-resource-manager/custom-providers/
I am able to successfully create resources for the types defined in the custom provider using ARM templates. However, I do not see those resources on the azure portal under the specific resource group.
Is this behavior expected?
I have deployed the custom provider in azure portal using ARM template by following below steps
Open azure portal and search for custom deployment as below
Taken reference from Microsoft Doc
After opening custom deployment, i have used the below code and then click on save
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"funcName": {
"type": "string",
"defaultValue": "[uniqueString(resourceGroup().id)]",
"metadata": {
"description": "The unique name of the function application"
}
},
"storageName": {
"type": "string",
"defaultValue": "[concat('store', uniquestring(resourceGroup().id))]",
"metadata": {
"description": "The unique name of the storage account."
}
},
"location": {
"type": "string",
"defaultValue": "eastus",
"metadata": {
"description": "The location for the resources."
}
},
"zipFileBlobUri": {
"type": "string",
"defaultValue": "https://github.com/Azure/azure-docs-json-samples/blob/master/custom-providers/_artifacts/functionpackage.zip?raw=true",
"metadata": {
"description": "The URI to the uploaded function zip file"
}
}
},
"resources": [
{
"type": "Microsoft.Web/sites",
"apiVersion": "2022-03-01",
"name": "[parameters('funcName')]",
"location": "[parameters('location')]",
"kind": "functionapp",
"identity": {
"type": "SystemAssigned"
},
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageName'))]"
],
"properties": {
"name": "[parameters('funcName')]",
"siteConfig": {
"appSettings": [
{
"name": "AzureWebJobsDashboard",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('storageName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '2022-05-01').keys[0].value)]"
},
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('storageName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '2022-05-01').keys[0].value)]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('storageName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '2022-05-01').keys[0].value)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[toLower(parameters('funcName'))]"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "6.5.0"
},
{
"name": "WEBSITE_RUN_FROM_PACKAGE",
"value": "[parameters('zipFileBlobUri')]"
}
]
},
"clientAffinityEnabled": false,
"reserved": false
}
},
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2022-05-01",
"name": "[parameters('storageName')]",
"location": "[parameters('location')]",
"kind": "StorageV2",
"sku": {
"name": "Standard_LRS"
}
},
{
"type": "Microsoft.CustomProviders/resourceProviders",
"apiVersion": "2018-09-01-preview",
"name": "[parameters('funcName')]",
"location": "[parameters('location')]",
"dependsOn": [
"[concat('Microsoft.Web/sites/',parameters('funcName'))]"
],
"properties": {
"actions": [
{
"name": "ping",
"routingType": "Proxy",
"endpoint": "[concat('https://', parameters('funcName'), '.azurewebsites.net/api/{requestPath}')]"
}
],
"resourceTypes": [
{
"name": "users",
"routingType": "Proxy,Cache",
"endpoint": "[concat('https://', parameters('funcName'), '.azurewebsites.net/api/{requestPath}')]"
}
]
}
},
{
"type": "Microsoft.CustomProviders/resourceProviders/users",
"apiVersion": "2018-09-01-preview",
"name": "[concat(parameters('funcName'), '/ana')]",
"location": "parameters('location')",
"dependsOn": [
"[concat('Microsoft.CustomProviders/resourceProviders/',parameters('funcName'))]"
],
"properties": {
"FullName": "Ana Bowman",
"Location": "Moon"
}
}
],
"outputs": {
"principalId": {
"type": "string",
"value": "[reference(concat('Microsoft.Web/sites/', parameters('funcName')), '2022-03-01', 'Full').identity.principalId]"
}
}
}
Fill the following details like Subscription id, resource group, location and click on review+create
After deploying into the azure portal, we will get below
After deploying it to azure poral Goto azure portal and click on your resource group and click on the check box you will find as below
I'm trying to manage CA certificates in Azure APIM through ARM but everything I tried gave no positive result.
For visualization, this is what I'm talking about:
When I look at the schema Microsoft.ApiManagement/service, there's a section for certificates where I can set the storeName variable but without results.
For sanity, I tried to upload it though Powershell plus manually and both option worked but that CA Certificate got wiped from the APIM at each deployment of my ARM template even if I used the "Incremental" option.
First I tried to modify the APIM ARM template by adding that block to the "properties" section:
"certificates": [
{
"encodedCertificate": "[parameters('RootCertificateBase64Content')]",
"certificatePassword": "[parameters('RootCertificatePassword')]",
"storeName": "Root"
}]
Here's my first test snippet for complete traceability:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"apimName": {
"type": "string",
"metadata": {
"description": "Name of the apimanagement"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
},
"sku": {
"type": "string",
"allowedValues": [
"Developer",
"Standard",
"Premium"
],
"defaultValue": "Developer",
"metadata": {
"description": "The pricing tier of this API Management service"
}
},
"skuCapacity": {
"type": "string",
"allowedValues": [
"1",
"2"
],
"defaultValue": "1",
"metadata": {
"description": "The instance size of this API Management service."
}
},
"subnetResourceId": {
"type": "string",
"metadata": {
"description": ""
}
},
"RootCertificateBase64Content": {
"type": "string",
"metadata": {
"description": "The Root certificate content"
}
},
"RootCertificatePassword": {
"type": "string",
"metadata": {
"description": "The Root certificate password"
}
}
},
"variables": {
"publisherEmail": "whatever#heyho.com",
"publisherName": "Whatever Team",
"notificationSenderEmail": "whatever#heygo.com"
},
"resources": [
{
"apiVersion": "2019-12-01",
"name": "[parameters('apimName')]",
"type": "Microsoft.ApiManagement/service",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('sku')]",
"capacity": "[parameters('skuCapacity')]"
},
"properties": {
"notificationSenderEmail": "[variables('notificationSenderEmail')]",
"publisherEmail": "[variables('publisherEmail')]",
"publisherName": "[variables('publisherName')]",
"virtualNetworkConfiguration": {
"subnetResourceId": "[parameters('subnetResourceId')]"
},
"virtualNetworkType": "Internal",
"certificates": [
{
"encodedCertificate": "[parameters('RootCertificateBase64Content')]",
"certificatePassword": "[parameters('RootCertificatePassword')]",
"storeName": "Root"
}]
},
"identity": {
"type": "SystemAssigned"
}
}
],
"outputs": {
"apiManagementPrivateHostIp": {
"type": "string",
"value": "[reference(concat(resourceId('Microsoft.ApiManagement/service', parameters('apimName')))).privateIPAddresses[0]]"
}
}
}
Second alternative I tried was to use the Microsoft.ApiManagement/service/certificates schema. There is no option there to specify the StoreName so I assumed it wasn't the right schema but I tried anyway. All attempts generated a certificate in the built-in Certificates store instead of the CA Certificates store.
Here's my second attempt's snippet:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"apimName": {
"type": "string",
"metadata": {
"description": "The parent APIM name"
}
},
"certificateName": {
"type": "string",
"metadata": {
"description": "The certificate name"
}
},
"CertificateBase64Content": {
"type": "string",
"metadata": {
"description": "The content of the certificate"
}
},
"CertificatePassword": {
"type": "string",
"metadata": {
"description": "The certificate password"
}
}
},
"resources": [
{
"name": "[concat(parameters('apimName'), '/Root/', parameters('certificateName'))]",
"type": "Microsoft.ApiManagement/service/certificates",
"apiVersion": "2019-01-01",
"properties": {
"data": "[parameters('CertificateBase64Content')]",
"password": "[parameters('CertificatePassword')]"
}
}
],
"outputs": {}
}
While looking at terraform documentation, it seems that it's possible to manage these certificates through the base schema and I confirmed that through the terraform azurerm provider source code (Unfortunately I cannot use Terraform and I MUST use ARM in that scenario).
Any clues on how to manage CA certificates in Azure APIM through ARM?
I assume you want to update CA certificate authority sections of already existing APIM? If yes then just provide all required properties for Microsoft.ApiManagement/service but for name use already existing APIM name that you want to update and choose the same resource group.
Thanks to this, it will just update existing APIM with properties you provided, instead of creating new APIM. The required properties are name, type, apiVersion, location, sku, properties. For properties you need to provide publisherEmail and publisherName, and of course certificates - this is what you want to update after all. So the absolute minimum for update will look like this:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters":{
"base64EncodedCertificate":{
"defaultValue":"base64 encoded certificate",
"type":"String"
},
"certificatePassword":{
"defaultValue":"certificate password",
"type":"String"
}
},
"variables": {},
"resources": [
{
"name": "existing-apim-name",
"type": "Microsoft.ApiManagement/service",
"apiVersion": "2021-01-01-preview",
"location": "West Europe",
"sku": {
"name": "Developer",
"capacity": 1
},
"properties": {
"publisherEmail": "publisher#gmail.com",
"publisherName": "Publisher Name",
"certificates": [
{
"encodedCertificate": "[parameters('base64EncodedCertificate')]",
"certificatePassword": "[parameters('certificatePassword')]",
"storeName": "Root"
}
]
}
}
]
}
Watch out. certificates array must contain all certificates that you want to have on this APIM. All existing CA certs that are not in this array will be deleted.
I'm having a scenario, where I need to use the same app service plan to deploy the resources (app service) in another resource group.
App service plan resides in another resource group.
I tried this, which is giving "app service plan not found error". Here is the Deployment.json file.
Reference: https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-deploy-az-cli?view=azure-bot-service-4.0&tabs=csharp#option-1-existing-app-service-plan
This deployment json works fine when we tried to deploy the app in the same resource group without creating a new plan.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appId": {
"type": "string",
"metadata": {
"description": "Active Directory App ID, set as MicrosoftAppId in the Web App's Application Settings."
}
},
"appSecret": {
"type": "string",
"metadata": {
"description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings. Defaults to \"\"."
}
},
"botId": {
"type": "string",
"metadata": {
"description": "The globally unique and immutable bot ID. Also used to configure the displayName of the bot, which is mutable."
}
},
"botSku": {
"defaultValue": "F0",
"type": "string",
"metadata": {
"description": "The pricing tier of the Bot Service Registration. Acceptable values are F0 and S1."
}
},
"newAppServicePlanName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The name of the new App Service Plan."
}
},
"newAppServicePlanSku": {
"type": "object",
"defaultValue": {
"name": "S1",
"tier": "Standard",
"size": "S1",
"family": "S",
"capacity": 1
},
"metadata": {
"description": "The SKU of the App Service Plan. Defaults to Standard values."
}
},
"appServicePlanLocation": {
"type": "string",
"metadata": {
"description": "The location of the App Service Plan."
}
},
"existingAppServicePlan": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Name of the existing App Service Plan used to create the Web App for the bot."
}
},
"newWebAppName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The globally unique name of the Web App. Defaults to the value passed in for \"botId\"."
}
}
},
"variables": {
"defaultAppServicePlanName": "[if(empty(parameters('existingAppServicePlan')), 'createNewAppServicePlan', parameters('existingAppServicePlan'))]",
"useExistingAppServicePlan": "[not(equals(variables('defaultAppServicePlanName'), 'createNewAppServicePlan'))]",
"servicePlanName": "[if(variables('useExistingAppServicePlan'), parameters('existingAppServicePlan'), parameters('newAppServicePlanName'))]",
"resourcesLocation": "[parameters('appServicePlanLocation')]",
"webAppName": "[if(empty(parameters('newWebAppName')), parameters('botId'), parameters('newWebAppName'))]",
"siteHost": "[concat(variables('webAppName'), '.azurewebsites.net')]",
"botEndpoint": "[concat('https://', variables('siteHost'), '/api/messages')]"
},
"resources": [
{
"comments": "Create a new App Service Plan if no existing App Service Plan name was passed in.",
"type": "Microsoft.Web/serverfarms",
"condition": "[not(variables('useExistingAppServicePlan'))]",
"name": "[variables('servicePlanName')]",
"apiVersion": "2018-02-01",
"location": "[variables('resourcesLocation')]",
"sku": "[parameters('newAppServicePlanSku')]",
"properties": {
"name": "[variables('servicePlanName')]"
}
},
{
"comments": "Create a Web App using an App Service Plan",
"type": "Microsoft.Web/sites",
"apiVersion": "2015-08-01",
"location": "[variables('resourcesLocation')]",
"kind": "app",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('servicePlanName'))]"
],
"name": "[variables('webAppName')]",
"properties": {
"name": "[variables('webAppName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('servicePlanName'))]",
"siteConfig": {
"appSettings": [
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "10.14.1"
},
{
"name": "MicrosoftAppId",
"value": "[parameters('appId')]"
},
{
"name": "MicrosoftAppPassword",
"value": "[parameters('appSecret')]"
}
],
"cors": {
"allowedOrigins": [
"https://botservice.hosting.portal.azure.net",
"https://hosting.onecloud.azure-test.net/"
]
}
}
}
},
{
"apiVersion": "2017-12-01",
"type": "Microsoft.BotService/botServices",
"name": "[parameters('botId')]",
"location": "global",
"kind": "bot",
"sku": {
"name": "[parameters('botSku')]"
},
"properties": {
"name": "[parameters('botId')]",
"displayName": "[parameters('botId')]",
"endpoint": "[variables('botEndpoint')]",
"msaAppId": "[parameters('appId')]",
"developerAppInsightsApplicationId": null,
"developerAppInsightKey": null,
"publishingCredentials": null,
"storageResourceId": null
},
"dependsOn": [
"[resourceId('Microsoft.Web/sites/', variables('webAppName'))]"
]
}
]
}
You have to specify the resource group that the app service plan is in when using the resourceId function as per the documentation.
I'm trying to execute this instruction of Azure CLI:
az deployment sub create --name "ThisIsATest" --location northeurope
--template-file /Users/muzcateg/Documents/TeaBotframeworkVIP/DeploymentTemplates/template-with-new-rg.json
--parameters appId="7450874d-a8cb-4613-b021-621a34b21bbb" appSecret="ThisIsATest123456789" botId="ThisIsATest" botSku=F0 newAppServicePlanName="ThisIsATestServicePlan" newWebAppName="ThisIsATestWebApp" groupName="ThisIsATestResources" groupLocation="northeurope" newAppServicePlanLocation="northeurope"
--output json
And I'm getting this error:
{
'additionalProperties': {},
'code': 'InvalidTemplate',
'message': "Deployment template validation failed: 'The resource '/subscriptions/63c45336-738e-4431-b8cd-21097fd6a9f4/resourceGroups/ThisIsATestResources/providers/Microsoft.BotService/botServices/ThisIsATest/channels/MsTeamsChannel' at line '1' and column '2080' doesn't depend on parent resource '/subscriptions/63c45336-738e-4431-b8cd-21097fd6a9f4/resourceGroups/ThisIsATestResources/providers/Microsoft.BotService/botServices/ThisIsATest'. Please add dependency explicitly using the 'dependsOn' syntax. Please see https://aka.ms/arm-template/#resources for usage details.'.",
'target': None,
'details': None,
'additionalInfo': [{
'additionalProperties': {},
'type': 'TemplateViolation',
'info': {
'lineNumber': 1,
'linePosition': 2080,
'path': 'properties.template.resources[2].resources[0]'
}
}]
}
I'm using the standard template (template-with-new-rg.json) from the Botframework GIT examples, I have tried a lot of changes to see if I can make it work but with no success.
A colleague of mine is executing the instruction correctly in her PC, She is using CLI 2.7.0, I was using 2.8.0 and I change it to 2.7.0 too, we are supposed to have the same permissions in Azure.
Just in case, this is the template code:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"groupLocation": {
"type": "string",
"metadata": {
"description": "Specifies the location of the Resource Group."
}
},
"groupName": {
"type": "string",
"metadata": {
"description": "Specifies the name of the Resource Group."
}
},
"appId": {
"type": "string",
"metadata": {
"description": "Active Directory App ID, set as MicrosoftAppId in the Web App's Application Settings."
}
},
"appSecret": {
"type": "string",
"metadata": {
"description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings."
}
},
"botId": {
"type": "string",
"metadata": {
"description": "The globally unique and immutable bot ID. Also used to configure the displayName of the bot, which is mutable."
}
},
"botSku": {
"type": "string",
"metadata": {
"description": "The pricing tier of the Bot Service Registration. Acceptable values are F0 and S1."
}
},
"newAppServicePlanName": {
"type": "string",
"metadata": {
"description": "The name of the App Service Plan."
}
},
"newAppServicePlanSku": {
"type": "object",
"defaultValue": {
"name": "S1",
"tier": "Standard",
"size": "S1",
"family": "S",
"capacity": 1
},
"metadata": {
"description": "The SKU of the App Service Plan. Defaults to Standard values."
}
},
"newAppServicePlanLocation": {
"type": "string",
"metadata": {
"description": "The location of the App Service Plan. Defaults to \"westus\"."
}
},
"newWebAppName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The globally unique name of the Web App. Defaults to the value passed in for \"botId\"."
}
}
},
"variables": {
"appServicePlanName": "[parameters('newAppServicePlanName')]",
"resourcesLocation": "[parameters('newAppServicePlanLocation')]",
"webAppName": "[if(empty(parameters('newWebAppName')), parameters('botId'), parameters('newWebAppName'))]",
"siteHost": "[concat(variables('webAppName'), '.azurewebsites.net')]",
"botEndpoint": "[concat('https://', variables('siteHost'), '/api/messages')]"
},
"resources": [
{
"name": "[parameters('groupName')]",
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2018-05-01",
"location": "[parameters('groupLocation')]",
"properties": {
}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2018-05-01",
"name": "storageDeployment",
"resourceGroup": "[parameters('groupName')]",
"dependsOn": [
"[resourceId('Microsoft.Resources/resourceGroups/', parameters('groupName'))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
"comments": "Create a new App Service Plan",
"type": "Microsoft.Web/serverfarms",
"name": "[variables('appServicePlanName')]",
"apiVersion": "2018-02-01",
"location": "[variables('resourcesLocation')]",
"sku": "[parameters('newAppServicePlanSku')]",
"properties": {
"name": "[variables('appServicePlanName')]"
}
},
{
"comments": "Create a Web App using the new App Service Plan",
"type": "Microsoft.Web/sites",
"apiVersion": "2015-08-01",
"location": "[variables('resourcesLocation')]",
"kind": "app",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms/', variables('appServicePlanName'))]"
],
"name": "[variables('webAppName')]",
"properties": {
"name": "[variables('webAppName')]",
"serverFarmId": "[variables('appServicePlanName')]",
"siteConfig": {
"appSettings": [
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "10.14.1"
},
{
"name": "MicrosoftAppId",
"value": "[parameters('appId')]"
},
{
"name": "MicrosoftAppPassword",
"value": "[parameters('appSecret')]"
}
],
"cors": {
"allowedOrigins": [
"https://botservice.hosting.portal.azure.net",
"https://hosting.onecloud.azure-test.net/"
]
}
}
}
},
{
"apiVersion": "2017-12-01",
"type": "Microsoft.BotService/botServices",
"name": "[parameters('botId')]",
"location": "global",
"kind": "bot",
"sku": {
"name": "[parameters('botSku')]"
},
"properties": {
"name": "[parameters('botId')]",
"displayName": "[parameters('botId')]",
"endpoint": "[variables('botEndpoint')]",
"msaAppId": "[parameters('appId')]",
"developerAppInsightsApplicationId": null,
"developerAppInsightKey": null,
"publishingCredentials": null,
"storageResourceId": null
},
"resources": [
{
"name": "MsTeamsChannel",
"type": "channels",
"location": "global",
"apiVersion": "2018-07-12",
"kind": "bot",
"properties": {
"channelName": "MsTeamsChannel"
},
"dependsOn": [
"[resourceId('Microsoft.BotService/botServices', parameters('botId'))]"
]
}
],
"dependsOn": [
"[resourceId('Microsoft.Web/sites/', variables('webAppName'))]"
]
}
],
"outputs": {}
}
}
}
]
}
Thanks in advance for any help.
The template just works on the old version of de Azure CLI in our case 2.0.7, so after lots of test and reading we end up deploying this JSON file with Azure CLI 2.7.0 and 2.8.0
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appId": {
"type": "string",
"metadata": {
"description": "Active Directory App ID, set as MicrosoftAppId in the Web App's Application Settings."
}
},
"appSecret": {
"type": "string",
"metadata": {
"description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings. Defaults to \"\"."
}
},
"botId": {
"type": "string",
"metadata": {
"description": "The globally unique and immutable bot ID. Also used to configure the displayName of the bot, which is mutable."
}
},
"botSku": {
"defaultValue": "F0",
"type": "string",
"metadata": {
"description": "The pricing tier of the Bot Service Registration. Acceptable values are F0 and S1."
}
},
"newAppServicePlanName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The name of the new App Service Plan."
}
},
"newAppServicePlanSku": {
"type": "object",
"defaultValue": {
"name": "S1",
"tier": "Standard",
"size": "S1",
"family": "S",
"capacity": 1
},
"metadata": {
"description": "The SKU of the App Service Plan. Defaults to Standard values."
}
},
"appServicePlanLocation": {
"type": "string",
"metadata": {
"description": "The location of the App Service Plan."
}
},
"existingAppServicePlan": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Name of the existing App Service Plan used to create the Web App for the bot."
}
},
"existingAppServicePlanResourceGroup": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Name of the resource group for the existing App Service Plan used to create the Web App for the bot."
}
},
"newWebAppName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The globally unique name of the Web App. Defaults to the value passed in for \"botId\"."
}
}
},
"variables": {
"defaultAppServicePlanName": "[if(empty(parameters('existingAppServicePlan')), 'createNewAppServicePlan', parameters('existingAppServicePlan'))]",
"useExistingAppServicePlan": "[not(equals(variables('defaultAppServicePlanName'), 'createNewAppServicePlan'))]",
"servicePlanName": "[if(variables('useExistingAppServicePlan'), parameters('existingAppServicePlan'), parameters('newAppServicePlanName'))]",
"resourcesLocation": "[parameters('appServicePlanLocation')]",
"webAppName": "[if(empty(parameters('newWebAppName')), parameters('botId'), parameters('newWebAppName'))]",
"siteHost": "[concat(variables('webAppName'), '.azurewebsites.net')]",
"botEndpoint": "[concat('https://', variables('siteHost'), '/api/messages')]"
},
"resources": [
{
"comments": "Create a new App Service Plan if no existing App Service Plan name was passed in.",
"type": "Microsoft.Web/serverfarms",
"condition": "[not(variables('useExistingAppServicePlan'))]",
"name": "[variables('servicePlanName')]",
"apiVersion": "2018-02-01",
"location": "[variables('resourcesLocation')]",
"sku": "[parameters('newAppServicePlanSku')]",
"properties": {
"name": "[variables('servicePlanName')]"
}
},
{
"comments": "Create a Web App using an App Service Plan",
"type": "Microsoft.Web/sites",
"apiVersion": "2015-08-01",
"location": "[variables('resourcesLocation')]",
"kind": "app",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('servicePlanName'))]"
],
"name": "[variables('webAppName')]",
"properties": {
"name": "[variables('webAppName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('servicePlanName'))]",
"siteConfig": {
"appSettings": [
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "10.14.1"
},
{
"name": "MicrosoftAppId",
"value": "[parameters('appId')]"
},
{
"name": "MicrosoftAppPassword",
"value": "[parameters('appSecret')]"
}
],
"cors": {
"allowedOrigins": [
"https://botservice.hosting.portal.azure.net",
"https://hosting.onecloud.azure-test.net/"
]
},
"webSocketsEnabled": true
}
}
},
{
"apiVersion": "2017-12-01",
"type": "Microsoft.BotService/botServices",
"name": "[parameters('botId')]",
"location": "global",
"kind": "bot",
"sku": {
"name": "[parameters('botSku')]"
},
"properties": {
"name": "[parameters('botId')]",
"displayName": "[parameters('botId')]",
"endpoint": "[variables('botEndpoint')]",
"msaAppId": "[parameters('appId')]",
"developerAppInsightsApplicationId": null,
"developerAppInsightKey": null,
"publishingCredentials": null,
"storageResourceId": null
},
"dependsOn": [
"[resourceId('Microsoft.Web/sites/', variables('webAppName'))]"
]
}
]
}
Thanks to all.
I've written an ARM template to deploy Azure Kubernetes Service (AKS). However, I'm unable to find a way to automate the creation of the service principal client ID and secret.
Is there a way I can create the service principal in an ARM template and store the client ID and secret in Azure Key Vault, as I've learned to do here?
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"environment": {
"metadata": {
"description": "The name of the environment."
},
"type": "string"
},
// Azure Kubernetes Service
"kubernetes_name": {
"metadata": {
"description": "The name of the Managed Cluster resource."
},
"type": "string"
},
"kubernetes_location": {
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "The location of AKS resource."
},
"type": "string"
},
"kubernetes_dnsPrefix": {
"metadata": {
"description": "Optional DNS prefix to use with hosted Kubernetes API server FQDN."
},
"type": "string"
},
"kubernetes_osDiskSizeGB": {
"defaultValue": 0,
"metadata": {
"description": "Disk size (in GB) to provision for each of the agent pool nodes. This value ranges from 0 to 1023. Specifying 0 will apply the default disk size for that agentVMSize."
},
"maxValue": 1023,
"minValue": 0,
"type": "int"
},
"kubernetes_osType": {
"allowedValues": [
"Linux"
],
"defaultValue": "Linux",
"metadata": {
"description": "The type of operating system."
},
"type": "string"
},
"kubernetes_agentCount": {
"defaultValue": 3,
"metadata": {
"description": "The number of agent nodes for the cluster."
},
"maxValue": 50,
"minValue": 1,
"type": "int"
},
"kubernetes_agentVMSize": {
"defaultValue": "Standard_D2_v2",
"metadata": {
"description": "The size of the Virtual Machine."
},
"type": "string"
},
"kubernetes_maxPods": {
"defaultValue": 30,
"metadata": {
"description": "Maximum number of pods that can run on a node."
},
"type": "int"
},
"kubernetes_servicePrincipalClientId": {
"defaultValue": null,
"metadata": {
"description": "Client ID (used by cloudprovider)"
},
"type": "securestring"
},
"kubernetes_servicePrincipalClientSecret": {
"defaultValue": null,
"metadata": {
"description": "The Service Principal Client Secret."
},
"type": "securestring"
},
"kubernetes_kubernetesVersion": {
"defaultValue": "1.7.7",
"metadata": {
"description": "The version of Kubernetes."
},
"type": "string"
},
"kubernetes_enableHttpApplicationRouting": {
"defaultValue": false,
"metadata": {
"description": "boolean flag to turn on and off of http application routing"
},
"type": "bool"
},
"kubernetes_networkPlugin": {
"allowedValues": [
"azure",
"kubenet"
],
"defaultValue": "kubenet",
"metadata": {
"description": "Network plugin used for building Kubernetes network."
},
"type": "string"
},
"kubernetes_enableRBAC": {
"defaultValue": true,
"metadata": {
"description": "boolean flag to turn on and off of RBAC"
},
"type": "bool"
},
"kubernetes_enableOmsAgent": {
"defaultValue": true,
"metadata": {
"description": "boolean flag to turn on and off of omsagent addon"
},
"type": "bool"
},
// Azure Log Analytics
"log_analytics_location": {
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Specify the region for your OMS workspace"
},
"type": "string"
},
"log_analytics_workspaceName": {
"metadata": {
"description": "Specify the name of the OMS workspace"
},
"type": "string"
},
"log_analytics_workspaceId": {
"metadata": {
"description": "Specify the resource id of the OMS workspace"
},
"type": "string"
},
"log_analytics_sku": {
"allowedValues": [
"free",
"standalone",
"pernode"
],
"defaultValue": "free",
"metadata": {
"description": "Select the SKU for your workspace"
},
"type": "string"
}
},
"resources": [
{
"comments": "Azure Kubernetes Service",
"apiVersion": "2018-03-31",
"dependsOn": [
"[concat('Microsoft.Resources/deployments/', 'WorkspaceDeployment')]"
],
"type": "Microsoft.ContainerService/managedClusters",
"location": "[parameters('kubernetes_location')]",
"name": "[parameters('kubernetes_name')]",
"properties": {
"kubernetesVersion": "[parameters('kubernetes_kubernetesVersion')]",
"enableRBAC": "[parameters('kubernetes_enableRBAC')]",
"dnsPrefix": "[parameters('kubernetes_dnsPrefix')]",
"addonProfiles": {
"httpApplicationRouting": {
"enabled": "[parameters('kubernetes_enableHttpApplicationRouting')]"
},
"omsagent": {
"enabled": "[parameters('kubernetes_enableOmsAgent')]",
"config": {
"logAnalyticsWorkspaceResourceID": "[parameters('log_analytics_workspaceId')]"
}
}
},
"agentPoolProfiles": [
{
"name": "agentpool",
"osDiskSizeGB": "[parameters('kubernetes_osDiskSizeGB')]",
"osType": "[parameters('kubernetes_osType')]",
"count": "[parameters('kubernetes_agentCount')]",
"vmSize": "[parameters('kubernetes_agentVMSize')]",
"storageProfile": "ManagedDisks",
"maxPods": "[parameters('kubernetes_maxPods')]"
}
],
"servicePrincipalProfile": {
"ClientId": "[parameters('kubernetes_servicePrincipalClientId')]",
"Secret": "[parameters('kubernetes_servicePrincipalClientSecret')]"
},
"networkProfile": {
"networkPlugin": "[parameters('kubernetes_networkPlugin')]"
}
},
"tags": {
"Environment": "[parameters('environment')]"
}
},
{
"comments": "Azure Log Analytics (Container Insights)",
"type": "Microsoft.Resources/deployments",
"name": "SolutionDeployment",
"apiVersion": "2017-05-10",
"resourceGroup": "[split(parameters('log_analytics_workspaceId'),'/')[4]]",
"subscriptionId": "[split(parameters('log_analytics_workspaceId'),'/')[2]]",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
"apiVersion": "2015-11-01-preview",
"type": "Microsoft.OperationsManagement/solutions",
"location": "[parameters('log_analytics_location')]",
"name": "[concat('ContainerInsights', '(', split(parameters('log_analytics_workspaceId'),'/')[8], ')')]",
"properties": {
"workspaceResourceId": "[parameters('log_analytics_workspaceId')]"
},
"plan": {
"name": "[concat('ContainerInsights', '(', split(parameters('log_analytics_workspaceId'),'/')[8], ')')]",
"product": "[concat('OMSGallery/', 'ContainerInsights')]",
"promotionCode": "",
"publisher": "Microsoft"
}
}
]
}
},
"dependsOn": [
"[concat('Microsoft.Resources/deployments/', 'WorkspaceDeployment')]"
],
"tags": {
"Environment": "[parameters('environment')]"
}
},
{
"comments": "Azure Log Analytics",
"type": "Microsoft.Resources/deployments",
"name": "WorkspaceDeployment",
"apiVersion": "2017-05-10",
"resourceGroup": "[split(parameters('log_analytics_workspaceId'),'/')[4]]",
"subscriptionId": "[split(parameters('log_analytics_workspaceId'),'/')[2]]",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
"apiVersion": "2015-11-01-preview",
"type": "Microsoft.OperationalInsights/workspaces",
"location": "[parameters('log_analytics_location')]",
"name": "[parameters('log_analytics_workspaceName')]",
"properties": {
"sku": {
"name": "[parameters('log_analytics_sku')]"
}
}
}
]
}
},
"tags": {
"Environment": "[parameters('environment')]"
}
}
],
"outputs": {
"controlPlaneFQDN": {
"type": "string",
"value": "[reference(concat('Microsoft.ContainerService/managedClusters/', parameters('kubernetes_name'))).fqdn]"
}
}
}
Unfortunately you cannot create Service Principals in ARM templates.
I create them using PowerShell scripts and then either pass the relevant properties in to the ARM Template as parameters, or push them in to KeyVault and reference them from KeyVault where supported by the relevant ARM Template.