Sometimes ARM template will throw PrincipalNotFound Error when Working with User-assigned Managed Identity - azure

So, I am trying to do the following with an ARM template:
Create a new User-assigned Managed Identity (my-managed-identity) in Resource Group my-rg
Assign my-managed-identity the Reader role for my-rg
Assign the role Managed Identity Operator to an AKS Service Principal (my-aks-sp) in my-managed-id
Here is my ARM template to do so:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"aksServicePrincipalObjectId": {
"type": "string",
"metadata": {
"description": "The Object Id for the AKS Cluster Service Principal"
}
},
},
"variables": {
"managedIdentityName": "my-managed-identity",
"readerRole": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]",
"managedIdOperatorRole": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'f1a07417-d97a-45cb-824c-7a7467783830')]"
},
"resources": [
{
"type": "Microsoft.ManagedIdentity/userAssignedIdentities",
"name": "[variables('managedIdentityName')]",
"apiVersion": "2018-11-30",
"location": "[resourceGroup().location]",
"resources": [
{
"type": "Microsoft.ManagedIdentity/userAssignedIdentities/providers/roleAssignments",
"name": "[concat(variables('managedIdentityName'), '/Microsoft.Authorization/', guid(parameters('aksServicePrincipalObjectId')))]",
"apiVersion": "2018-09-01-preview",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.ManagedIdentity/userAssignedIdentities/', variables('managedIdentityName'))]"
],
"properties": {
"roleDefinitionId": "[variables('managedIdOperatorRole')]",
"principalId": "[parameters('aksServicePrincipalObjectId')]"
}
}
]
},
{
"type": "Microsoft.Authorization/roleAssignments",
"name": "[guid(variables('managedIdentityName'))]",
"apiVersion": "2018-09-01-preview",
"dependsOn": [
"[concat('Microsoft.ManagedIdentity/userAssignedIdentities/', variables('managedIdentityName'))]"
],
"properties": {
"roleDefinitionId": "[variables('readerRole')]",
"principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('managedIdentityName')),'2018-11-30').principalId]"
}
}
]
}
The weird thing is that sometimes this deployment doesn't work. I will more often than not get the error:
New-AzResourceGroupDeployment : 2:56:07 PM - Resource Microsoft.Authorization/roleAssignments 'd62bb9a1-bf0b-5a92-aca1-74beab087ee9' failed with message '{
"error": {
"code": "PrincipalNotFound",
"message": "Principal fad453d06bd042148411606b74525ed2 does not exist in the directory 936529098-bafa-4c91-b54f-f012cc11eeec."
}
}
Am I missing something here?

This documentation from Microsoft solved my problem.
Here is my complete template:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"aksServicePrincipalObjectId": {
"type": "string",
"metadata": {
"description": "The Object Id for the AKS Cluster Service Principal"
}
},
},
"variables": {
"managedIdentityName": "my-managed-identity",
"readerRole": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]",
"managedIdOperatorRole": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'f1a07417-d97a-45cb-824c-7a7467783830')]"
},
"resources": [
{
"type": "Microsoft.ManagedIdentity/userAssignedIdentities",
"name": "[variables('managedIdentityName')]",
"apiVersion": "2018-11-30",
"location": "[resourceGroup().location]",
"resources": [
{
"type": "Microsoft.ManagedIdentity/userAssignedIdentities/providers/roleAssignments",
"name": "[concat(variables('managedIdentityName'), '/Microsoft.Authorization/', guid(parameters('aksServicePrincipalObjectId')))]",
"apiVersion": "2018-09-01-preview",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.ManagedIdentity/userAssignedIdentities/', variables('managedIdentityName'))]"
],
"properties": {
"roleDefinitionId": "[variables('managedIdOperatorRole')]",
"principalId": "[parameters('aksServicePrincipalObjectId')]",
"principalType": "ServicePrincipal" // This solved my issue
}
}
]
},
{
"type": "Microsoft.Authorization/roleAssignments",
"name": "[guid(variables('managedIdentityName'))]",
"apiVersion": "2018-09-01-preview",
"dependsOn": [
"[concat('Microsoft.ManagedIdentity/userAssignedIdentities/', variables('managedIdentityName'))]"
],
"properties": {
"roleDefinitionId": "[variables('readerRole')]",
"principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('managedIdentityName')),'2018-11-30').principalId]",
"scope": "[resourceGroup().id]" //This is what I added to get it to work!
}
}
]
}

