如何用C#获取Azure软删除资源及Key Vault软删除条目
核心问题
你之前的实现逻辑从入口就错了,所以找不到对应数据:
- 订阅下被软删除的通用Azure资源不归属任何现存资源组,根本不会出现在资源组下的普通资源枚举结果里,查询入口直接在订阅层级,不需要遍历资源组
- 普通Key Vault资源下的
GetSecrets()、GetVaultKeys()方法返回的都是未删除的活跃条目,软删除状态的密钥、机密不会出现在这个列表里,你找不到相关属性是因为调错了接口
依赖调整
你现在安装的Compute、Network、Storage等beta包和当前软删除检测需求无关,可以直接移除,保留以下包即可:
<PackageReference Include="Azure.Identity" Version="1.6.0" /> <PackageReference Include="Azure.ResourceManager" Version="1.0.0" /> <PackageReference Include="Azure.ResourceManager.Resources" Version="1.0.0" /> <PackageReference Include="Azure.ResourceManager.KeyVault" Version="1.0.0-beta.8" /> <PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.3.0" /> <PackageReference Include="Azure.Security.KeyVault.Keys" Version="4.3.0" />
权限前置要求:
- 认证身份(本地调试的个人账号、Function托管标识)需要在订阅范围分配
Microsoft.Resources/deletedResources/read权限,才能读取通用软删除资源 - 同一身份需要拥有目标Key Vault数据平面的「列出已删除机密」「列出已删除密钥」权限,建议直接在订阅层级分配,避免逐KV配置
实现逻辑说明
1. 通用软删除资源查询
直接在订阅资源对象上调用GetDeletedResourcesAsync()方法即可,这个是Azure.ResourceManager.Resources 1.0稳定版自带的接口,返回结果包含软删除资源的名称、类型、原所属资源组、删除时间、计划永久删除时间等全量属性,不需要遍历资源组,还能查到原资源组已经被删除的软删除资源。
注意:只有开启了软删除功能的资源类型才会出现在结果里,未开启软删除的资源删除后会被直接清除,没有留存记录。
2. Key Vault软删除条目查询
分两步实现:
- 第一步直接在订阅层级枚举所有Key Vault资源,不需要遍历资源组,调用
subscription.GetVaultsAsync()即可拿到订阅下全部KV实例 - 第二步跳过未开启软删除的KV,对开启软删除的KV实例,用数据平面的
SecretClient、KeyClient调用GetDeletedSecretsAsync()、GetDeletedKeysAsync()方法,即可拿到所有软删除状态的机密、密钥,返回结果包含删除时间、计划清除时间等属性。如果需要查询软删除证书,新增CertificateClient调用GetDeletedCertificatesAsync()即可,逻辑完全一致。
可运行代码示例
替换你原来的DoSomething方法即可:
private async Task DoSomething(ILogger log) { // 生产/本地通用认证类,本地自动读VS登录凭据,部署后自动用Function托管标识 var credentials = new DefaultAzureCredential(new DefaultAzureCredentialOptions { ExcludeVisualStudioCodeCredential = true, ExcludeSharedTokenCacheCredential = true, ExcludeInteractiveBrowserCredential = true }); var subscriptionId = Environment.GetEnvironmentVariable(Settings.SubscriptionId); ArmClient client = new ArmClient(credentials, subscriptionId); var subscription = await client.GetDefaultSubscriptionAsync(); // 扫描通用软删除资源 log.LogInformation("开始扫描订阅通用软删除资源"); await foreach (var deletedResource in subscription.GetDeletedResourcesAsync()) { var resData = deletedResource.Data; log.LogInformation($"发现软删除资源:名称{resData.Name},类型{resData.ResourceType},原资源组{resData.Properties?.ResourceGroup},删除时间{resData.Properties?.DeletedOn},计划清除时间{resData.Properties?.ScheduledPurgeOn}"); // 此处添加自定义存储、告警逻辑 } // 扫描Key Vault软删除条目 log.LogInformation("开始扫描Key Vault软删除条目"); await foreach (var vault in subscription.GetVaultsAsync()) { var vaultProp = vault.Data.Properties; // 未开软删除的KV不存在软删除条目,直接跳过 if (vaultProp.EnableSoftDelete != true) { log.LogInformation($"Key Vault {vault.Data.Name} 未开启软删除,跳过扫描"); continue; } var vaultUri = new Uri($"https://{vault.Data.Name}.vault.azure.net/"); // 查询软删除机密 var secretClient = new SecretClient(vaultUri, credentials); await foreach (var deletedSecret in secretClient.GetDeletedSecretsAsync()) { log.LogInformation($"KV {vault.Data.Name} 发现软删除机密:名称{deletedSecret.Name},删除时间{deletedSecret.DeletedOn},计划清除时间{deletedSecret.ScheduledPurgeDate}"); // 自定义处理逻辑 } // 查询软删除密钥 var keyClient = new KeyClient(vaultUri, credentials); await foreach (var deletedKey in keyClient.GetDeletedKeysAsync()) { log.LogInformation($"KV {vault.Data.Name} 发现软删除密钥:名称{deletedKey.Name},删除时间{deletedKey.DeletedOn},计划清除时间{deletedKey.ScheduledPurgeDate}"); // 自定义处理逻辑 } } }
注意事项
- 完全移除遍历资源组的逻辑,两个查询入口都在订阅层级,遍历资源组不仅效率低,还会漏掉原资源组已经被删除的软删除资源
- 不要使用写死的
VisualStudioCredential,部署到Azure后这个认证方式会直接失败,用DefaultAzureCredential即可兼容本地调试和生产环境 - 如果需要扫描管理组范围的软删除资源,把入口换成
ManagementGroupResource的对应扩展方法即可,逻辑和订阅级完全一致 - Key Vault默认软删除保留期是90天,其他资源类型保留期根据配置不同有差异,可以根据返回的
ScheduledPurgeDate字段做分级告警
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

