Azure Key Vault is to secure the secrets safely and access them securely as needed without hard-coding them in our code to authenticate to various applications on various environments, but the main challenge here is to authenticate to Key Vault, and if it is compromised then the entire secrets in the vault will be compromised so it should be handled properly.
To overcome this and handle the secrets securely, Azure has come up with a concept called Managed Identities for Azure Resources
as a feature in Azure Active Directory, which will help us to authenticate between the azure resources with a trusted relationship.
There are two types of managed identities, one is System Assigned Managed Identity (SAMI)
and the other is User Assigned Managed Identity (UAMI)
, however I am not going to discuss more about the Managed Identities here, you can refer to the
Microsoft Docs.
In this demo, I am going to enable User Assigned Managed Identity
between Azure Virtual Machine and Azure Key Vault using PowerShell to access the Key Vault from the VM and retrieve the secrets with a trusted relationship. You can enable the User Assigned Managed Identity
while creating the VM itself, but for our demo I am going to enable it after the VM is created, and the steps are as follows…
For our demo I am going to create a simple windows VM with all default values using the New-AzVM CmdLet…
# Create a Resource Group
$rgName = 'Test-RG'
$location = 'westus'
$null = New-AzResourceGroup -Name $rgName -Location $location
# Create a Virtual Machine
$vmName = 'Test-VM'
$userName = 'sysadmin'
$plainTextPassword = 'P@ssw0rd!'
$securePassword = $plainTextPassword | ConvertTo-SecureString -AsPlainText -Force
$credential = [pscredential]::new($userName, $securePassword)
$vm = New-AzVM -ResourceGroupName $rgName -Name $vmName `
-Location $location -Credential $credential
The above code will create a brand new VM with all defaults and allow the RDP (3389) and PowerShell Remoting (5985) ports. If you want to create a fully configured VM of your choice then you can refer to the script on my GitHub Repo.
Users with Contributor role can create & manage Virtual Machines.
Install and import the module Az.ManagedServiceIdentity to create managed identity using New-AzUserAssignedIdentityCmdLet, and this module is not part of Az PowerShell module.
# Install and Import the module
$moduleName = 'Az.ManagedServiceIdentity'
Install-Module -Name $moduleName -Force
Import-Module -Name $moduleName
# Create User Assugned Managed Identity
$identityName = 'amuai'
$identity = New-AzUserAssignedIdentity -Name $identityName `
-ResourceGroupName $rgName -Location $location
The above command will create a User Assigned Managed Identity named amuai.
Create an Azure Key Vault to store secrets, which we will access it from the Virtual Machine using the Managed Identity…
# Create Azure Key Vault
$keyVaultName = 'testakv99'
$keyVault = New-AzKeyVault -ResourceGroupName $rgName `
-Name $keyVaultName -Location $location
The above command will create an Azure Key Vault named testakv99, and now we will add a secret to it.
For this demo, we will add the same password that was used to create our test VM.
# Add a secret to Key Vault
$null = Set-AzKeyVaultSecret -VaultName $keyVaultName `
-Name $userName -SecretValue $securePassword
Users having the access to Key Vault will have the same access on all the secrets in the vault, so please add the secrets only required to the user.
For this demo, the managed identity is required to read the credentials from the Key Vault, so we need to grant the Reader role on the Key Vault to the Managed Identity.
# Grant Reader role to Managed Identity on Key Vault
$null = New-AzRoleAssignment -ApplicationId $identity.ClientId `
-RoleDefinitionName Reader -Scope $keyVault.ResourceId
IAM role is limited to the Key Vault resource only and has no effect on accessing the secrets. You need to grant Key Vault access policy to get the secret.
Since this is a demo and we only need to get the secret to be used in our code on the managed identity enabled VM, we will grant GETAccess Policy on Key Vault to managed identity.
# Grant GET permissions to secrets on Key Key Vault to managed identity
Set-AzKeyVaultAccessPolicy -ResourceGroupName $rgName -VaultName $keyVaultName `
-ServicePrincipalName $identity.ClientId -PermissionsToSecrets get
Now we need to assign this identity and enable User Assigned Managed Identity
on Virtual Machine.
Since we have already created a VM and have that VM object in $vm, we will use the same variable for our demo or else you can get the existing VM using Get-AzVM CmdLet.
# Assign the identity and enable User Assigned Managed Identity on Virtual Machine.
$null = Update-AzVM -ResourceGroupName $rgName -VM $vm `
-IdentityType UserAssigned -IdentityID $identity.Id
All done, now let’s test this on the Managed Identity enabled VM.
Now let’s test the access to Key Vault from the VM without an explicit authentication and get the secret from the Key Vault.
Since I want to use the secret in the PowerShell code, I will test the access and retrieve the secret using the PowerShell itself, so I will install Az module on the VM for our testing purpose.
If you are not using this secret in the PowerShell, you can use the REST methods to get the secrets from the Key Vault, please refer to the Microsoft Docs for the same.
Get the public ip of the VM and connect to it…
# Get the public ip of the new VM
$vmPIP = Get-AzPublicIpAddress -ResourceGroupName $rgName -Name $vmName | % IpAddress
Now let’s install the Az module and authenticate to Azure using the Identity flag and access the secret…
## On the NEW VM in which User Assigned Managed Identity enabled
# Enter-PSSession -ComputerName $vmPIP -Credential $credential
# Install NuGet package provider where Az module is available
Install-PackageProvider -Name NuGet -Force
# Install the Az module
Install-Module -Name Az -Force
# Login to Azure with managed identity
Login-AzAccount -Identity
# Get the secret from the Key Vault
$kvName = 'testakv99'
$keyName = 'sysadmin'
$Secret = Get-AzKeyVaultSecret -VaultName $kvName -Name $keyName | % SecretValueText
# You can use this secret in your code, since it is a demo I am writing it to screen
Write-Host "The password is: $Secret"
You can take a glance of the complete script from my GitHub Repo.