Related

Azure ARM Template, assign multiple roles to managed identity in Automation Account

I try to build an ARM Template to create Automation Account with System Managed Identity, and in the same template add role assignment on the Subscription level to that System Managed Identity. The code I use is:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"AutomationAccountName": {
"type": "string",
"metadata": {
"description": "Automation account name"
}
},
"AutomationAccountProductTag": {
"type": "string",
"metadata": {
"description": "Automation account Product tag"
}
},
"AutomationAccountOwnerTag": {
"type": "string",
"metadata": {
"description": "Automation account Owner tag"
}
},
"WindowsRunbookName": {
"type": "string",
"metadata": {
"description": "Runbook name for Windows instances"
}
},
"RolesToAssignForMangedIdentity": {
"type": "array",
"defaultValue": [
{
"name": "StorageQueueDataContributor",
"role": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]"
},
{
"name": "Contributor",
"role": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]"
},
{
"name": "StorageBlobDataContributor",
"role": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]"
},
{
"name": "VirtualMachineContributor",
"role": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c')]"
}
]
}
},
"variables": {
"WindowsRunbookURL": "https://infraawsssmagentinstall.blob.core.windows.net/awsssmagentfiles/Runbook_install_ssm_windows.ps1",
"LinuxRunbookURL": "",
"RunbookRuntime": "5.1"
},
"resources": [
// create automation account //
{
"type": "Microsoft.Automation/automationAccounts",
"apiVersion": "2021-06-22",
"name": "[parameters('AutomationAccountName')]",
"location": "[resourceGroup().location]",
"tags": {
"Product": "[parameters('AutomationAccountProductTag')]",
"Owner": "[parameters('AutomationAccountOwnerTag')]"
},
"identity": {
"type": "SystemAssigned"
},
"properties": {
"sku": {
"name": "Basic"
}
}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2021-04-01",
"name": "[concat(parameters('RolesToAssignForMangedIdentity')[copyIndex()].name, '_' , guid(parameters('RolesToAssignForMangedIdentity')[copyIndex()].name)) ]",
"copy": {
"name": "RolesCopy",
"count": "[length(parameters('RolesToAssignForMangedIdentity'))]"
},
"properties": {
"mode": "Incremental",
"expressionEvaluationOptions": {
"scope": "outer"
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Automation/automationAccounts/providers/roleAssignments",
"apiVersion": "2021-04-01-preview",
"name": "[concat( parameters('AutomationAccountName'), '/Microsoft.Authorization/', guid(parameters('RolesToAssignForMangedIdentity')[copyIndex()].name))]",
"properties": {
"roleDefinitionId": "[parameters('RolesToAssignForMangedIdentity')[copyIndex()].role]",
"principalId": "[reference(resourceId('Microsoft.Automation/automationAccounts', parameters('AutomationAccountName')), '2021-06-22', 'full').identity.principalId]",
"principalType": "ServicePrincipal"
}
}
]
}
}
}
// assigne roles to created managed identity from automation account
],
"outputs": {}
}
It is adding the role but only for that Automation Account like in picture below:
And what I need is:
I tested your code in my environment and it gave me the same output as below:
Solution:
You have to use "type": "Microsoft.Authorization/roleAssignments" instead of "type": "Microsoft.Automation/automationAccounts/providers/roleAssignments". Also in Nested template you have to add "subscriptionId":"yoursubID" & "location": "any location".
After you have made the above changes your Template will be like below:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"AutomationAccountName": {
"type": "string",
"metadata": {
"description": "Automation account name"
},
"defaultValue": "ansumantestautomation"
},
"AutomationAccountProductTag": {
"type": "string",
"metadata": {
"description": "Automation account Product tag"
},
"defaultValue":"Test"
},
"AutomationAccountOwnerTag": {
"type": "string",
"metadata": {
"description": "Automation account Owner tag"
},
"defaultValue":"Ansuman"
},
"RolesToAssignForMangedIdentity": {
"type": "array",
"defaultValue": [
{
"name": "StorageQueueDataContributor",
"role": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')]"
},
{
"name": "Contributor",
"role": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]"
},
{
"name": "StorageBlobDataContributor",
"role": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]"
},
{
"name": "VirtualMachineContributor",
"role": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c')]"
}
]
}
},
"resources": [
// create automation account //
{
"type": "Microsoft.Automation/automationAccounts",
"apiVersion": "2021-06-22",
"name": "[parameters('AutomationAccountName')]",
"location": "[resourceGroup().location]",
"tags": {
"Product": "[parameters('AutomationAccountProductTag')]",
"Owner": "[parameters('AutomationAccountOwnerTag')]"
},
"identity": {
"type": "SystemAssigned"
},
"properties": {
"sku": {
"name": "Basic"
}
}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2021-04-01",
"subscriptionId":"94xxx4068-xxxx-xxxx-xxxxx-e00a8xxxx59b",
"location": "East US",
"name": "[concat(parameters('RolesToAssignForMangedIdentity')[copyIndex()].name, '_' , guid(parameters('RolesToAssignForMangedIdentity')[copyIndex()].name)) ]",
"copy": {
"name": "RolesCopy",
"count": "[length(parameters('RolesToAssignForMangedIdentity'))]"
},
"dependsOn":[
"[resourceId('Microsoft.Automation/automationAccounts', parameters('AutomationAccountName'))]"
],
"properties": {
"mode": "Incremental",
"expressionEvaluationOptions": {
"scope": "outer"
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2020-04-01-preview",
"name": "[guid(parameters('RolesToAssignForMangedIdentity')[copyIndex()].name)]",
"properties": {
"roleDefinitionId": "[parameters('RolesToAssignForMangedIdentity')[copyIndex()].role]",
"principalId": "[reference(resourceId('Microsoft.Automation/automationAccounts', parameters('AutomationAccountName')), '2021-06-22', 'full').identity.principalId]",
"principalType": "ServicePrincipal"
}
}
]
}
}
}
// assigne roles to created managed identity from automation account
],
"outputs": {}
}
Outputs:
Note: While using the above Template you have to give the SubscriptionId instead of using [subscription().id] otherwise it will error in finding the subscription.

