Azure 代金券 微软云 Azure 账号 API 密钥保护

微软云Azure / 2026-04-21 22:50:16

你有没有在深夜收到一条 Slack 消息:「Alert: azure-qa-subscription 已有 3 台 VM 被用于挖矿,费用飙升至 $2,847/h」?

别急着重启——先查查你那张贴在 GitHub README 里的 AZURE_CLIENT_SECRET=xxx 是否还活着。

一、API 密钥不是密码,是云上身份证的复印件

很多人把 Azure 的「服务主体密钥」当成普通密码:设一个、藏好、忘了。错!它本质是长期有效的身份凭证,比密码危险十倍——它不依赖交互式登录,不触发 MFA,不校验 IP,只要泄露,攻击者就能以你的身份调用所有授权 API,创建资源、读取 Key Vault、导出 SQL 数据库备份……甚至开启 Azure Functions 免费薅羊毛挖门罗币。

我们见过最离谱的案例:某公司 DevOps 工程师为图省事,在 GitHub Action 的 .yml 文件里硬编码了服务主体密钥,并设置 secrets: read 权限——结果被 fork 后的恶意 PR 自动触发构建,密钥直接明文输出到日志流里。37 分钟后,攻击者用该密钥创建了 12 个 GPU 实例跑加密货币。

哪些密钥最常「裸奔」?

  • 服务主体客户端密钥(Client Secret):Azure AD 应用注册时生成,有效期默认 2 年,但 63% 的企业从不轮换;
  • 用户凭据(Username/Password):用于自动化脚本登录,一旦账户启用 MFA 就失效,且无法审计具体调用行为;
  • 访问令牌(Access Token):短期有效,但开发者常误存为环境变量,导致容器镜像层固化敏感信息;
  • Azure 代金券 存储账户密钥(Storage Account Keys):虽非严格意义的「API 密钥」,但拥有 Storage Blob Data Contributor 权限后,等同于开放整个 blob 容器的读写门禁卡。

二、四步断根法:让密钥「活不到上线」

保护密钥不是加个锁,而是让它压根没机会见光。

Step 1:永远别生成 Client Secret——改用证书或托管标识

执行这条命令前,请深呼吸:
az ad sp credential reset --name "my-app" --create-cert

它会自动生成 PFX 证书并绑定到服务主体,私钥只存本地磁盘(建议加密存储),公钥自动注册到 Azure AD。相比密钥,证书天然支持自动过期、吊销、多签验证,且 Azure CLI/SDK 原生支持(--cert & --key 参数)。

更激进?直接上 托管标识(Managed Identity)。VM、Function、Logic App 等资源启用后,Azure 自动分配一个 AD 对象 ID,无需任何密钥——代码里调用 DefaultAzureCredential() 即可静默获取 token。实测:某客户将 17 个 CI/CD Pipeline 迁移至系统分配托管标识后,密钥泄露事件归零。

Step 2:Key Vault 不是保险箱,是「带摄像头的金库」

很多团队把密钥塞进 Key Vault 就以为安全了,却忘了两件事:
① Key Vault 自身访问策略若允许「所有应用」读取,等于金库大门焊死,钥匙挂门口;
② 应用通过 MSI 访问 Key Vault 时,若未限制 get secret 权限粒度,等于给清洁工配了金库总钥匙。

正确姿势:
• 创建专用 Key Vault,关闭「允许 Azure 服务绕过防火墙」;
• 为每个应用分配独立访问策略,仅授予 get 权限,且限定具体 secret 名称(如 prod-db-conn-string);
• 开启 Key Vault 日志,对接 Log Analytics,配置告警:「1 小时内同一 identity 调用 get 超 50 次」→ 立即冻结关联服务主体。

Step 3:CI/CD 流水线里,密钥必须「即用即焚」

GitHub Actions / Azure DevOps 中,禁止使用 env:set-env: 注入密钥。正确做法:
• GitHub Actions:用 secrets.AZURE_CREDENTIALS + azure/login@v1 动态获取 token,token 生命周期与 job 绑定;
• Azure DevOps:启用 Variable Groups + Linked Service,密钥不落 pipeline YAML,而由 Agent 侧动态拉取;
• Docker 构建:绝对不用 --build-arg 传密钥!改用 BuildKit 的 --secret 机制,构建完自动销毁。

附赠一行防呆命令(CI 中运行):
echo "$AZURE_CLIENT_SECRET" | grep -q "[a-zA-Z0-9+/=]\{20,\}" && echo "❌ 密钥疑似泄露,中止构建" && exit 1

Step 4:监控不是摆设,是「密钥心跳仪」

Azure Monitor 默认不记录密钥类操作。手动补全:
• 在 Azure AD → 监控 → 日志中,新建查询:
SigninLogs | where AppDisplayName =~ "Microsoft Graph" and Status == "Success" and OperationName =~ "ApplicationManagement" | project TimeGenerated, UserPrincipalName, AppDisplayName, IPAddress, Resource
• 设置每 15 分钟运行,命中即发 Teams 告警;
• 关键动作强制二次确认:在 Azure Policy 中定义「禁止无 MFA 的服务主体密钥创建」,违反即 deny。

三、那些年我们踩过的坑(血泪复盘)

坑一:「临时密钥」用了三年
某客户说:“这个密钥只给测试环境用,反正没数据。” 结果测试环境连了生产 Key Vault 的网络对等互连……

坑二:Terraform state 文件里躺着 4 个密钥
state 存在公共 blob?未启用服务端加密?更绝的是,有人把 backend.tf 提交到了 GitHub,里面写着 storage_access_key = "xxxx"……

坑三:开发本地跑通就上线,忘了删调试代码
一段 print(os.environ.get('AZURE_CLIENT_SECRET')) 被遗忘在 Python Lambda 函数里,每次调用都往 CloudWatch Logs 写明文——日志组未设置保留策略,半年后被爬虫扫出。

四、终极 Checklist(打印贴显示器边)

  • □ 所有新服务主体禁用 Client Secret,强制用证书或 MSI;
  • □ Key Vault 访问策略按「最小权限+命名空间隔离」配置,禁用 wildcard;
  • □ CI/CD 中密钥绝不出现于 YAML/JSON/ENV 文件,一律走 secrets 注入;
  • □ 每季度自动轮换所有剩余 Client Secret(可用 Azure CLI + cron 脚本);
  • □ Azure AD 日志 + Key Vault 日志 + Activity Log 三日志聚合告警,延迟 ≤ 2 分钟;
  • □ 每次 Terraform apply 前,执行 tfsec 扫描,拦截硬编码密钥。

最后送一句大实话:
在云时代,「保护密钥」的本质不是技术问题,而是组织问题——当你发现团队还在用微信群发密钥截图时,请立刻叫停所有云迁移项目,先上安全意识培训课。

毕竟,再强的 RBAC,也挡不住一张微信聊天记录里的 base64 字符串。

Telegram售前客服
客服ID
@cloudcup
联系
Telegram售后客服
客服ID
@yanhuacloud
联系