Search code examples
azurepowershellazure-devopsazure-powershellazure-keyvault

Script for backing up keyvault


I've been trying to tweak and make a basic simple script just a bit more clean and overall to improve it. Basically the initial script was iterating and doing a backup for each secret,certificate and key from each keyvault in a subscription. I am trying to make it better by creating a function and trying to use it as such, unfortunately I'm still missing some thigns and I would like someone to help me sort this out:

function Get-Backup{
    [CmdletBinding()]
    param (
        [Parameter()]
        $Item,
        [Parameter()]
        $VaultName
    )
$Items = az keyvault $Item list --vault-name $VaultName | ConvertFrom-Json
    foreach ($Item in $Items) {
        az keyvault $Item backup --vault-name $VaultName --name $Item.Name --file $Item/$Name.txt
    }
}

$Vaults = az keyvault list | ConvertFrom-Json
foreach ($VaultName in $Vaults) {
Get-Backup("secret",$VaultName)
Get-Backup("certificate",$VaultName)
Get-Backup("key",$VaultName)
}

This doesn't work, and I don't understand really what I'm missing or doing wrong. the whole point of this would be to do a script that would automatically pick all the secrets all the keys and all the certificates in a vault, and do this for each vault.

I am trying to compile a function so I could reduce the main code and rely more on functions.

Unfortunatetly I can not post the error as it contains lots of identifiable information of my subscription name resource group etc. Starts with " ERROR: '' is misspelled or not recognized by the system. "

I am looking to do this myself but being stuck for a couple of days, I'd really appreaciate some hints and help.


