Как скопировать все секреты из одного Azure Keyvault в другое с помощью Powershell

Недавно нам потребовалось скопировать каждый отдельный секрет (имя и значение) из одного Azure KeyVault во вновь созданное. Я нашел способы восстановить секреты из резервной копии, но резервной копии у нас не было. Существует ли сценарий Powershell, который может просто перебрать каждое сочетание имени и значения в исходном хранилище и скопировать его в целевое хранилище?

Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
Как установить LAMP Stack 1/2 на Azure Linux VM
Как установить LAMP Stack 1/2 на Azure Linux VM
В дополнение к нашему предыдущему сообщению о намерении Azure прекратить поддержку Azure Database для MySQL в качестве единого сервера после 16...
22
0
16 698
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Есть сейчас!

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)

Вы можете вызвать его, используя

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

Ответ принят как подходящий

это просто слишком триггерно (без обид), вот более "мощная" версия:

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
}

Просто подытожу:

Параметры являются обязательными с этим изменением, и вы можете завершить их с помощью табуляции, поэтому вам не нужно помнить, какой из них является первым.
Использование foreach немного чище, чем использование do\while (определенно меньше когнитивных усилий).
Вам не нужно приводить значения к тексту и шифровать его обратно, вы можете просто использовать зашифрованное значение, чтобы назначить его новому секрету.

круто, это выглядит намного аккуратнее - я не пишу много powershell (если вы не могли сказать), так что спасибо за очистку!

Tom Warner 10.04.2019 19:25

Я написал набор скриптов powershell для клонирования хранилищ ключей из одной подписки в другую. Надеюсь, это поможет.

Поправьте меня, если я ошибаюсь, но разве вы не копируете все секреты из хранилища ключей и не перезаписываете их в том же хранилище ключей?

Sartigan 02.03.2021 20:29

@Sartigan Нет, я делаю это динамическим, чтобы вы могли указать имя нового хранилища ключей, и скрипт скопирует его туда.

HSharma 03.03.2021 05:03

Очень простой скрипт для копирования секрета из одного хранилища в другое:

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
}

Скрипт можно перевести на новую крутость 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
}

Вы проверяли это? Параметр имени не выводится в команде LIST. Я не мог заставить это работать. github.com/Azure/azure-cli/issues/3499

markwilde 04.12.2020 12:10

да, @markwilde, я проверяю это, сохраняя в файле .ps1 и запуская скрипт, предоставляющий параметры. Он работает правильно и клонировал мои KV.

Florin Grigoriu 12.12.2020 02:16

Это НЕ работает, оно молча терпит неудачу, так как имя не экспортируется. Хотя исправление достаточно простое ``` $secretNames = az keyvault secret list --vault-name $sourceVaultName -o json --query "[].id" | ConvertFrom-Json | ForEach-Object {$_.Substring($_.LastIndexOf('/') +1)}

GavinB 04.06.2021 00:14

Это для тех, кто пришел сюда в поисках решения для Python:

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)

TypeError: объект «NoneType» не подлежит подписке

Zizzipupp 13.05.2021 17:28

Скрипт у меня работает хорошо. Убедитесь, что вы заполнили список key_list ключами, которые хотите передать. Также стоит отметить, что это касается двух хранилищ ключей в рамках подписки Azure такой же!

cody.codes 31.05.2021 00:46

Я начал с ответа @ 4c74356b41, но внес пару изменений. Я не хотел копировать сертификаты, так как это не очень хорошо работает (он копирует их как секреты, и они вообще не работают между регионами), и я также хотел сохранить свойства ContentType:

$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
}

Другие вопросы по теме