From 50652f7f09bf57c1372c00467b41c3f258b930fe Mon Sep 17 00:00:00 2001 From: Paolo Salvatori Date: Thu, 6 Aug 2026 15:31:54 +0200 Subject: [PATCH 1/2] Recover a soft-deleted key vault instead of failing the re-run Deleting a key vault only soft-deletes it and its name stays reserved, so re-running a cluster provisioning script after deleting the resource group failed the key vault create with "A vault with the same name already exists in deleted state. You need to either recover or purge existing key vault." That is correct Azure behaviour, and these scripts advertise themselves as idempotent, so they now handle it: before creating, each script checks `az keyvault list-deleted` for its own vault name and recovers it, which restores the vault with its contents. Recovery is used rather than purge because purging throws the contents away; if recovery fails the script prints the exact purge command and exits non-zero rather than guessing. Verified against the emulator: delete the resource group, re-run the script, and the vault is recovered and the run continues to a working cluster, where it previously aborted at that step. Co-Authored-By: Claude Opus 5 --- .../01-system-assigned-managed-identity.sh | 29 +++++++++++++++++++ scripts/01-user-assigned-managed-identity.sh | 29 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/scripts/01-system-assigned-managed-identity.sh b/scripts/01-system-assigned-managed-identity.sh index 9edb3ff..6dd2ff0 100755 --- a/scripts/01-system-assigned-managed-identity.sh +++ b/scripts/01-system-assigned-managed-identity.sh @@ -238,6 +238,35 @@ else echo "[$resource_group_name] resource group already exists in the [$subscription_name] subscription" fi +# Recover the key vault if a previous run left it soft-deleted. +# Deleting a key vault only soft-deletes it, and the name stays reserved for the retention period, so +# re-running this script after deleting the resource group fails the create below with +# "A vault with the same name already exists in deleted state". Recovering restores the vault with its +# contents, which is what a re-run wants; purging would throw them away. +deleted_key_vault=$(az keyvault list-deleted \ + --query "[?name=='$key_vault_name'].name" \ + --output tsv \ + --only-show-errors 2>/dev/null) + +if [[ -n $deleted_key_vault ]]; then + echo "[$key_vault_name] key vault exists in a soft-deleted state in the subscription [$subscription_name]" + echo "Recovering the [$key_vault_name] key vault..." + + az keyvault recover \ + --name "$key_vault_name" \ + --location "$location" \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "[$key_vault_name] key vault successfully recovered" + else + echo "Failed to recover the soft-deleted [$key_vault_name] key vault" + echo "Discard it and re-run this script, or recover it by hand:" + echo " az keyvault purge --name $key_vault_name --location $location" + exit 1 + fi +fi + # Create Key Vault echo "Checking if [$key_vault_name] key vault actually exists in the [$resource_group_name] resource group..." az keyvault show \ diff --git a/scripts/01-user-assigned-managed-identity.sh b/scripts/01-user-assigned-managed-identity.sh index 586c92c..1eba920 100755 --- a/scripts/01-user-assigned-managed-identity.sh +++ b/scripts/01-user-assigned-managed-identity.sh @@ -239,6 +239,35 @@ else echo "[$resource_group_name] resource group already exists in the [$subscription_name] subscription" fi +# Recover the key vault if a previous run left it soft-deleted. +# Deleting a key vault only soft-deletes it, and the name stays reserved for the retention period, so +# re-running this script after deleting the resource group fails the create below with +# "A vault with the same name already exists in deleted state". Recovering restores the vault with its +# contents, which is what a re-run wants; purging would throw them away. +deleted_key_vault=$(az keyvault list-deleted \ + --query "[?name=='$key_vault_name'].name" \ + --output tsv \ + --only-show-errors 2>/dev/null) + +if [[ -n $deleted_key_vault ]]; then + echo "[$key_vault_name] key vault exists in a soft-deleted state in the subscription [$subscription_name]" + echo "Recovering the [$key_vault_name] key vault..." + + az keyvault recover \ + --name "$key_vault_name" \ + --location "$location" \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "[$key_vault_name] key vault successfully recovered" + else + echo "Failed to recover the soft-deleted [$key_vault_name] key vault" + echo "Discard it and re-run this script, or recover it by hand:" + echo " az keyvault purge --name $key_vault_name --location $location" + exit 1 + fi +fi + # Create Key Vault echo "Checking if [$key_vault_name] key vault actually exists in the [$resource_group_name] resource group..." az keyvault show \ From 8d0f6244e7e83b308e28e5acb5806b5189a3ab3e Mon Sep 17 00:00:00 2001 From: Paolo Salvatori Date: Thu, 6 Aug 2026 15:48:53 +0200 Subject: [PATCH 2/2] Recover a soft-deleted key vault in its own region, not the script's A soft-deleted vault stays in the region it was deleted in, and that region is part of how Azure addresses it (`/providers/Microsoft.KeyVault/locations//deletedVaults/`), so recovering or purging it with a different one does not resolve. The two regions differ as soon as the `location` at the top of the script is changed between runs, which also made the fallback message print a purge command that could not work. Both scripts now read the vault's own location from `az keyvault list-deleted` and use it for the recovery and for the printed purge command. That value doubles as the presence check, so it is one query rather than two. Verified against the emulator with the regions deliberately mismatched: a vault deleted in WestEurope while the script is configured for ItalyNorth is now recovered into WestEurope and disappears from the deleted list. Co-Authored-By: Claude Opus 5 --- scripts/01-system-assigned-managed-identity.sh | 15 +++++++++------ scripts/01-user-assigned-managed-identity.sh | 15 +++++++++------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/scripts/01-system-assigned-managed-identity.sh b/scripts/01-system-assigned-managed-identity.sh index 6dd2ff0..d109837 100755 --- a/scripts/01-system-assigned-managed-identity.sh +++ b/scripts/01-system-assigned-managed-identity.sh @@ -243,18 +243,21 @@ fi # re-running this script after deleting the resource group fails the create below with # "A vault with the same name already exists in deleted state". Recovering restores the vault with its # contents, which is what a re-run wants; purging would throw them away. -deleted_key_vault=$(az keyvault list-deleted \ - --query "[?name=='$key_vault_name'].name" \ +# The vault's own location, not $location: a soft-deleted vault stays in the region it was deleted in, +# so recovering (or purging) it with a different region fails. They differ whenever the location at the +# top of this script was changed between runs. +deleted_key_vault_location=$(az keyvault list-deleted \ + --query "[?name=='$key_vault_name'].properties.location | [0]" \ --output tsv \ --only-show-errors 2>/dev/null) -if [[ -n $deleted_key_vault ]]; then - echo "[$key_vault_name] key vault exists in a soft-deleted state in the subscription [$subscription_name]" +if [[ -n $deleted_key_vault_location ]]; then + echo "[$key_vault_name] key vault exists in a soft-deleted state in [$deleted_key_vault_location]" echo "Recovering the [$key_vault_name] key vault..." az keyvault recover \ --name "$key_vault_name" \ - --location "$location" \ + --location "$deleted_key_vault_location" \ --only-show-errors 1>/dev/null if [[ $? == 0 ]]; then @@ -262,7 +265,7 @@ if [[ -n $deleted_key_vault ]]; then else echo "Failed to recover the soft-deleted [$key_vault_name] key vault" echo "Discard it and re-run this script, or recover it by hand:" - echo " az keyvault purge --name $key_vault_name --location $location" + echo " az keyvault purge --name $key_vault_name --location $deleted_key_vault_location" exit 1 fi fi diff --git a/scripts/01-user-assigned-managed-identity.sh b/scripts/01-user-assigned-managed-identity.sh index 1eba920..32432f4 100755 --- a/scripts/01-user-assigned-managed-identity.sh +++ b/scripts/01-user-assigned-managed-identity.sh @@ -244,18 +244,21 @@ fi # re-running this script after deleting the resource group fails the create below with # "A vault with the same name already exists in deleted state". Recovering restores the vault with its # contents, which is what a re-run wants; purging would throw them away. -deleted_key_vault=$(az keyvault list-deleted \ - --query "[?name=='$key_vault_name'].name" \ +# The vault's own location, not $location: a soft-deleted vault stays in the region it was deleted in, +# so recovering (or purging) it with a different region fails. They differ whenever the location at the +# top of this script was changed between runs. +deleted_key_vault_location=$(az keyvault list-deleted \ + --query "[?name=='$key_vault_name'].properties.location | [0]" \ --output tsv \ --only-show-errors 2>/dev/null) -if [[ -n $deleted_key_vault ]]; then - echo "[$key_vault_name] key vault exists in a soft-deleted state in the subscription [$subscription_name]" +if [[ -n $deleted_key_vault_location ]]; then + echo "[$key_vault_name] key vault exists in a soft-deleted state in [$deleted_key_vault_location]" echo "Recovering the [$key_vault_name] key vault..." az keyvault recover \ --name "$key_vault_name" \ - --location "$location" \ + --location "$deleted_key_vault_location" \ --only-show-errors 1>/dev/null if [[ $? == 0 ]]; then @@ -263,7 +266,7 @@ if [[ -n $deleted_key_vault ]]; then else echo "Failed to recover the soft-deleted [$key_vault_name] key vault" echo "Discard it and re-run this script, or recover it by hand:" - echo " az keyvault purge --name $key_vault_name --location $location" + echo " az keyvault purge --name $key_vault_name --location $deleted_key_vault_location" exit 1 fi fi