How to add msi scope to another RG in azure using templates

I have a MSI in 'x' RG. I am able to set its scope to the RG.
Question is- I want to add the MSI scope to another RG - "xx" as well using templates. Below is my template snippet:
"type": "Microsoft.ManagedIdentity/userAssignedIdentities",
"name": "[variables('msi_name')]",
"apiVersion": "2018-11-30",
"location": "[resourceGroup().location]",
},
{
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2018-12-01-preview",
"name": "[guid(resourceGroup().id)]",
"dependsOn": [
"vmsCopy",
"[concat('Microsoft.ManagedIdentity/userAssignedIdentities/', variables('msi_name'))]"
],
"properties": {
"roleDefinitionId": "[variables(parameters('roleType'))]",
"principalId": "[reference(concat('Microsoft.ManagedIdentity/userAssignedIdentities/',variables('msi_name'))).principalId]",
"scope": "resourceGroup().id"
}
},
{
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2018-12-01-preview",
"name": "[concat(guid(concat(resourceGroup().id),'_1'))]",
"dependsOn": [
"vmsCopy",
"[concat('Microsoft.ManagedIdentity/userAssignedIdentities/', variables('msi_name'))]"
],
"properties": {
"roleDefinitionId": "[variables(parameters('roleType'))]",
"principalId": "[reference(concat('Microsoft.ManagedIdentity/userAssignedIdentities/',variables('msi_name'))).principalId]",
"scope": "[concat('/subscriptions/',subscription().subscriptionId,'/resourcegroups/','xx')]"
}
}
Getting following error everytime -
/subscriptions//resourceGroups/xx' must match the scope specified on the URI '/subscriptions//resourcegroups/x'."
Both RGs are in same subscription.
you need to wrap the second role assignment with a deployment into another rg:
{
"type": "Microsoft.Resources/deployments",
"name": "subnet-role-assignment",
"apiVersion": "2017-05-10",
"resourceGroup": "second_rg_name",
"dependsOn": [
"vmsCopy",
"[concat('Microsoft.ManagedIdentity/userAssignedIdentities/', variables('msi_name'))]"
],
"expressionEvaluationOptions": {
"scope": "inner"
},
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2018-12-01-preview",
"name": "[concat(guid(concat(resourceGroup().id),'_1'))]",
"properties": {
"roleDefinitionId": "[variables(parameters('roleType'))]",
"principalId": "[reference(resourceId('first_rg_name', 'Microsoft.ManagedIdentity/userAssignedIdentities/', variables('msi_name'))).principalId]",
"scope": "[resourceGroup().id]"
}
}
]
}
}
}

