Automate the rotation of a secret for resources that have two sets of authentication credentials

The best way to authenticate to Azure services is by using a managed identity, but there are some scenarios where that isn't an option. In those cases, access keys or passwords are used. You should rotate access keys and passwords frequently.

This tutorial shows how to automate the periodic rotation of secrets for databases and services that use two sets of authentication credentials. Specifically, this tutorial shows how to rotate Azure Storage account keys stored in Azure Key Vault as secrets. You'll use a function triggered by Azure Event Grid notification.

Note

Storage account keys can be automatically managed in Key Vault if you provide shared access signature tokens for delegated access to the storage account. There are services that require storage account connection strings with access keys. For that scenario, we recommend this solution.

Here's the rotation solution described in this tutorial:

Diagram that shows the rotation solution.

In this solution, Azure Key Vault stores storage account individual access keys as versions of the same secret, alternating between the primary and secondary key in subsequent versions. When one access key is stored in the latest version of the secret, the alternate key is regenerated and added to Key Vault as the new latest version of the secret. The solution provides the application's entire rotation cycle to refresh to the newest regenerated key.

  1. Thirty days before the expiration date of a secret, Key Vault publishes the near expiry event to Event Grid.
  2. Event Grid checks the event subscriptions and uses HTTP POST to call the function app endpoint that's subscribed to the event.
  3. The function app identifies the alternate key (not the latest one) and calls the storage account to regenerate it.
  4. The function app adds the new regenerated key to Azure Key Vault as the new version of the secret.

Prerequisites

You can use this deployment link if you don't have an existing key vault and existing storage accounts:

Link that's labelled Deploy to Azure.

  1. Under Resource group, select Create new. Name the group akvrotation and then select OK.

  2. Select Review + create.

  3. Select Create.

    Screenshot that shows how to create a resource group.

You'll now have a key vault and two storage accounts. You can verify this setup in the Azure CLI by running this command:

az resource list -o table -g akvrotation

The result will look something like this output:

Name                     ResourceGroup         Location    Type                               Status
-----------------------  --------------------  ----------  ---------------------------------  --------
akvrotation-kv         akvrotation      eastus      Microsoft.KeyVault/vaults
akvrotationstorage     akvrotation      eastus      Microsoft.Storage/storageAccounts
akvrotationstorage2    akvrotation      eastus      Microsoft.Storage/storageAccounts

Create and deploy the key rotation function

Next, you'll create a function app with a system-managed identity, in addition to other required components. You'll also deploy the rotation function for the storage account keys.

The function app rotation function requires the following components and configuration:

  • An Azure App Service plan
  • A storage account to manage function app triggers
  • An access policy to access secrets in Key Vault
  • The Storage Account Key Operator Service role assigned to the function app so it can access storage account access keys
  • A key rotation function with an event trigger and an HTTP trigger (on-demand rotation)
  • An Event Grid event subscription for the SecretNearExpiry event
  1. Select the Azure template deployment link:

    Azure template deployment link.

  2. In the Resource group list, select akvrotation.

  3. In the Storage Account RG box, enter the name of the resource group in which your storage account is located. Keep the default value [resourceGroup().name] if your storage account is already located in the same resource group where you'll deploy the key rotation function.

  4. In the Storage Account Name box, enter the name of the storage account that contains the access keys to rotate.

  5. In the Key Vault RG box, enter the name of resource group in which your key vault is located. Keep the default value [resourceGroup().name] if your key vault already exists in the same resource group where you'll deploy the key rotation function.

  6. In the Key Vault Name box, enter the name of the key vault.

  7. In the Function App Name box, enter the name of the function app.

  8. In the Secret Name box, enter the name of the secret where you'll store access keys.

  9. In the Repo URL box, enter the GitHub location of the function code: https://github.com/jlichwa/KeyVault-Rotation-StorageAccountKey-PowerShell.git.

  10. Select Review + create.

  11. Select Create.

    Screenshot that shows how to create the first storage account.

