16
votes

We recently found ourselves needing to copy over every single secret (name and value) from one Azure KeyVault to a newly created one. I found ways to restore the secrets from a backup, but we didn't have a backup. Is there a Powershell script that can just loop through every name/value combo in a source vault and copy it to a destination vault?

6

6 Answers

18
votes

this is just too triggering (no offense), here's a more "powershelly" version:

Param(
    [Parameter(Mandatory)]
    [string]$sourceVaultName,
    [Parameter(Mandatory)]
    [string]$destVaultName
)

Connect-AzAccount

$secretNames = (Get-AzKeyVaultSecret -VaultName $sourceVaultName).Name
$secretNames.foreach{
    Set-AzKeyVaultSecret -VaultName $destVaultName -Name $_ `
        -SecretValue (Get-AzKeyVaultSecret -VaultName $sourceVaultName -Name $_).SecretValue
}

Just to sum it up:

Parameters are mandatory with this change and you can tab complete them, so you dont have to remember which one is first.
Using foreach is a bit cleaner than using do\while (certainly less cognitive effort).
You dont have to cast values to text and encrypt it back, you can just use encrypted value to assign it to new secret

5
votes

There is now!

import-module AzureRM.keyvault

$sourceVaultName = $args[0]
$destVaultName = $args[1]

Connect-AzureRmAccount

#unfortunately you can only access secret values one at a time, by name. so this gets the names first
$names = (Get-AzureKeyVaultSecret -VaultName $sourceVaultName | select Name)

$i=0
do {
   $rawSecret = (Get-AzureKeyVaultSecret -VaultName $sourceVaultName -Name $names[$i].Name).SecretValueText
   $AKVsecret = ConvertTo-SecureString $rawSecret -AsPlainText -Force
   Set-AzureKeyVaultSecret -VaultName $destVaultName -Name $names[$i].Name -SecretValue $AKVsecret
   $i++
} while($i -lt $names.length)

You can call it using

script.ps1 source-keyvault-name dest-keyvault-name

5
votes

This is for those who came here looking for a python solution:

from azure.keyvault.secrets import SecretClient  # pip install azure-keyvault-secrets
from azure.identity import DefaultAzureCredential  # pip install azure-identity

source_vault_url = "https://sourcevault.vault.azure.net"
destination_vault_url = "https://destvault.vault.azure.net/"

credential = DefaultAzureCredential(
    exclude_cli_credential=False
    , exclude_environment_credential=True
    , exclude_managed_identity_credential=True
    , exclude_visual_studio_code_credential=True
    , exclude_shared_token_cache_credential=True
    , exclude_interactive_browser_credential=True
)

source_client = SecretClient(vault_url=source_vault_url, credential=credential)
destination_client = SecretClient(vault_url=destination_vault_url, credential=credential)

key_list = ['key1', 'key2', 'key3']

# Get secrets from the source key vault
credentials = {}
for key in key_list :
    credentials[key] = source_client.get_secret(key).value

# Set secrets in the destination  key vault
for key, value in credentials.items():
    print(f"Creating a secret called '{key}' with the value '{value}' ...")
    destination_client.set_secret(key, value)
4
votes

The script can be translated to the new coolness of az.cli

Param(
    [Parameter(Mandatory)]
    [string]$sourceVaultName,

    [Parameter(Mandatory=$false)]
    [string]$sourceSubscription,

    [Parameter(Mandatory)]
    [string]$destVaultName,

    [Parameter(Mandatory=$false)]
    [string]$descriptionSubscription
)

# az login
if($sourceSubscription){
    az account set --subscription $sourceSubscription
}

Write-Host 'Reading secrets ids from' $sourceVaultName
$secretNames = az keyvault secret list --vault-name $sourceVaultName  -o json --query "[].name"  | ConvertFrom-Json

Write-Host 'Reading secrets values'
$secrets = $secretNames | % {
    $secret = az keyvault secret show --name $_ --vault-name $sourceVaultName -o json | ConvertFrom-Json
    [PSCustomObject]@{
        name  = $_;
        value = $secret.value;
    }
}
Write-Host 'writing secrets'

if($descriptionSubscription){
    az account set --subscription $descriptionSubscription
}

$secrets.foreach{
    az keyvault secret set --vault-name $destVaultName --name $_.name  --value  $_.value
}
1
votes

I wrote a set of powershell scripts to clone key vaults from one subscription to another. Hope it make some help.

1
votes

Very simple script to copy secret from one vault to another:

Param(
[Parameter(Mandatory)]
[string]$oldKeyVault,
[Parameter(Mandatory)]
[string]$newKeyVault
)

#Display Secrets in New Key Vault
Write-Host 'Secrets in New Key Vault BEFORE Sync'
$newSecrets = Get-AzKeyVaultSecret -VaultName $newKeyVault
foreach($newSecret in $newSecrets)
{
    $newSecretDetails = Get-AzKeyVaultSecret -VaultName $newKeyVault -Name $newSecret.Name

    Write-Host 'New Secret: Name='$newSecretDetails.Name

    #Uncomment below if you need to check values
    #Write-Host 'New Secret: Name='$newSecretDetails.Name ': Value=' $newSecretDetails.SecretValueText
}

Write-Host ''
Write-Host ''

#Display Secrets in New Old Vault
Write-Host 'Secrets in Old Key Vault before Sync'
$oldSecrets = Get-AzKeyVaultSecret -VaultName $oldKeyVault
foreach($oldSecret in $oldSecrets)
{
    $oldSecretDetails = Get-AzKeyVaultSecret -VaultName $oldKeyVault -Name $oldSecret.Name

    Write-Host 'Old Secret: Name='$oldSecretDetails.Name

    #Uncomment below if you need to check values   
    #Write-Host 'Old Secret: Name='$oldSecretDetails.Name ': Value=' $oldSecretDetails.SecretValueText
}

Write-Host ''
Write-Host ''

#Sync Key Vault
Write-Host 'Syncing Vaults'
$oldSecrets = Get-AzKeyVaultSecret -VaultName $oldKeyVault
foreach($oldSecret in $oldSecrets)
{
    $oldSecretDetails = Get-AzKeyVaultSecret -VaultName $oldKeyVault -Name $oldSecret.Name    
    $secureStringKey = ConvertTo-SecureString -String $oldSecretDetails.SecretValueText -AsPlainText -Force    
    Set-AzKeyVaultSecret -VaultName $newKeyVault -Name $oldSecretDetails.Name -SecretValue $secureStringKey
    Write-Host 'Secret Copied to New Key Vault: Name = ' $oldSecretDetails.Name
}

Write-Host ''
Write-Host ''

#Display Secrets in New Key Vault
Write-Host 'Secrets in New Key Vault AFTER Sync'
$newSecrets = Get-AzKeyVaultSecret -VaultName $newKeyVault
foreach($newSecret in $newSecrets)
{
    $newSecretDetails = Get-AzKeyVaultSecret -VaultName $newKeyVault -Name $newSecret.Name

    Write-Host 'New Secret: Name='$newSecretDetails.Name

    #Uncomment below if you need to check values  
    #Write-Host 'New Secret: Name='$newSecretDetails.Name ': Value=' $newSecretDetails.SecretValueText
}