ARM Template - Set dependency on RBAC Role existing

I am able to grant my SQL Server Identity membership of the Storage Blob Contributor role on my storage account using an ARM template.
However, when creating my Audit resource (which has dependsOn references to both the Storage Account and to the SQL Server) it looks like it is trying to create this before the RBAC permission has been granted as I get
{
"status": "Failed",
"error": {
"code": "ResourceDeploymentFailure",
"message": "The resource operation completed with terminal provisioning state 'Failed'.",
"details": [
{
"code": "BlobAuditingInsufficientStorageAccountPermissions",
"message": "Insufficient read or write permissions on storage account 'myStorage'. Add permissions to the server Identity to the storage account."
}
]
}
}
Oddly, I have this for Vulnerability Scans from the same server to another Storage Account and this succeeded. I don't know if that was simply a quirk of the way that Azure decided to order the deployment.
Anyway, is there a way to add a dependsOn reference to the RBAC permission so that I don't try to create the Audit destination to Storage until it has permissions?
To be clear, the RBAC assignment is a sub-resource of the Storage Account:
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"name": "[variables('auditStorageAccount')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[variables('uniqueSQLName')]"
],
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "StorageV2",
"properties": {
"isHnsEnabled": false,
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [],
"ipRules": [],
"defaultAction": "Deny"
},
"supportsHttpsTrafficOnly": true,
"encryption": {
"services": {
"file": {
"keyType": "Account",
"enabled": true
},
"blob": {
"keyType": "Account",
"enabled": true
}
},
"keySource": "Microsoft.Storage"
},
"accessTier": "Hot"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts/providers/roleAssignments",
"apiVersion": "2020-03-01-preview",
"name": "[concat(variables('auditStorageAccount'), '/Microsoft.Authorization/', guid(uniqueString(variables('auditStorageAccount'))))]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('auditStorageAccount'))]",
"[resourceId('Microsoft.Sql/servers', variables('uniqueSQLName'))]"
],
"properties": {
"roleDefinitionId": "[variables('StorageBlobContributor')]",
"principalId": "[reference(resourceId('Microsoft.Sql/servers', variables('uniqueSQLName')), '2019-06-01-preview', 'Full').identity.principalId]",
"scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('auditStorageAccount'))]",
"principalType": "ServicePrincipal"
}
}
]
}
My assumption was that having it as a sub-resource would ensure that it was in place for anything that then had a dependsOn to the Storage Account
According to the error, I think when you deploy the SQL audit log resource, the assigned role action does not complete successfully.So We need to define in the template that the audit log resource depends on the role assignment actions
For example
My template.json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"sqlServerName": {
"type": "string",
"defaultValue": "[concat('sql-', uniqueString(resourceGroup().id))]",
"metadata": {
"description": "Name of the SQL server"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
},
"sqlAdministratorLogin": {
"type": "string",
"defaultValue":"sqladmin",
"metadata": {
"description": "The administrator username of the SQL Server."
}
},
"sqlAdministratorLoginPassword": {
"type": "securestring",
"defaultValue":"Password0123!",
"metadata": {
"description": "The administrator password of the SQL Server."
}
},
"storageAccountName": {
"type": "string",
"defaultValue": "[concat('sqlaudit', uniqueString(resourceGroup().id))]",
"metadata": {
"description": "The name of the auditing storage account."
}
}
},
"variables": {
"StorageBlobContributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]",
"uniqueRoleGuid": "[guid(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), variables('storageBlobContributor'), resourceId('Microsoft.Sql/servers', parameters('sqlServerName')))]"
},
"resources": [{
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('storageAccountName')]",
"apiVersion": "2019-06-01",
"location": "[parameters('location')]",
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2",
"properties": {
"networkAcls": {
"bypass": "AzureServices",
"defaultAction": "Allow"
}
},
"resources": [{
"type": "Microsoft.Storage/storageAccounts/providers/roleAssignments",
"apiVersion": "2020-03-01-preview",
"name": "[concat(parameters('storageAccountName'), '/Microsoft.Authorization/', variables('uniqueRoleGuid'))]",
"dependsOn": [
"[resourceId('Microsoft.Sql/servers', parameters('sqlServerName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
],
"properties": {
"roleDefinitionId": "[variables('StorageBlobContributor')]",
"principalId": "[reference(resourceId('Microsoft.Sql/servers', parameters('sqlServerName')), '2019-06-01-preview', 'Full').identity.principalId]",
"scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]",
"principalType": "ServicePrincipal"
}
}
]
}, {
"type": "Microsoft.Sql/servers",
"apiVersion": "2019-06-01-preview",
"location": "[parameters('location')]",
"name": "[parameters('sqlServerName')]",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"administratorLogin": "[parameters('sqlAdministratorLogin')]",
"administratorLoginPassword": "[parameters('sqlAdministratorLoginPassword')]",
"version": "12.0"
},
"tags": {
"displayName": "[parameters('sqlServerName')]"
},
"resources": [{
"type": "auditingSettings",
"apiVersion": "2019-06-01-preview",
"name": "DefaultAuditingSettings",
"dependsOn": [
"[parameters('sqlServerName')]",
"[parameters('storageAccountName')]",
"[extensionResourceId(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), 'Microsoft.Authorization/roleAssignments/', variables('uniqueRoleGuid'))]"
],
"properties": {
"state": "Enabled",
"storageEndpoint": "[reference(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').PrimaryEndpoints.Blob]",
"storageAccountAccessKey": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').keys[0].value]",
"auditActionsAndGroups": [
"SUCCESSFUL_DATABASE_AUTHENTICATION_GROUP",
"FAILED_DATABASE_AUTHENTICATION_GROUP",
"BATCH_COMPLETED_GROUP"
],
"storageAccountSubscriptionId": "[subscription().subscriptionId]",
"isStorageSecondaryKeyInUse": false
}
}
]
}
]
}
Deploy
New-AzResourceGroupDeployment -ResourceGroupName <resource-group-name> -TemplateFile <path-to-template>
For more details, please refer to the sample