Solution

  • Could you try solution given here. But please note that here you have

    risk of having in-memory variables

    Param(
        [parameter(mandatory)] [string] $originVault,
        [parameter(mandatory)] [string] $originSubscriptionId,
        [parameter(mandatory)] [string] $destinationVault,
        [parameter(mandatory)] [string] $destinationSubscriptionId,
        [string] $disableDestinationSecrets = $true
    )
    
    # 1. Set the source subscription id. 
    Write-Host "Setting origin subscription to: $($originSubscriptionId)..."
    az account set -s $originSubscriptionId
    
    # 1.1 Get all secrets
    Write-Host "Listing all origin secrets from vault: $($originVault)"
    $originSecretKeys = az keyvault secret list --vault-name $originVault  -o json --query "[].name"  | ConvertFrom-Json
    
    # 1.3 Loop secrets into PSCustomObjects, making it easy to work with later.
    $secretObjects = $originSecretKeys | ForEach-Object {
        Write-Host " - Getting secret value for '$($_)'"
        $secret = az keyvault secret show --name $_ --vault-name $originVault -o json | ConvertFrom-Json
        
        [PSCustomObject]@{
            secretName  = $_;
            secretValue = $secret.value;
        }#endcustomobject.
    
    }#endforeach.
    
    Write-Host "Done fetching secrets..."
    
    # 2. Set the destination subscription id.
    Write-Host "Setting destination subscription to: $($destinationSubscriptionId)..."
    az account set -s $destinationSubscriptionId
    
    # 2.2 Loop secrets objects, and set secrets in destination vault
    Write-Host "Writing all destination secrets to vault: $($destinationVault)"
    $secretObjects | ForEach-Object {
        Write-Host " - Setting secret value for '$($_.secretName)'"
        az keyvault secret set --vault-name $destinationVault --name "$($_.secretName)" --value  "$($_.secretValue)" --disabled $disableDestinationSecrets -o none
    }
    
    # 3. Clean up
    Write-Host "Cleaning up and exiting."
    Remove-Variable secretObjects
    Remove-Variable originSecretKeys
    
    Write-Host "Finished."
    

    or this one which uses powershell instead of azure cli.

    $storageAccountTemplateFile = "https://raw.githubusercontent.com/srozemuller/Azure/main/AzureStorageAccount/azuredeploy.json"
    $storageAccountTemplateParameters = "https://raw.githubusercontent.com/srozemuller/Azure/main/AzureStorageAccount/azuredeploy.parameters.json"
    $backupFolder = "$env:Temp\KeyVaultBackup"
    $location = "West Europe"
    
    $backupLocationTag = "BackupLocation"
    $backupContainerTag = "BackupContainer"
    
    $global:parameters = @{
        resourceGroupName = "RG-PRD-Backups-001"
        location          = $location
    }
    function backup-keyVaultItems($keyvaultName) {
        #######Parameters
        #######Setup backup directory
        If ((test-path $backupFolder)) {
            Remove-Item $backupFolder -Recurse -Force
    
        }
        ####### Backup items
        New-Item -ItemType Directory -Force -Path "$($backupFolder)\$($keyvaultName)" | Out-Null
        Write-Output "Starting backup of KeyVault to a local directory."
        ###Certificates
        $certificates = Get-AzKeyVaultCertificate -VaultName $keyvaultName 
        foreach ($cert in $certificates) {
            Backup-AzKeyVaultCertificate -Name $cert.name -VaultName $keyvaultName -OutputFile "$backupFolder\$keyvaultName\certificate-$($cert.name)" | Out-Null
        }
        ###Secrets
        $secrets = Get-AzKeyVaultSecret -VaultName $keyvaultName
        foreach ($secret in $secrets) {
            #Exclude any secrets automatically generated when creating a cert, as these cannot be backed up   
            if (! ($certificates.Name -contains $secret.name)) {
                Backup-AzKeyVaultSecret -Name $secret.name -VaultName $keyvaultName -OutputFile "$backupFolder\$keyvaultName\secret-$($secret.name)" | Out-Null
            }
        }
        #keys
        $keys = Get-AzKeyVaultKey -VaultName $keyvaultName
        foreach ($kvkey in $keys) {
            #Exclude any keys automatically generated when creating a cert, as these cannot be backed up   
            if (! ($certificates.Name -contains $kvkey.name)) {
                Backup-AzKeyVaultKey -Name $kvkey.name -VaultName $keyvaultName -OutputFile "$backupFolder\$keyvaultName\key-$($kvkey.name)" | Out-Null
            }
        }
    }
    $keyvaults = Get-AzKeyVault 
        if ($keyvaults) {
            if ($null -eq (get-AzResourceGroup $global:parameters.resourceGroupName -ErrorAction SilentlyContinue)) {
                New-AzResourceGroup @global:parameters
            }
            if ($null -eq ($keyvaults | ? { $_.Tags.Keys -match $BackupLocationTag })) {
                # if no backuplocation tags is available at any of the keyVaults we will create one first
                $deployment = New-AzResourceGroupDeployment -ResourceGroupName $global:parameters.resourceGroupName -TemplateUri $storageAccountTemplateFile -TemplateParameterUri $storageAccountTemplateParameters
                $backupLocation = $deployment.outputs.Get_Item("storageAccount").value
                if ($deployment.ProvisioningState -eq "Succeeded") {
                    foreach ($keyvault in $keyvaults) {
                        $containerName = $keyvault.VaultName.Replace("-", $null).ToLower()
                        if (!(Get-aztag -ResourceId $keyvault.ResourceId  | ? { $_.Tags.Keys -match $BackupLocationTag }  )) {
                            Update-AzTag $keyvault.ResourceId -operation Merge -Tag @{BackupLocation = $backupLocation; BackupContainer = $containerName }
                        }
                    }
                }    
            }
            else {
                foreach ($keyvault in $keyvaults) {
                    $backupLocation = (get-azkeyvault -VaultName $keyvault.vaultname | ? { $_.Tags.Keys -match $BackupLocationTag}).tags.Get_Item($BackupLocationTag)
                    $storageAccount = get-AzStorageAccount | ? { $_.StorageAccountName -eq $backupLocation }
                    if ($null -eq (Get-aztag -ResourceId $keyvault.ResourceId  | ? { $_.Tags.Keys -match $BackupContainerTag }  )) {
                        $containerName = $keyvault.VaultName.Replace("-", $null).ToLower()
                        Update-AzTag $keyvault.ResourceId -operation Merge -Tag @{BackupContainer = $containerName }
                    }
                    $containerName = (get-azkeyvault -VaultName $keyvault.vaultname | ? { $_.Tags.Keys -match $backupContainerTag }).tags.Get_Item($backupContainerTag)
                    if ($null -eq (Get-AzStorageContainer -Name $containerName -Context $storageAccount.context)) {
                        New-AzStorageContainer -Name $containerName -Context $storageAccount.context
                    }
                    backup-keyVaultItems -keyvaultName $keyvault.VaultName
                    foreach ($file in (get-childitem "$($backupFolder)\$($keyvault.VaultName)")) {
                        Set-AzStorageBlobContent -File $file.FullName -Container $containerName -Blob $file.name -Context $storageAccount.context -Force
                    }
                }
            }
        }