Related
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 am new to ARM templates and I have the following issue:
I have an ARM template which creates an API Management service and I want this API Management service to use Log Analytics workspace in order to store it's logs there.
I have already created a log analytics workspace resource.
So, according to Microsoft documentation: https://learn.microsoft.com/en-us/azure/azure-monitor/essentials/resource-manager-diagnostic-settings
the only thing I need to do is to edit the API management ARM template and include a new resource:
"type": "Microsoft.Insights/diagnosticSettings"
but when I do that, I get the following error:
"Values must be one of the following values......" getting a long long list.
Am I doing something wrong here?
thank you for your time!
If we want to create a diagnostic setting for an Azure API Management resource, we can add a resource of type Microsoft.ApiManagement/service/providers/diagnosticSettings to the template.
For example
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"publisherEmail": {
"type": "string",
"minLength": 1,
"metadata": {
"description": "The email address of the owner of the service"
},
"defaultValue": "test#gmail.com"
},
"publisherName": {
"type": "string",
"minLength": 1,
"metadata": {
"description": "The name of the owner of the service"
},
"defaultValue": "test",
},
"sku": {
"type": "string",
"defaultValue": "Developer",
"allowedValues": [
"Developer",
"Standard",
"Premium"
],
"metadata": {
"description": "The pricing tier of this API Management service"
}
},
"skuCount": {
"type": "string",
"defaultValue": "1",
"allowedValues": [
"1",
"2"
],
"metadata": {
"description": "The instance size of this API Management service."
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
}
},
"variables": {
"apiManagementServiceName": "[concat('myapiservice', uniqueString(resourceGroup().id))]"
},
"resources": [{
"type": "Microsoft.ApiManagement/service",
"apiVersion": "2019-12-01",
"name": "[variables('apiManagementServiceName')]",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('sku')]",
"capacity": "[parameters('skuCount')]"
},
"properties": {
"publisherEmail": "[parameters('publisherEmail')]",
"publisherName": "[parameters('publisherName')]"
}
}, {
"type": "Microsoft.ApiManagement/service/providers/diagnosticSettings",
"apiVersion": "2017-05-01-preview",
"name": "[concat(variables('apiManagementServiceName'), '/Microsoft.Insights/', 'mytest')]",
"dependsOn": ["[resourceId('Microsoft.ApiManagement/service', variables('apiManagementServiceName'))]"],
"properties": {
"logs": [{
"category": "GatewayLogs",
"enabled": true,
}
],
"metrics": [{
"enabled": true,
"category": "AllMetrics"
}
],
"workspaceId": "<the resource id of workspace>",
}
}
]
}
I'm trying to assign the role to 'Cosmos Db account' by using following template.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"principalId": {
"type": "string",
"defaultValue": "gb9e32f1-678f-4552-ae0a-0000f765aaaa",
"metadata": {
"description": ""
}
},
"CosmosDbAccountName": {
"type": "string",
"defaultValue": "cosmosdbaccount",
"metadata": {
"description": "Cosmos Db Account name"
}
},
"RoleType": {
"defaultValue" : "Contributor",
"type": "string",
"metadata": {
"description": "Built-in role to assign"
},
"allowedValues" : [
"Contributor"
]
}
},
"variables": {
"Scope": "[concat(parameters('CosmosDbAccountName'),'/Microsoft.Authorization/',guid(subscription().subscriptionId))]"
},
"resources": [
{
"type": "Microsoft.DocumentDB/databaseAccounts/providers/roleAssignments",
"name": "[variables('Scope')]",
"apiVersion":"2020-04-01-preview",
"properties": {
"RoleDefinitionId":"/subscriptions/[subscription().subscriptionId]/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c",
"principalId": "[parameters('principalId')]"
}
}
]
}
I am currently getting error as
{"code":"DeploymentFailed","message":"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.","details":[{"code":"BadRequest","message":"{\r\n "error": {\r\n "code": "RoleAssignmentUpdateNotPermitted",\r\n "message": "Tenant ID, application ID, principal ID, and scope are not allowed to be updated."\r\n }\r\n}"}]}
I think there is existing role assignment with the same name that you are trying to create through this template and it ends up giving the error for "RoleAssignmentUpdateNotPermitted".
Few changes to your template can solve your problem like generating a unique GUID and then concat it with cosmos DB account name, Please try the below updated template:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"principalId": {
"type": "string",
"defaultValue": "gb9e32f1-678f-4552-ae0a-0000f765aaaa",
"metadata": {
"description": ""
}
},
"CosmosDbAccountName": {
"type": "string",
"defaultValue": "cosmosdbaccount",
"metadata": {
"description": "Cosmos Db Account name"
}
},
"RoleType": {
"defaultValue" : "Contributor",
"type": "string",
"metadata": {
"description": "Built-in role to assign"
},
"allowedValues" : [
"Contributor"
]
},
"guid": {
"defaultValue": "[newGuid()]",
"type": "String"
}
},
"variables": {
"Scope": "[concat(parameters('CosmosDbAccountName'),'/Microsoft.Authorization/', parameters('guid'))]"
},
"resources": [
{
"type": "Microsoft.DocumentDB/databaseAccounts/providers/roleAssignments",
"name": "[variables('Scope')]",
"apiVersion":"2020-04-01-preview",
"properties": {
"RoleDefinitionId":"/subscriptions/[subscription().subscriptionId]/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c",
"principalId": "[parameters('principalId')]"
}
}
]
}
via portal, I can define an Event Subscription in the Storage Account, at the End I have such a view in the portal:
Now I would like to do the same with ARM-Template, I have the following Code:
{
"type": "Microsoft.EventGrid/topics/providers/eventSubscriptions",
"name": "[concat(variables('StorageAccountName'),'/Microsoft.EventGrid/',variables('EventGridName'))]",
"location": "[parameters('region')]",
"apiVersion": "2018-01-01",
"dependsOn": [ "[resourceId('Microsoft.Web/sites', variables('AzureFunction'))]" ],
"properties": {
"topic": "[concat('Microsoft.EventGrid/topics/',variables('StorageAccountName'))]",
"destination": {
"endpointType": "WebHook",
"properties": {
"topics": "[variables('StorageAccountName')]",
"endpointUrl": "[concat('https://', variables('AzureFunction'),'.azurewebsites.net/admin/extensions/EventGridExtensionConfig')]"
}
}
}
}
after running this code, I get the following error:
Resource Microsoft.EventGrid/topics/providers/eventSubscriptions 'xxxx0prod0sac0xx0we/Microsoft.EventGrid/xxxx-prod-eg-dz-we' failed with message '{
"error": {
"code": "ResourceNotFound",
"message": "The Resource 'Microsoft.EventGrid/topics/xxxx0prod0sac0xx0we' under resource group 'xxxx' was not found."
}
}'
Do you have any idea, what should I do to solve this problem?
#Kaja, Please use the below ARM template to create an Event Subscription in the Storage Account:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageName": {
"type": "string",
"defaultValue": "[concat('storage', uniqueString(resourceGroup().id))]",
"metadata": {
"description": "Provide a unique name for the Blob Storage account."
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Provide a location for the Blob Storage account that supports Event Grid."
}
},
"eventSubName": {
"type": "string",
"defaultValue": "subToStorage",
"metadata": {
"description": "Provide a name for the Event Grid subscription."
}
},
"endpoint": {
"type": "string",
"metadata": {
"description": "Provide the URL for the WebHook to receive events. Create your own endpoint for events."
}
}
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts/providers/eventSubscriptions",
"name": "[concat(parameters('storageName'), '/Microsoft.EventGrid/', parameters('eventSubName'))]",
"apiVersion": "2018-01-01",
"properties": {
"destination": {
"endpointType": "WebHook",
"properties": {
"endpointUrl": "[parameters('endpoint')]"
}
},
"filter": {
"subjectBeginsWith": "",
"subjectEndsWith": "",
"isSubjectCaseSensitive": false,
"includedEventTypes": [
"All"
]
}
}
}
]
}
Reference: https://github.com/Azure/azure-quickstart-templates/blob/master/101-event-grid-subscription-and-storage/azuredeploy.json
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.