Skip to content

Commit 9889d78

Browse files
Add soft-deleted check and purge (#104)
1 parent 72c4e8e commit 9889d78

File tree

6 files changed

+495
-22
lines changed

6 files changed

+495
-22
lines changed

.github/copilot-instructions.python.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ applyTo: "**/*.py"
2323
- Use 4-space indentation and PEP 8 conventions.
2424
- Use only straight quotes (U+0027 and U+0022), not typographic quotes.
2525
- Use whitespace to separate logical sections and add a blank line before `return` statements.
26+
- Use f-strings unless there is no interpolation.
2627

2728
## Import Style Guidelines
2829

TROUBLESHOOTING.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,99 @@ In one case, `%USERPROFILE%\.azure\bin` contained a `bicep.exe` file but with a
223223

224224
## Resource Management Issues
225225

226+
### Soft-Deleted Resources (APIM and Key Vault)
227+
228+
When you delete Azure API Management services or Key Vaults, they are soft-deleted and remain recoverable for a period of time (typically 48 days for APIM, 90 days for Key Vault). These soft-deleted resources continue to reserve their names and can cause deployment conflicts.
229+
230+
**Common Issues:**
231+
- Deployment fails with "Name already exists" even though resource appears deleted
232+
- Cannot reuse the same name for a new APIM service or Key Vault
233+
- Key Vault creation fails during infrastructure deployment
234+
- Subscription quotas are affected by soft-deleted resources
235+
236+
**Error During Infrastructure Deployment:**
237+
```
238+
Creating Key Vault: kv-sbfc4encghfag
239+
❌ Failed to create Key Vault: kv-sbfc4encghfag
240+
This may be caused by a soft-deleted Key Vault with the same name.
241+
Check for soft-deleted resources: python shared/python/show_soft_deleted_resources.py
242+
```
243+
244+
**Check for Soft-Deleted Resources:**
245+
```bash
246+
# Using Python script (recommended)
247+
python shared/python/show_soft_deleted_resources.py
248+
249+
# Manual check
250+
az apim deletedservice list
251+
az keyvault list-deleted
252+
```
253+
254+
**Purge Soft-Deleted Resources:**
255+
256+
⚠️ **WARNING:** Purging is permanent and irreversible. Resources cannot be recovered after purging.
257+
258+
```bash
259+
# Purge all soft-deleted resources with confirmation
260+
python shared/python/show_soft_deleted_resources.py --purge
261+
262+
# Purge without confirmation (use with caution!)
263+
python shared/python/show_soft_deleted_resources.py --purge --yes
264+
265+
# Manual purge
266+
az apim deletedservice purge --service-name <name> --location <location>
267+
az keyvault purge --name <name> --location <location>
268+
```
269+
270+
**Best Practices:**
271+
1. Check for soft-deleted resources before deploying with the same name
272+
2. Use unique names for resources to avoid conflicts
273+
3. Purge soft-deleted resources if you need to reuse the name immediately
274+
4. Consider using timestamps or random suffixes in resource names during development
275+
276+
#### Understanding Key Vault Purge Protection
277+
278+
Key Vaults can have **purge protection** enabled, which prevents them from being manually purged before their scheduled purge date. This is a security feature that cannot be disabled once enabled.
279+
280+
**Error When Purging Protected Key Vaults:**
281+
```
282+
(MethodNotAllowed) Operation 'DeletedVaultPurge' is not allowed.
283+
Code: MethodNotAllowed
284+
Message: Operation 'DeletedVaultPurge' is not allowed.
285+
```
286+
287+
**Identifying Purge Protection:**
288+
The `show_soft_deleted_resources.py` script automatically detects and displays purge protection status:
289+
```bash
290+
python shared/python/show_soft_deleted_resources.py
291+
```
292+
293+
Sample output:
294+
```
295+
1/2:
296+
Vault Name : kv-glgoiqn66pbnu
297+
Location : eastus2
298+
Deletion Date : 2025-12-13 10:30:00 UTC
299+
Purge Date : 2026-03-12 10:30:00 UTC
300+
Purge Protection : 🔒 ENABLED
301+
Vault ID : /subscriptions/.../vaults/kv-glgoiqn66pbnu
302+
303+
⚠️ 1 vault(s) have PURGE PROTECTION enabled and cannot be manually purged.
304+
These vaults will be automatically purged on their scheduled purge date.
305+
```
306+
307+
**Handling Purge-Protected Key Vaults:**
308+
-**Recoverable:** You can still recover the vault before the scheduled purge date
309+
-**Cannot purge manually:** The vault cannot be purged until its scheduled purge date
310+
- 💡 **Use different names:** Deploy new Key Vaults with different names
311+
- 🔒 **Security feature:** This is by design to prevent accidental data loss
312+
313+
**Recovery Option:**
314+
```bash
315+
# Recover a soft-deleted Key Vault (even with purge protection)
316+
az keyvault recover --name <vault-name>
317+
```
318+
226319
### Resource Group Does Not Exist
227320

228321
**Error Message:**

shared/python/infrastructures.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -861,13 +861,20 @@ def _create_keyvault(self, key_vault_name: str) -> bool:
861861
if not check_kv.success:
862862
# Create Key Vault via Azure CLI with RBAC authorization (consistent with Bicep module)
863863
print(f' Creating Key Vault: {key_vault_name}')
864-
az.run(
864+
create_kv = az.run(
865865
f'az keyvault create --name {key_vault_name} --resource-group {self.rg_name} --location {self.rg_location} --enable-rbac-authorization true',
866-
f'✅ Key Vault created: {key_vault_name}',
867-
'❌ Failed to create Key Vault',
868-
print_command_to_run = False
866+
print_command_to_run = False,
867+
print_errors = False
869868
)
870869

870+
if not create_kv.success:
871+
print(f' ❌ Failed to create Key Vault: {key_vault_name}')
872+
print(' This may be caused by a soft-deleted Key Vault with the same name.')
873+
print(' Check for soft-deleted resources: python shared/python/show_soft_deleted_resources.py\n')
874+
return False
875+
876+
print(f' ✅ Key Vault created: {key_vault_name}')
877+
871878
#Assign Key Vault Certificates Officer role to current user for certificate creation
872879

873880
# Key Vault Certificates Officer role
@@ -878,6 +885,7 @@ def _create_keyvault(self, key_vault_name: str) -> bool:
878885
)
879886
if not assign_kv_role.success:
880887
print(' ❌ Failed to assign Key Vault Certificates Officer role to current user')
888+
print(' This is an RBAC permission issue - verify your account has sufficient permissions.')
881889
return False
882890

883891
print(' ✅ Assigned Key Vault Certificates Officer role to current user')

0 commit comments

Comments
 (0)