4. Azure Key Vault 轮换:密钥版本管理与自动轮换配置

好,咱们进入 Azure 环境。Key Vault 是微软云上管密钥的标配,但很多人把它当成了「保险柜」——钥匙扔进去就不管了。这其实是个大坑。

我见过不少团队,密钥在 Key Vault 里躺了两年没动过。合规审计一来,直接亮红灯。为什么?因为密钥轮换不是「可选项」,而是很多合规框架(像 SOC 2、PCI DSS)的硬性要求。

这一章,咱们就聊聊 Key Vault 里怎么管密钥版本,怎么把轮换做成自动的。

4.1 密钥版本管理:Key Vault 的核心逻辑

Key Vault 里的每个密钥,其实都是一条「版本链」。你创建一个密钥,它自动生成一个版本号。你再更新一次,新版本就追加到链尾。

我个人习惯把版本管理想象成 Git 的 commit:

  • 当前版本:默认被启用的那个,应用程序默认用它加解密。
  • 历史版本:旧密钥还在,但状态可能是「已禁用」或「已过期」。
  • 版本 ID:每个版本有个唯一标识,像 https://myvault.vault.azure.net/keys/mykey/abc123 这样。

这里有个关键点:删除密钥不等于删除版本。Key Vault 的软删除机制会把整个密钥及其所有版本扔进回收站,保留 90 天。嗯,这既是保护也是隐患——你删了密钥,但审计日志里还能查到旧版本的使用记录。

核心原则:永远不要手动删除旧版本,除非你确认所有依赖它的系统都已经迁移完毕。我在项目中遇到过,有人删了旧版本,结果备份恢复脚本直接崩了——因为备份用的还是旧密钥。

4.2 手动轮换 vs 自动轮换

咱们先看两种方式的对比,你心里就有数了。

维度 手动轮换 自动轮换
操作方式 Azure Portal / CLI 手动创建新版本 Event Grid + Function / 定时任务触发
轮换频率 取决于人记不记得 按策略(30天/90天/自定义)
审计合规 容易遗漏,审计追责难 有日志、有记录,合规无忧
风险 人为失误、密钥泄露后响应慢 自动化脚本本身可能成为攻击面

说白了,手动轮换适合测试环境,生产环境必须上自动。你想想看,一个密钥泄露了,你还在手动点鼠标创建新版本?黄花菜都凉了。

4.3 自动轮换配置实战

Azure 官方推荐的方式是 Event Grid + Azure Functions。流程是这样的:

  1. Key Vault 里的密钥快要过期时,触发一个事件。
  2. Event Grid 捕获这个事件,推送给一个 Azure Function。
  3. Function 执行轮换逻辑:创建新版本、更新应用程序配置、禁用旧版本。

下面是一个简化版的 Function 代码,我用 C# 写的,但逻辑通用:

public static async Task Run(
    EventGridEvent eventGridEvent,
    ILogger log)
{
    log.LogInformation($"收到密钥过期事件: {eventGridEvent.Subject}");

    // 1. 解析事件中的密钥名称
    var keyName = eventGridEvent.Subject.Split('/').Last();

    // 2. 创建新版本
    var newKey = await keyClient.CreateKeyAsync(
        keyName,
        KeyType.Rsa,
        new CreateKeyOptions
        {
            ExpiresOn = DateTimeOffset.UtcNow.AddDays(90),
            Enabled = true
        });

    log.LogInformation($"新版本创建成功: {newKey.Value.Id}");

    // 3. 更新应用配置(这里假设用 App Configuration)
    await configurationClient.SetSecretAsync(
        $"{keyName}-current-version",
        newKey.Value.Id.ToString());

    // 4. 禁用旧版本(可选,建议保留一个窗口期)
    // 这里省略了获取旧版本 ID 的逻辑
}

我的经验:别急着禁用旧版本。我建议保留至少 24 小时的窗口期,让所有正在使用旧密钥的服务有时间切换到新版本。我曾经因为立即禁用旧版本,导致一批异步任务全部失败——教训深刻。

4.4 轮换策略设计

自动轮换不是「一键开启」就完事了。你需要设计策略。我个人习惯用这张表来规划:

密钥类型 建议轮换周期 触发方式 备注
加密密钥(RSA/AES) 90 天 基于时间 数据加密标准做法
签名密钥 180 天 基于时间 签名验证有缓存,不宜太频繁
临时令牌密钥 24 小时 基于事件 泄露后立即轮换
备份密钥 365 天 手动+自动 保留旧版本至少 2 个周期

你可能会问:为什么签名密钥周期更长?因为签名验证通常有缓存,你换得太频繁,下游系统还没拿到新公钥,签名验证就失败了。说白了,轮换不是越快越好,要考虑整个生态的适配速度。

4.5 避坑指南:我踩过的几个坑

  • 坑一:版本 ID 硬编码。我曾经看到有人把密钥版本 ID 直接写在配置文件里。轮换一次,改一次配置。这不是轮换,这是给自己找活干。正确做法是用 Key Vault 引用(@Microsoft.KeyVault(SecretUri=...)),或者用 App Configuration 动态获取当前版本。
  • 坑二:忽略软删除。Key Vault 默认开启软删除,你删了密钥,它还在回收站里。审计时能看到「已删除」状态,但如果你不清理,90 天内旧版本依然可以被恢复。合规审计会问:这些旧密钥为什么还在?
  • 坑三:轮换脚本没有监控。自动轮换跑失败了怎么办?我建议给 Function 加上告警,轮换失败直接发邮件或钉钉通知。不然你以为是自动的,结果密钥过期了还没人知道。

重要提醒:自动轮换脚本本身要有访问 Key Vault 的权限。这个权限要单独管理,不要用同一个服务主体。我曾经见过轮换脚本和生产应用用同一个凭据——轮换脚本出问题,连带着生产应用一起挂。

4.6 核心流程图:Key Vault 自动轮换架构

下面这张图展示了整个自动轮换的架构和数据流。我建议你保存下来,做方案设计时直接参考。

Azure Key Vault 自动轮换架构图 Key Vault 自动轮换架构 Azure Key Vault Event Grid Azure Function App Configuration 应用服务 密钥过期事件 推送事件 创建新版本 更新配置 获取最新版本 说明:密钥过期触发 Event Grid,Event Grid 调用 Function 创建新版本并更新配置,应用服务从 App Configuration 获取最新版本。 旧版本保留 24 小时窗口期,确保所有服务平滑切换。

4.7 审计视角:轮换日志怎么看

合规审计时,审计员会关注三件事:

  1. 轮换是否按策略执行:日志里有没有定期创建新版本的记录?
  2. 旧版本是否被妥善处理:是禁用还是删除?有没有保留过久?
  3. 轮换操作是谁触发的:是自动化脚本还是人工?人工操作需要额外审批记录。

在 Azure Monitor 里,你可以用这个 KQL 查询来检查轮换记录:

AzureDiagnostics
| where ResourceProvider == "MICROSOFT.KEYVAULT"
| where OperationName == "VaultCreateKey" or OperationName == "VaultDeleteKey"
| where TimeGenerated > ago(90d)
| project TimeGenerated, OperationName, CallerIPAddress, KeyName = split(ResourceId, '/')[-1]
| order by TimeGenerated desc

这个查询能帮你快速定位:哪些密钥在 90 天内被轮换过?哪些没有?审计员要的就是这种数据。

一句话总结:Key Vault 的密钥轮换,核心是版本管理 + 自动化触发。手动轮换只适合玩具环境,生产环境必须上 Event Grid + Function。别忘了加监控和告警,不然自动轮换变成「自动失效」就尴尬了。