title: How to use ARM templates to deploy a roleAssignment for an App Registration Service Principal?
body: <p>In my current project I'm working with pre-created App Registration Service Principals in Azure AD. I'm using an ARM template to create a StorageV2 account plus some blob containers, then create a roleAssignment giving Storage Blob Contributor rights to one of the Service Principals. The relevant section of the ARM template is at the end of this post.</p>
  
  <p>What I've found is that if I take the <code>ObjectId</code> of a regular AD user, such as myself or my colleague, and set that as <code>PrincipalId</code>, the script runs correctly. However, I can't get this to work with a Service Principal.</p>
  
  <p>If I use the Service Principal's <code>ObjectId</code>, then I get the following error:</p>
  
  <pre><code>Deployment failed. Correlation ID: 40e0c146-165a-47c0-b022-ac04781d8194. {
    "error": {
      "code": "PrincipalTypeNotSupported",
      "message": "Principals of type Application cannot validly be used in role assignments."
    }
  }
  </code></pre>
  
  <p>Having spotted some suggestions for Azure Powershell users that I should use Application (Client) Id instead, I tried that, but get the following error (Guids redacted):</p>
  
  <pre><code>Deployment failed. Correlation ID: 5c725a51-230a-4d85-bb61-b2f4cdf849ff. {
    "error": {
      "code": "PrincipalNotFound",
      "message": "Principal 9f****30 does not exist in the directory db****75."
    }
  }
  </code></pre>
  
  <p>So the <code>ObjectId</code> it can find but not use, and the <code>ClientId</code> it can't find.</p>
  
  <p>I have found that if I use Azure Powershell and use the <code>New-AzureRmRoleAssignment</code> command, I can reproduce the <code>PrincipalTypeNotSupported</code> error by providing the Service Principal's <code>ObjectId</code> to the <code>-ObjectId</code> switch. However, that command also has a <code>-ServicePrincipalName</code> switch as an alternative, and if I give that the Service Principal's <code>ClientId</code>, it works!</p>
  
  <p>Is there any equivalent of <code>-ServicePrincipalName</code> for the ARM templates, and if not, is there any other way to achieve this? I can use Azure Powershell as a workaround, but it's messier than I'd like.</p>
  
  <p>If this is a feature gap, where's the best place to report it?</p>
  
  <p>Relevant section of ARM template follows:</p>
  
  <pre><code>"resources": [
      {
          "name": "[variables('storageAccountName')]",
          "type": "Microsoft.Storage/storageAccounts",
          "location": "[resourceGroup().location]",
          "apiVersion": "2018-07-01",
          "sku": {
              "name": "[parameters('storageAccountSku')]"
          },
          "dependsOn": [],
          "tags": {
              "displayName": "Storage Account"
          },
          "kind": "StorageV2",
          "properties": {
              "accessTier": "Hot",
              "supportsHttpsTrafficOnly": true,
              "networkAcls": {
                  "bypass": "AzureServices",
                  "virtualNetworkRules": [],
                  "ipRules": [],
                  "defaultAction": "Deny"
              }
          },
          "resources": [
              {
                  "type": "blobServices/containers",
                  "name": "[concat('default/', variables('myBlobContainerName'))]",
                  "apiVersion": "2018-07-01",
                  "dependsOn": [
                      "[variables('storageAccountName')]"
                  ],
                  "resources": [
                      {
                          "type": "Microsoft.Authorization/roleAssignments",
                          "name": "[variables('myRoleAssignmentGuid')]",
                          "apiVersion": "2018-07-01",
                          "properties": {
                              "roleDefinitionId": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/ba92f5b4-2d11-453d-a403-e96b0029c9fe')]",
                              "principalId": "[variables('myPrincipalId')]"
                          },
                          "dependsOn": [
                              "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'), '/blobServices/default/containers/', variables('myBlobContainerName'))]"
                          ]
                      }
                  ]
              }
          ]
      }
  ]
  </code></pre>