After you complete the preceding steps, you'll have a storage account, a server farm, a function app, and Application Insights. When the deployment is complete, you'll see this page: Screenshot that shows the Your deployment is complete page.

Note

If you encounter a failure, you can select Redeploy to finish the deployment of the components.

You can find deployment templates and code for the rotation function on GitHub.

Add the storage account access keys to Key Vault

First, set your access policy to grant manage secrets permissions to users:

az keyvault set-policy --upn <email-address-of-user> --name akvrotation-kv --secret-permissions set delete get list

You can now create a new secret with a storage account access key as its value. You'll also need the storage account resource ID, secret validity period, and key ID to add to the secret so the rotation function can regenerate the key in the storage account.

Determine the storage account resource ID. You can find this value in the id property.

az storage account show -n akvrotationstorage

List the storage account access keys so you can get the key values:

az storage account keys list -n akvrotationstorage 

Run this command, using your retrieved values for key1Value and storageAccountResourceId:

$tomorrowDate = (get-date).AddDays(+1).ToString("yyy-MM-ddThh:mm:ssZ")
az keyvault secret set --name storageKey --vault-name akvrotation-kv --value <key1Value> --tags "CredentialId=key1" "ProviderAddress=<storageAccountResourceId>" "ValidityPeriodDays=60" --expires $tomorrowDate

If you create a secret with a short expiration date, a SecretNearExpiry event will publish within several minutes. This event will in turn trigger the function to rotate the secret.

You can verify that access keys have regenerated by retrieving the storage account key and the Key Vault secret and comparing them.

Use this command to get the secret information:

az keyvault secret show --vault-name akvrotation-kv --name storageKey

Notice that CredentialId is updated to the alternate keyName and that value is regenerated: Screenshot that shows the output of the a z keyvault secret show command for the first storage account.

Retrieve the access keys to compare the values:

az storage account keys list -n akvrotationstorage 

Screenshot that shows the output of the a z storage account keys list command for the first storage account.

Add storage accounts for rotation

You can reuse the same function app to rotate keys for multiple storage accounts.

To add storage account keys to an existing function for rotation, you need:

  • The Storage Account Key Operator Service role assigned to function app so it can access storage account access keys.
  • An Event Grid event subscription for the SecretNearExpiry event.
  1. Select the Azure template deployment link:

    Azure template deployment link.

  2. In the Resource group list, select akvrotation.

  3. In the Storage Account Name box, enter the name of the storage account that contains the access keys to rotate.

  4. In the Key Vault Name box, enter the name of the key vault.

  5. In the Function App Name box, enter the name of the function app.

  6. In the Secret Name box, enter the name of the secret where you'll store access keys.

  7. Select Review + create.

  8. Select Create.

    Screenshot that shows how to create an additional storage account.

Add another storage account access key to Key Vault

Determine the storage account resource ID. You can find this value in the id property.

az storage account show -n akvrotationstorage2

List the storage account access keys so you can get the key2 value:

az storage account keys list -n akvrotationstorage2 

Run this command, using your retrieved values for key2Value and storageAccountResourceId:

tomorrowDate=`date -d tomorrow -Iseconds -u | awk -F'+' '{print $1"Z"}'`
az keyvault secret set --name storageKey2 --vault-name akvrotation-kv --value <key2Value> --tags "CredentialId=key2" "ProviderAddress=<storageAccountResourceId>" "ValidityPeriodDays=60" --expires $tomorrowDate

Use this command to get the secret information:

az keyvault secret show --vault-name akvrotation-kv --name storageKey2

Notice that CredentialId is updated to the alternate keyName and that value is regenerated: Screenshot that shows the output of the a z keyvault secret show command for the second storage account.

Retrieve the access keys to compare the values:

az storage account keys list -n akvrotationstorage 

Screenshot that shows the output of the a z storage account keys list command for the second storage account.

Key Vault dual credential rotation functions

Next steps