Reference listKeys() in nested templates

I am creating an ARM template that deploys a lot of resources in different resource groups. Actually, the resource groups themselves are part of the deployment. In a simple version, I create only two resource groups (masterRG and dependentRG), and then create two nested (inline) deployments. The first inline deployment puts a storage account (testsadj1604) in masterRG. This deployment is dependent on masterRG.
The second deployment creates a keyvault and tries to store a connectionstring from testsadj1604 in that vault.
In my real case, I have more resourceGroups and I actually try deploy a Function App that has the connectionstring as 'appsetting'. The methodology is the same though.
The error I get is the following:
Deployment failed. Correlation ID: 9c359e8e-8657-4756-a5a3-f9c5698fbb46. {
"error": {
"code": "ResourceNotFound",
"message": "The Resource 'Microsoft.Storage/storageAccounts/testsadj1604' under resource group '<null>' was not found."
}
}
This is my code:
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"resources": [
{
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2018-05-01",
"name": "masterRG",
"location": "West Europe",
"properties": {}
},
{
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2018-05-01",
"name": "dependentRG",
"location": "West Europe",
"properties": {}
},
{
"name": "masterRgDeployment",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2019-10-01",
"resourceGroup": "masterRG",
"dependsOn": [
"masterRG"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"apiVersion": "2019-06-01",
"type": "Microsoft.Storage/storageAccounts",
"name": "testsadj1604",
"location": "West Europe",
"sku": {
"name": "Standard_GRS"
},
"kind": "StorageV2",
"properties": {
"supportsHttpsTrafficOnly": true
}
}
]
}
}
},
{
"name": "dependentRgDeployment",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2019-10-01",
"resourceGroup": "dependentRG",
"dependsOn": [
"dependentRG",
"masterRgDeployment"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.KeyVault/vaults",
"name": "kvaNameTest1604",
"apiVersion": "2015-06-01",
"location": "West Europe",
"properties": {
"enabledForDeployment": false,
"enabledForDiskEncryption": false,
"enabledForTemplateDeployment": true,
"tenantId": "[subscription().tenantId]",
"accessPolicies": [
{
"objectId": "fc05639d-70eb-4175-a89b-eab7f883c691",
"tenantId": "[subscription().tenantId]",
"permissions": {
"keys": [
"get",
"list",
"update"
],
"secrets": [
"get",
"list",
"update"
]
}
}
],
"sku": {
"name": "Standard",
"family": "A"
},
"networkAcls": {
"defaultAction": "Allow",
"bypass": "AzureServices"
}
}
},
{
"type": "Microsoft.KeyVault/vaults/secrets",
"name": "kvaNameTest1604/saConnectionString",
"apiVersion": "2018-02-14",
"location": "West Europe",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', 'kvaNameTest1604')]"
],
"properties": {
"value": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', 'testsadj1604'), '2019-06-01').keys[0].value]"
}
}
]
}
}
}
]
}
I am pretty sure the error comes from the listKeys() at the bottom, going on my daylong trial-and-error (and Google frenzy) in my real template. Using listKeys() and nested deployments is a drag, but I really don't see why it shouldn't work. I made sure there is a dependsOn in the second deployment.
This is wrecking my brain, is there any way I can use nested (inline) templates and reference the storage account keys that are in a different resourcegroup (but part of the overall deployment)? I also tried to create an output in the first deployment and reference that in the second but that had no effect. I am at a total loss, any help is welcome!
There are a few things you need to do for this to work in a single template:
on your keyvault secret deployment set this property:
"expressionEvaluationOptions": {
"scope": "inner"
},
That will delay evaluation of the expression until that deployment begins.
when you set #1, you need to define parameters for the values you need (you can no longer use "global" params/vars), you could hardcode all the strings like in your example, but I'm guessing that's not what you do in the "real" deployment. Define the params and pass the values into that deployment.
your listKeys() call needs to include the full resourceId of the storageAccount, since it is in a separate/distinct deployment - so you need to provide the resourceGroup name param - if you cross subscriptions in the deployment (your sample didn't) you need to provide the subscriptionId param.
Below is a working example...
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountName": {
"type": "string",
"defaultValue": "[concat('scratch', uniqueString(newGuid()))]"
}
},
"resources": [
{
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2018-05-01",
"name": "masterRG",
"location": "West Europe",
"properties": {
}
},
{
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2018-05-01",
"name": "dependentRG",
"location": "West Europe",
"properties": {
}
},
{
"name": "masterRgDeployment",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2019-10-01",
"resourceGroup": "masterRG",
"dependsOn": [
"masterRG"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"apiVersion": "2019-06-01",
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('storageAccountName')]",
"location": "West Europe",
"sku": {
"name": "Standard_GRS"
},
"kind": "StorageV2",
"properties": {
"supportsHttpsTrafficOnly": true
}
}
]
}
}
},
{
"name": "dependentRgDeployment",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2019-10-01",
"resourceGroup": "dependentRG",
"dependsOn": [
"dependentRG",
"masterRgDeployment"
],
"properties": {
"mode": "Incremental",
"expressionEvaluationOptions": {
"scope": "inner"
},
"parameters":{
"storageAccountName": {
"value": "[parameters('storageAccountName')]"
},
"storageAccountResourceGroupName": {
"value": "masterRG"
}
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountName": {
"type": "string"
},
"storageAccountResourceGroupName": {
"type": "string"
}
},
"variables": {
"vaultName": "[concat('kv-', parameters('storageAccountName'))]"
},
"resources": [
{
"type": "Microsoft.KeyVault/vaults",
"name": "[variables('vaultName')]",
"apiVersion": "2019-09-01",
"location": "West Europe",
"properties": {
"enabledForDeployment": false,
"enabledForDiskEncryption": false,
"enabledForTemplateDeployment": true,
"tenantId": "[subscription().tenantId]",
"accessPolicies": [ ],
"sku": {
"name": "Standard",
"family": "A"
},
"networkAcls": {
"defaultAction": "Allow",
"bypass": "AzureServices"
}
}
},
{
"type": "Microsoft.KeyVault/vaults/secrets",
"name": "[concat(variables('vaultName'), '/saConnectionString')]",
"apiVersion": "2019-09-01",
"location": "West Europe",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', variables('vaultName'))]"
],
"properties": {
"value": "[listKeys(resourceId(parameters('storageAccountResourceGroupName'),'Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').keys[0].value]"
}
}
]
}
}
}
]
}

