Listing Azure Storage account access keys with PowerShell

Posted: (EET/GMT+2)

 

Azure's blob storage is great for storing general-purpose data, be is binary or text. But getting access to multiple storage accounts and retrieving their access keys using the Azure Portal is a bit tedious. I recently needed a faster solution, so I decided to write a post about it. So, if you need to list access keys for multiple Azure Storage accounts, PowerShell can do the job with a short script.

But first, a warning: storage account keys are secrets. Anyone who has a storage account key can use it to access the storage account, depending on the account configuration and network rules. Do not print keys into shared logs, paste them into tickets, or leave exported files lying around.

Prefer Microsoft Azure Active Directory (AAD), managed identities, and role-based access when possible. Use account keys only when the application or tool really needs them.

With the warning out of the way, let's start scripting. Start by connecting to Azure:

Connect-AzAccount

If you have access to multiple subscriptions, select the correct one:

Set-AzContext -Subscription "12340000-0000-0000-0000-000000000000"

To list all storage accounts in the selected subscription:

Get-AzStorageAccount

To retrieve keys for one storage account, use the Get-AzStorageAccountKey cmdlet (docs here):

Get-AzStorageAccountKey `
    -ResourceGroupName "rg-storage" `
    -Name "blobstorage1"

The practical version is to loop through the storage accounts and include the account name in the output.

Get-AzStorageAccount |
    ForEach-Object {
        $account = $_

        Get-AzStorageAccountKey `
            -ResourceGroupName $account.ResourceGroupName `
            -Name $account.StorageAccountName |
            Select-Object `
                @{ Name = "ResourceGroupName"; Expression = { $account.ResourceGroupName } },
                @{ Name = "StorageAccountName"; Expression = { $account.StorageAccountName } },
                KeyName,
                Permissions,
                Value
    }

This gives a table containing the resource group, storage account name, key name, permissions, and key value.

In real environments, you usually do not want every storage account. Filter the list first, for example, by only taking accounts whose name starts with my-blob-storage:

Get-AzStorageAccount |
    Where-Object StorageAccountName -like "my-blob-storage*" |
    ForEach-Object {
        $account = $_

        Get-AzStorageAccountKey `
            -ResourceGroupName $account.ResourceGroupName `
            -Name $account.StorageAccountName |
            Select-Object `
                @{ Name = "ResourceGroupName"; Expression = { $account.ResourceGroupName } },
                @{ Name = "StorageAccountName"; Expression = { $account.StorageAccountName } },
                KeyName,
                Permissions,
                Value
    }

Or only accounts from one resource group:

Get-AzStorageAccount -ResourceGroupName "rg-storage" |
    ForEach-Object {
        $account = $_

        Get-AzStorageAccountKey `
            -ResourceGroupName $account.ResourceGroupName `
            -Name $account.StorageAccountName |
            Select-Object `
                @{ Name = "ResourceGroupName"; Expression = { $account.ResourceGroupName } },
                @{ Name = "StorageAccountName"; Expression = { $account.StorageAccountName } },
                KeyName,
                Permissions,
                Value
    }

If you need to export the result, be careful where the file is written. Use something like this:

Get-AzStorageAccount -ResourceGroupName "rg-storage" |
    ForEach-Object {
        $account = $_

        Get-AzStorageAccountKey `
            -ResourceGroupName $account.ResourceGroupName `
            -Name $account.StorageAccountName |
            Select-Object `
                @{ Name = "ResourceGroupName"; Expression = { $account.ResourceGroupName } },
                @{ Name = "StorageAccountName"; Expression = { $account.StorageAccountName } },
                KeyName,
                Permissions,
                Value
    } |
    Export-Csv `
        -Path ".\storage-account-keys.csv" `
        -NoTypeInformation

That CSV file contains secrets. Store it securely, delete it when no longer needed, and do not commit it to source control.

If you only need to confirm that keys exist, do not output the actual key values:

Get-AzStorageAccount |
    ForEach-Object {
        $account = $_

        Get-AzStorageAccountKey `
            -ResourceGroupName $account.ResourceGroupName `
            -Name $account.StorageAccountName |
            Select-Object `
                @{ Name = "ResourceGroupName"; Expression = { $account.ResourceGroupName } },
                @{ Name = "StorageAccountName"; Expression = { $account.StorageAccountName } },
                KeyName,
                Permissions
    }

Good safety rules:

  • only retrieve keys when you really need them
  • filter to the storage accounts you actually care about
  • avoid writing keys to shared logs
  • treat exported CSV files as secret material
  • prefer managed identities and role-based access for applications
  • rotate keys if they have been exposed or compromised.

Reading storage account keys requires Azure permissions that allow listing keys. If the command fails with an authorization error, check the Azure role assignments for the current user or service principal. The above are examples of simple scripts, but they deal with sensitive data. So keep your script careful.

Safe journeys!