System-assigned and User-assigned Identities in Azure

I recently needed to use managed identities in an Azure-project and decided to try the relatively new user-assigned identities.

If you are not familiar with system-assigned identities, the benefit of them is that you can use them to authorize accesses between Azure services without resorting to client IDs and passwords or other schemes, that could expose secrets.

User-assigned identities are almost the same, but they are not tied to the lifetime of a single service as they are their own, dedicated resource.

You can read more about both here.

Here is an example, how to create an user-assigned identity with Bicep:

resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
  name: parameters.identity
  location: parameters.location
}

output principalId string = userAssignedIdentity.properties.principalId
output clientId string = userAssignedIdentity.properties.clientId
output resourceId string = userAssignedIdentity.id

This means that you can run different Azure services with this same identity and assign it rights etc. If an Azure service using the identity is deleted, it won't affect this identity. A system-assigned identity would be deleted if the associated service is deleted.

After the user-assigned identity is created, it can be assigned in the identity-section of a resource specification.

Here the identity is associated with an Azure Function:

param userIdentityResourceId string

  identity: {
    type:'UserAssigned'
    userAssignedIdentities: {
      '${userIdentityResourceId}': {}     
    }
  }

After deploying this Function, the Function was running with the new identity and everything seemed to be fine.

Identity Crisis

With Azure Functions, a good practice is to use Key Vault -references between the services and a managed identity is needed for them to work properly.

However, even though I had added the user assigned identity to the Key Vault's Access Policies, the Function didn't seem to have an access:

image.png

 accessPolicies: [
      {
        tenantId: subscription().tenantId
        objectId: userIdentityId //User assigned identity
        permissions: {
          secrets: [
            'get'
            'list'
          ]
        }
      }

I rechecked everything, including the Key Vault reference syntax:

@Microsoft.KeyVault(VaultName=keyVaultName;SecretName=DatabaseSettings--ConnectionString)

Finally, I found the reason from this blog post by Dhyanendra Singh Rathor (thanks!):

At the time of writing, Azure Key Vault reference only supports system-assigned managed identities.

So, it seemed that I needed to use System Assigned -identity, after all...

But then I noticed in the Azure Portal, that you could use both System and User Assigned identities at the same time - at least in Azure Functions!

You couldn't tell from the documentation, how to do that in Bicep, but generating the template in the Azure Portal revealed that the syntax is simple enough:

  identity: {
    type:'SystemAssigned, UserAssigned'
    userAssignedIdentities: {
      '${userIdentityResourceId}': {}     
    }
  }

After that, I added the system assigned identity, too, to the Key Vault's Acces Policy collection:

{
        tenantId: subscription().tenantId
        objectId: functionSystemAssignedId 
        permissions: {
          secrets: [
            'get'
            'list'
            ]
          }
        }

After that, the Key Vault reference started to work, as it should:

image.png

I needed to have both, since the user-assigned identity is used to access the SQL Database instance, but that's an another story...

Conclusion

The user-assigned identities are easy to setup and to assign them for various resources. However, some vital areas of Azure still don't support them fully, so system-assigned identity may be needed, too.