Getting issue The request to create role assignment 'xxxx--x-x-x--x-x-x-xxxxxxx' is not valid. Role assignment scope must match the scope specified

I am trying to create storage account, blob storage and then trying to create role on storage account. Below is the code storagedeploy.json:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"Project": {
"type": "string",
"metadata": {
"description": "Project name"
}
},
"Environment": {
"type": "string",
"metadata": {
"description": "Project name"
}
},
"location": {
"type": "string",
"metadata": {
"description": "Location for all resources."
}
}
},
"variables": {
"storageAccountName": "[toLower(concat(parameters('Project'), parameters('Environment'), uniqueString(resourceGroup().id)))]"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-04-01",
"name": "[variables('storageAccountName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "StorageV2",
"properties": {
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [],
"ipRules": [],
"defaultAction": "Allow"
},
"supportsHttpsTrafficOnly": true,
"encryption": {
"services": {
"file": {
"enabled": true
},
"blob": {
"enabled": true
}
},
"keySource": "Microsoft.Storage"
},
"accessTier": "Hot"
}
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices",
"apiVersion": "2019-04-01",
"name": "[concat(variables('storageAccountName'), '/default')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
],
"properties": {
"cors": {
"corsRules": []
},
"deleteRetentionPolicy": {
"enabled": false
}
}
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2019-04-01",
"name": "[concat(variables('storageAccountName'), '/default/mycompany-project123-dev-data-store-ue1')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('storageAccountName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
],
"properties": {
"publicAccess": "None"
}
},
{
"type": "Microsoft.Authorization/roleAssignments",
"name": "[guid(resourceGroup().id)]",
"apiVersion": "2019-04-01-preview",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('storageAccountName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
],
"properties": {
"roleDefinitionId": "[concat(subscription().id, '/providers/Microsoft.Authorization/roleDefinitions/17d1049b-9a84-46fb-8f53-869881c3d3ab')]",
"principalId": "xxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxx",
"scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
}
}
]
}
on execution, i am getting below issue:
PS C:\work\azure\azure-devops\resourcetemplates\staticresources> az group deployment create --resource-group myproject-devops --template-file .\storagedeploy.json
Please provide string value for 'Project' (? for help): ert
Please provide string value for 'Environment' (? for help): fds
Please provide string value for 'location' (? for help): eastus2
Deployment failed. Correlation ID: xxxx-x-x-x-x--x-xxxxxxx. {
"error": {
"code": "InvalidCreateRoleAssignmentRequest",
"message": "The request to create role assignment 'xxxx--x-x-x--x-x-x-sxxssxxx' is not valid. Role assignment scope '/subscriptions/xxxxxxxx3-xxxxxxxd-xxxxxxxd-xxe-xxxxxxxx2/resourceGroups/myproject-devops/providers/Microsoft.Storage/storageAccounts/ertfds5h4nafspjqzii' must match the scope specified on the URI '/subscriptions/xxxxxxxx3-xxxxxxxd-xxxxxxxd-xxe-xxxxxxxx2/resourcegroups/myproject-devops'."
}
}
I tried to google, but getting different solutions. Where exactly i am missing. I tried to follow this issue on stack-overflow
Also, i am trying to assign permission to particular resource like:
To assign to storage, below is code which is working fine:
{
"type": "Microsoft.Storage/storageAccounts/providers/roleAssignments",
"name": "[concat(variables('storageAccountName'),'/Microsoft.Authorization/',guid(subscription().subscriptionId))]",
"apiVersion": "2019-04-01-preview",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('storageAccountName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
],
"properties": {
"roleDefinitionId": "[concat(resourceGroup().id, '/providers/Microsoft.Authorization/roleDefinitions/17d1049b-9a84-46fb-8f53-869881c3d3ab')]",
"principalId": "[parameters('principalId')]",
"scope": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
}
}
But same i need to do with cosmosDB, redis cache, key vault, but its not working, any idea where i am missing. Below are codes:
For cosmosDB::
{
"type": "Microsoft.DocumentDB/databaseAccounts/providers/roleAssignments",
"name": "[concat(variables('cosmosDBAccountName'),'/Microsoft.Authorization/',guid(subscription().subscriptionId))]",
"apiVersion": "2019-04-01-preview",
"dependsOn": [
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', variables('cosmosDBAccountName'), parameters('Project'))]",
"[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDBAccountName'))]"
],
"properties": {
"roleDefinitionId": "[concat(resourceGroup().id, '/providers/Microsoft.Authorization/roleDefinitions/5bd9cd88-fe45-4216-938b-f97437e15450')]",
"principalId": "[parameters('principalId')]",
"scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosDBAccountName'))]"
}
}
For Redis cache::
{
"type": "Microsoft.Cache/Redis/providers/roleAssignments",
"name": "[concat(variables('redisCacheName'),'/Microsoft.Authorization/',guid(subscription().subscriptionId))]",
"apiVersion": "2019-04-01-preview",
"dependsOn": [
"[resourceId('Microsoft.Cache/Redis', variables('redisCacheName'))]"
],
"properties": {
"roleDefinitionId": "[concat(resourceGroup().id, '/providers/Microsoft.Authorization/roleDefinitions/e0f68234-74aa-48ed-b826-c38b57376e17')]",
"principalId": "[parameters('principalId')]",
"scope": "[resourceId('Microsoft.Cache/Redis', variables('redisCacheName'))]"
}
}
For Key vault:
{
"type": "Microsoft.KeyVault/vaults/providers/roleAssignments",
"name": "[concat(variables('keyVaultName'),'/Microsoft.Authorization/',guid(subscription().subscriptionId))]",
"apiVersion": "2019-04-01-preview",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]"
],
"properties": {
"roleDefinitionId": "[concat(resourceGroup().id, '/providers/Microsoft.Authorization/roleDefinitions/f25e0fa2-a7c8-4377-a976-54943a77a395')]",
"principalId": "[parameters('principalId')]",
"scope": "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]"
}
}
this means the role you are trying to assign cannot be assigned to that scope. you should either alter the role to allow it to be assigned to that scope or you should use another role\create a new custom role.
https://learn.microsoft.com/en-us/azure/role-based-access-control/role-definitions#assignablescopes
Made some changes into your json, and it worked on my side now:
{....
.......
......
{
"type": "Microsoft.Authorization/roleAssignments",
"name": "[guid(resourceGroup().id)]",
"apiVersion": "2019-04-01-preview",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('storageAccountName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
],
"properties": {
"roleDefinitionId": "[concat(resourceGroup().id, '/providers/Microsoft.Authorization/roleDefinitions/17d1049b-9a84-46fb-8f53-869881c3d3ab')]",
"principalId": "xxxxxxxxxxxxxxxxxxxxxxxxxx",
"scope": "[resourceGroup().Id]"
}
}
]
}
As the error said, here you should let your roleassignment scope same with your resource group.

Resources