Contents
With the introduction of Managed Identities came many security options. Among other things, manual credential management is no longer necessary, this is taken over by Azure.
Different scripts are often required for matters such as operation, provisioning, housekeeping, etc., which need to authenticate and communicate with different API’s in a secury way. Usually, this requires a service principal (Azure AD app registration) secured by a secret or certificate, which in turn should be stored securely and rotated regularly.
What are Managed Identities in Azure?
As the name suggests, Managed Identities are identities, actually service principals, which are managed by Azure, including the key material. That means you don’t have to worry about storing and rotation secrets or certificates, as there is none of that anymore (at least not visible for us).
But wait, if there’s no secrets or certificate, how do I authenticate?
A Managed Identity is always linked to an object. This means that the authenticating object or identity is always the Azure Resource or Managed Identity object, not an app registration with provided credentials. In other words, let’s assume you have an Azure Automation account, on which you run a PowerShell script to gather all current users and groups. You can then enable a (system-assigned) Managed Identity on the Automation account. With that, you can tell Azure AD “hey use this Managed Identity to authenticate” during authentication out of the Automation Account.
There are a few things to keep in mind:
- As you’ve seen above, the authenticating object is the Azure resource or any resource with a Managed Identity object attached. Therefore, anyone with access to the enabled Azure resource is also able to run tasks using the Managed Identity. It’s highly important to secure access to the resource using RBAC.
- You cannot extract credentials or use Managed Identities elsewhere. This makes local development more difficult, since you’re not able to authenticate e.g. within a script you develop locally. Depending on the service, there are other options e.g. VSCode extensions.
There are two types of Managed Identities:
System-assigned
A system-assigned Managed Identity is enabled and attached directly on the resource. It also shares the lifecycle of the resource, which means it will be deleted automatically when the resource is deleted.
User-assigned
As you may have noticed, a system-assigned Managed Identity has a 1:1 relationship with the resource. This can make granting permissions in a complex environment more difficult when you e.g. have identical services for load balancing or many automated deployments, because you need to grant permissions for each managed-identity separately after the resource creation.
Here’s where user-assigned Managed Identities come in handy. User-assigned Managed Identities are standalone Managed Identity objects, which can be assigned to multiple resources. Assume you have a web application consisting of an Application Gateway with three virtual machines as a backend pool. The virtual machines need to access an Azure Key Vault to retrieve secrets. You can then create a user-assigned Managed Identity, grant permissions to it and assign it to each virtual machine instead of enabling a system-assigned Managed Identity on each virtual machines and granting permissions for each.
The usage of system-assigned vs. user-assigned Managed Identites always depends on the architecture, operability and security requirements of your solution.
Lab: How to enable Managed Identities
Managed Identities can be enabled in multiple ways, usually via the Azure Portal, Bicep/ARM, Azure CLI, PowerShell and REST API. There’s already good documentation on how to enable Managed Identities on an Automation Account using the Azure Portal, PowerShell and REST API from Microsoft:
- Using a system-assigned managed identity for an Azure Automation account
- Using a user-assigned managed identity for an Azure Automation account
We will take a deeper look and create an Azure Automation Account including a PowerShell Runbook with which we will fetch and display the token to verify the usage of the Managed Identity.
1. Prerequisites
For this lab you need an active Azure Subscription including Contributor permissions, since we deploy the following resources:
- Resource group
- Automation Account
- Automation Runbook
We create the resource group and the resource deployment using Azure CLI. You can download and install it from here, if you haven’t already: How to install the Azure CLI
All files can be found in my GitHub repository. It’s best to download it briefly and cd into the folder within your terminal or PowerShell console.
2. Define variables
First we add some variables to simplify our script. You can simply run Azure CLI commands within a PowerShell console or script:
# Variables $location = "westeurope" $tenantName = "Your tenant name or id" $targetSubscriptionId = "Your target subscription" $resourceGroupName = "Your resoure group name"
3. Login to Azure
Next we need to log into Azure with Azure CLI:
# Login to Azure az login --tenant $tenantName az account set --subscription $targetSubscriptionId
4. Create resource group
After we successfully logged into Azure, we’re able to create our resource group which will hold our resources:
# Create resource group az group create --location $location --name $resourceGroupName
5. Create Bicep template
We’re now ready to deploy resources to our resource group. We’ll use Azure Bicep to declare the state of our resources, which we will then hand over to the Azure Resource Manager (ARM) for the actual deployment.
You find a template of the main.bicep
file in the repository you downloaded in step 1. Let’s take a quick look at the template and it’s declarations:
Like in PowerShell or other languages, you can use variables and parameters to simplify your deployment. We declare some parameters aswell:
// PARAMETERS param location string = resourceGroup().location param automationAccountName string = 'd-aut-blog-mid-01'
After that we begin with the declaration of the Azure Automation Account. Take a close look at lines 10-12 where we enable the system-assigned Managed Identity.
// RESOURCE DEPLOYMENTS // Automation Account resource automationAccount 'Microsoft.Automation/automationAccounts@2022-08-08' = { name: automationAccountName location: location identity: { type: 'SystemAssigned' } properties: { sku: { name: 'Free' } } }
We now declared our Automation Account, which holds the Automation Runbook. Let’s declare our PowerShell Runbook, which automatically fetches and publishes a PowerShell script from the same repository. We use this script for testing after the deployment.
// Automation Runbook resource runbook 'Microsoft.Automation/automationAccounts/runbooks@2022-08-08' = { name: 'runbook01' parent: automationAccount location: location properties: { runbookType: 'PowerShell' publishContentLink: { uri: 'https://raw.githubusercontent.com/gerbermarco/blog-posts/main/what-are-managed-identities/runbook-content.ps1' } } }
6. Deploy Bicep template
To deploy our Bicep template, we switch back to our Azure CLI session inside PowerShell or terminal. We can start our deployment with a simple az deployment group create
command:
# Deploy main.bicep to Azure az deployment group create --resource-group $resourceGroupName --template-file main.bicep
You can see shortly after that the deployment is running, you get the JSON response from Azure as soon as the deployment went through successfully.
You can now switch to the Azure Portal and check the resource creation, you should now see your resource group including an Azure Automation Account and an Automation Runbook.
7. Verify deployment
Open your newly created Automation Account in the Azure portal and take a look at the “Identity” blade. As you can see, the system-assigned Managed Identity is enabled with an according object ID:
Let’s open our Automation Runbook under the “Runbooks” blade on the left side menu. You should now see your newly created runbook, open it and click on “</> View”. You can now see the published code from the file runbook-content.ps1
fetched from the repository.
This script will obtain an access token using the current identity running the Runbook, and output the subjcet (user) value from the token. If you are interested in the structure and claims of JWT tokens, you can find more information here.
Alright, in our final test we will verify the use of the Managed Identity. Start the runbook with the “Start” button and observe the output, it can take a few minutes to spin up the runner in the background. The output should look like this:
You can now compare the ID from the output with the object ID of the Managed Identity from the “Identity” blade. They match, which means that the Managed Identity is actually used.
Conclusion
Managed Identities are a great solution to further improve security and Zero Trust inside the Azure platform. They are easy to enable and DevOps-friendly. Take a look at how you can improve security in your environment and maybe already replace certain App registrations.
Now that we have our Managed Identity enabled, how do we grant permissions? You will learn everything about this topic in a future post.