Tom Warner
Tom Warner

Reputation: 3570

How do I copy over all secrets from one Azure Keyvault to another using Powershell

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?

Upvotes: 32

Views: 40378

Answers (7)

UnionP
UnionP

Reputation: 1638

I started with @4c74356b41's answer, but made a couple changes. I didn't want to copy the certificates across since that doesn't really work well (it copies them as secrets, and they don't work at all cross-region), and I wanted to preserve the ContentType properties as well:

$sourceVaultName = "<source vault>"
$destVaultName = "<dest vault>"

$secrets = Get-AzKeyVaultSecret -VaultName $sourceVaultName
$secrets | ? { $_.ContentType -ne "application/x-pkcs12" } | % {
    $secret = Get-AzKeyVaultSecret -VaultName $sourceVaultName -Name $_.Name
    Set-AzKeyVaultSecret -VaultName $destVaultName -Name $secret.Name -SecretValue $secret.SecretValue -ContentType $secret.ContentType
}

Upvotes: 5

AlvinH
AlvinH

Reputation: 1469

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)

Upvotes: 7

Florin Grigoriu
Florin Grigoriu

Reputation: 185

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
}

Upvotes: 8

Srinithin
Srinithin

Reputation: 53

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
}

Upvotes: 1

HSharma
HSharma

Reputation: 403

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

Upvotes: 0

4c74356b41
4c74356b41

Reputation: 72171

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

Upvotes: 52

Tom Warner
Tom Warner

Reputation: 3570

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

Upvotes: 5

Related Questions