Azure Storage Account Keys Automatic Rotation

Azure Infrastructure

Introduction

A new feature called Managed Storage Account Keys popped up last month that promises to make rotating Azure Storage Account Keys easier. I have to give a ton of credit to my colleague Dmitriy S. who helped with a lot of the discovery and troubleshooting.

Why rotate?

It is recommended to periodically rotate your Storage Account Keys. Storage Account Keys give the holder full access to your storage account and all data within it. Rotating the keys periodically help mitigate the risk of unauthorized access.

The old way

Previously, we had this article called “Set up Azure Key Vault with end-to-end key rotation and auditing,” which describes automation storage account key rotation. While that will still work, it’s very complex to setup, involves using an Automation Account and Runbook, Functions, and a Logic App. We now have a much easier way!

The new way

Using Managed Storage Account Keys, we can easily set up automatic key rotation by just deploying a Storage Account and a Key Vault. The article called Azure Key Vault Storage Account Keys describes the feature and developer experience. However, the “Getting started” section was a bit confusing, incomplete and it looks like it contains some errors. So, let’s go through it together.

Set-up permissions

I’m going to assume you have a Key Vault and Storage Account already and they have registered providers. The first thing we need is the ObjectId of Key Vault. Note, we need the ObjectId of the Key Vault service (“first party identity”), NOT your specific Key Vault. This object ID is different for each tenant. The instructions on the official documentation say:

Get-AzureRmADServicePrincipal -SearchString "AzureKeyVault"

However, that didn’t work for one of my tenants (which was a Enterprise Enrollment). A more accurate way to get the ObjectId is to first login using “Connect-AzureAD” and then using the following command:

$servicePrincipal = Get-AzureADServicePrincipal -Filter "AppId eq 'cfa8b339-82a2-471a-a3c9-0fc0be7a4093'"

This won’t work on MSDN Azure subscriptions, but neither did the first way. I’ve found that the AppId above is consistent across all of my tenants but could be different for AzureChina, AzureGov, etc. Next, we need to assign the “Storage Account Key Operator Service Role” role which gives the Key Vault list and regenerate permissions:

$storageAccountId = (Get-AzureRmStorageAccount -StorageAccountName wspladiag02 -ResourceGroupName wspla-rg).Id
New-AzureRmRoleAssignment -ObjectId $servicePrincipal.ObjectId -RoleDefinitionName 'Storage Account Key Operator Service Role' -Scope $storageAccountId

Storage account onboarding

The official documentation is unclear on the next steps, in my opinion. But, here’s how we set up daily key rotation using PowerShell. First, we need to make sure we (user performing operation) has “set” operation allowed within the Key Vault’s access policies. If you don’t, you’ll get this error later on:

Add-AzureKeyVaultManagedStorageAccount : Operation "set" is not allowed by vault policy

So to prevent that, let’s add the current user:

$keyVaultName = "kv-infra-secrets"
$keyVaultResourceGroupName = "RG-Infrastructure"
Set-AzureRmKeyVaultAccessPolicy -VaultName $keyVaultName -ResourceGroupName $keyVaultResourceGroupName -UserPrincipalName "[email protected]" -PermissionsToStorage set, get, regeneratekey

I gave the user get and regeneratekey also but those aren’t required unless you want to use other commands. Now let’s create a TimeSpan object:

$regenerationPeriod = [System.Timespan]::FromDays(1)

Next, we use a new command to add the Storage Account as “Managed” by this Key Vault. If you don’t have this command, remember to update to the latest Azure PowerShell.

$parameters = @{
VaultName = $keyVaultName
AccountResourceId = $storageAccountId
AccountName = "mystoragetest1"
ActiveKeyName = "key1"
RegenerationPeriod = $regenerationPeriod
}
Add-AzureKeyVaultManagedStorageAccount @parameters

That’s it! The Storage Account Key will be rotated on the schedule you set up. You can verify everything by using Get-AzureKeyVaultManagedStorageAccount. You can also regenerate the keys manually using Update-AzureKeyVaultManagedStorageAccountKey if you don’t want to wait.

6 comments… add one
  • Micah J Sep 7, 2017 Link Reply

    Great article, hats off to your and your colleagues on this as $MS documentation was a bit pants and I was struggling.

    One minor update, is that to get-azurekeyvaultManagedStorageAccount you need to add ‘list’ to your permissions.

    Set-AzureRmKeyVaultAccessPolicy -VaultName $keyVaultName -ResourceGroupName $keyVaultResourceGroupName -UserPrincipalName “[email protected]” -PermissionsToStorage set, get, regeneratekey

    thanks again!!

  • Ahmadreza Khadem Sep 11, 2017 Link Reply

    Thanks very helpful

  • Dmitriy Shmuylovskiy Nov 15, 2017 Link Reply

    Thanks Wahid, great article.

    What I’ve mentioned howver that “-userPrinicalName” does not work in our case. I’m using “-objectID” instead and retrieving this value with this contract:

    (Get-AzureRmADUser | where-object {$_.UserPrincipalName -like “$userServicePrincialName*”}).id.guid

  • Chaitanya Alladi May 10, 2018 Link Reply

    Hello Wahid,

    I’m trying to implement this setup and ran into some error at the final step, saying “keyvault is unable to perform the action on behalf of the caller” where i created my resources and role assignment and set access policy with my service principal ID, as i do not want to bring in any specific user for this process and gace my service principal owner role too. But from your findings, i see you did role assignment for a service principal and set access policy is done for a user principal. How does that work? can you please suggest me accordingly, so i can try to fix my issue.

    Thanks
    Chaitanya Alladi.

  • CHITRA RAJU Jun 18, 2018 Link Reply

    How to achieve this storage key rotating using azure policy json ? Do we have the provision/ alaises to do this in json ?

  • CHITRA RAJU Jun 18, 2018 Link Reply

    How to achieve this same using azure policy json ?

Leave a Reply