Agentic Skills 实战:用 TypeScript 在 Azure Key Vault 中安全管理密钥(azure-keyvault-secrets-ts)
【免费下载链接】agentic-awesome-skillsAAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and planning, backed by 2,400+ agentic skills. Includes CLI, local MCP, catalog, plugins, and Workbench.项目地址: https://gitcode.com/gh_mirrors/an/agentic-awesome-skills
导读
在 agentic-awesome-skills 项目的技能库中,azure-keyvault-secrets-ts/SKILL.md 是一份面向 JavaScript/TypeScript 开发者的 Azure Key Vault Secrets SDK 操作指南。它告诉你如何在 Node.js 应用中集中存储与读取密钥、如何用DefaultAzureCredential完成免配置认证、如何对密钥执行增删改查与版本管理,以及如何配套使用 Key Vault Keys 完成加密、签名、密钥包装与备份恢复。读完本文,你将能够在 TypeScript 项目中直接落地一套「凭据入 Vault、应用按需取」的密钥管理方案,并理解这份技能在 AAS 技能目录中的定位与使用边界。
技能定位:AAS 目录中的云安全技能
在 data/catalog.json 的目录记录中,azure-keyvault-secrets-ts被标注为:
category: cloud——归类于云平台技能;risk: critical——该技能涉及密钥与凭据的高危操作,使用前必须明确权限边界;source: community——来源于社区贡献;tags: ["azure", "keyvault", "secrets", "ts"]——便于 Agent 与搜索引擎按主题检索。
技能文件本身(SKILL.md)通过 YAML frontmatter 声明了name、description、risk与date_added等元数据,正文则以「安装 → 认证 → 操作 → 最佳实践 → 限制」的顺序组织。这与仓库中 docs/contributors/skill-anatomy.md 描述的技能结构规范一致:一份合格的技能必须同时给出触发条件、可执行步骤和明确的安全边界。
同主题技能还包括 azure-keyvault-keys-ts/SKILL.md(密钥管理)、azure-keyvault-py/SKILL.md(Python 版)以及 azure-keyvault/SKILL.md(含 CLI 的完整运维手册)。本技能聚焦「Secrets SDK for JavaScript」,是其中最小的、面向应用内嵌代码的切片。
安装与依赖
在 Node.js 项目中使用本技能,需要安装两个包:
npm install @azure/keyvault-secrets @azure/identity@azure/keyvault-secrets:Secrets 客户端 SDK,提供SecretClient及全部密钥操作;@azure/identity:认证库,提供DefaultAzureCredential等凭据类型。
注意:技能文档明确声明这些 SDK 仅支持 Node.js,不支持浏览器环境(见 SKILL.md 的 Best Practices 第 6 条)。如果你的代码运行在浏览器端,需要通过后端代理服务转发请求,切勿在前端直接引入该 SDK。
环境变量与 Vault 地址解析
技能支持两种环境变量写法,二选一即可:
KEY_VAULT_URL=https://<vault-name>.vault.azure.net # 或 AZURE_KEYVAULT_NAME=<vault-name>两种方式在代码中的区别在于:使用AZURE_KEYVAULT_NAME时,需要自行拼接出完整的 Vault URL(见下节认证代码)。建议在.env或部署平台的配置中心统一管理该变量,不要在代码中硬编码 Vault 名称。
认证:DefaultAzureCredential 的链路
import { DefaultAzureCredential } from "@azure/identity"; import { SecretClient } from "@azure/keyvault-secrets"; const credential = new DefaultAzureCredential(); const vaultUrl = `https://${process.env.AZURE_KEYVAULT_NAME}.vault.azure.net`; const secretClient = new SecretClient(vaultUrl, credential);DefaultAzureCredential是技能文档推荐的首选认证方式(Best Practices 第 1 条),它的价值在于一条代码同时覆盖开发与生产环境:在本地开发时它会依次尝试环境变量、Azure CLI 登录态、Visual Studio 凭据等来源;部署到 Azure(如 App Service、AKS、Functions)后会自动切换到托管身份(Managed Identity)。因此你无需在代码中维护多套认证分支。
注意:原技能示例中出现了
KeyClient的引用,但它属于@azure/keyvault-keys包,本节仅导入@azure/keyvault-secrets时KeyClient并不存在。若只需管理密钥,请忽略该行;若同时需要密钥操作,请一并安装@azure/keyvault-keys并参考 azure-keyvault-keys-ts/SKILL.md。
密钥(Secret)操作全解
写入密钥
// 最简写入 const secret = await secretClient.setSecret("MySecret", "secret-value"); // 带属性的写入 const secretWithAttrs = await secretClient.setSecret("MySecret", "value", { enabled: true, expiresOn: new Date("2025-12-31"), contentType: "application/json", tags: { environment: "production" } });setSecret的第三个参数是SetSecretOptions,其中:
enabled:是否立即启用,false表示写入但不激活;expiresOn:过期时间,过期后读取会失败(配合 Best Practices 第 3 条「为密钥设置过期时间」);contentType:便于标记 JSON、证书等类型;tags:任意键值对,可用于环境、团队、用途等维度检索。
读取密钥
// 获取最新版本 const secret = await secretClient.getSecret("MySecret"); console.log(secret.value); // 获取指定版本 const specificSecret = await secretClient.getSecret("MySecret", { version: secret.properties.version });Key Vault 的密钥天然具备版本化能力:每次setSecret都会产生一个新版本。默认getSecret返回最新版本;如需回滚或审计某个历史版本,可以显式传入version(版本号可从secret.properties.version或列出版本时取得)。
列出密钥与版本
for await (const secretProperties of secretClient.listPropertiesOfSecrets()) { console.log(secretProperties.name); } // 列出某密钥的全部版本 for await (const version of secretClient.listPropertiesOfSecretVersions("MySecret")) { console.log(version.version); }两个迭代器都是异步生成器(for await...of),返回的是属性(SecretProperties),而非密钥值本身——这符合最小权限原则:仅遍历名称与元数据时不会拉取敏感明文。
删除、恢复与永久清除
// 软删除(进入回收站) const deletePoller = await secretClient.beginDeleteSecret("MySecret"); await deletePoller.pollUntilDone(); // 永久清除(不可恢复) await secretClient.purgeDeletedSecret("MySecret"); // 恢复被软删除的密钥 const recoverPoller = await secretClient.beginRecoverDeletedSecret("MySecret"); await recoverPoller.pollUntilDone();删除操作全部采用Long-Running Operation(LRO)轮询模式:begin*返回轮询器(Poller),pollUntilDone()会阻塞直至操作完成。这与 azure-keyvault/SKILL.md 中 CLI 的az keyvault secret delete / recover / purge一一对应:
beginDeleteSecret↔az keyvault secret delete(软删除);beginRecoverDeletedSecret↔az keyvault secret recover;purgeDeletedSecret↔az keyvault secret purge(需关闭清除保护)。
技能文档的 Best Practices 第 2 条要求生产环境 Vault必须开启软删除(soft-delete),因此在生产环境中purgeDeletedSecret通常会被拒绝或需要二次确认。
配套:密钥(Key)与密码学操作
技能在 Keys Operations 一节还覆盖了@azure/keyvault-keys的能力(该技能目录同样收录于 azure-keyvault-keys-ts/SKILL.md),典型场景是把密钥(Secret)之外的加密密钥一并托管。
创建密钥
const keyClient = new KeyClient(vaultUrl, credential); // 通用 RSA 密钥 const key = await keyClient.createKey("MyKey", "RSA"); // 指定位数的 RSA const rsaKey = await keyClient.createRsaKey("MyRsaKey", { keySize: 2048 }); // 椭圆曲线密钥 const ecKey = await keyClient.createEcKey("MyEcKey", { curve: "P-256" }); // 带属性与操作许可 const keyWithAttrs = await keyClient.createKey("MyKey", "RSA", { enabled: true, expiresOn: new Date("2025-12-31"), tags: { purpose: "encryption" }, keyOps: ["encrypt", "decrypt", "sign", "verify"] });keyOps用于限定密钥允许的操作——这正是 Best Practices 第 5 条「限制密钥操作」的实现方式:只授予业务实际需要的操作(如仅encrypt/decrypt或仅sign/verify),降低密钥泄露后的危害半径。
密钥轮换
// 手动轮换 const rotatedKey = await keyClient.rotateKey("MyKey"); // 设置自动轮换策略 await keyClient.updateKeyRotationPolicy("MyKey", { lifetimeActions: [{ action: "Rotate", timeBeforeExpiry: "P30D" }], expiresIn: "P90D" });轮换策略中的时间单位使用 ISO 8601 时长(P30D= 30 天)。含义是:在密钥到期前 30 天触发一次轮换,新密钥有效期为 90 天。对应 CLI 中的az keyvault key rotate与az keyvault key rotation-policy update(详见 azure-keyvault/SKILL.md)。
加密 / 解密
import { CryptographyClient } from "@azure/keyvault-keys"; // 从密钥对象或密钥 ID 构建密码学客户端 const cryptoClient = new CryptographyClient(key, credential); // 或 const cryptoClient = new CryptographyClient(key.id!, credential); // 加密 const encryptResult = await cryptoClient.encrypt({ algorithm: "RSA-OAEP", plaintext: Buffer.from("My secret message") }); // 解密 const decryptResult = await cryptoClient.decrypt({ algorithm: "RSA-OAEP", ciphertext: encryptResult.result }); console.log(decryptResult.result.toString());CryptographyClient的加密/解密在服务端完成:私钥从不离开 HSM 或 Vault 边界,应用只提交密文/明文并获得结果。RSA-OAEP是 RSA 加密的标准填充方案;在 azure-keyvault/SKILL.md 的 CLI 示例中还出现了更强的RSA-OAEP-256(SHA-256 变体),可根据合规要求选用。
签名 / 验签
import { createHash } from "node:crypto"; // 生成消息摘要 const hash = createHash("sha256").update("My message").digest(); // 签名 const signResult = await cryptoClient.sign("RS256", hash); // 验签 const verifyResult = await cryptoClient.verify("RS256", hash, signResult.result); console.log("Valid:", verifyResult.result);签名流程遵循「先摘要、后签名」的标准做法:先在本地用node:crypto的createHash("sha256")计算摘要,再把摘要交给CryptographyClient.sign。RS256即 RSA + SHA-256 签名算法,verify返回布尔值表示签名是否有效。
密钥包装 / 解包
// 包装(加密)一段密钥材料以便安全存储 const wrapResult = await cryptoClient.wrapKey("RSA-OAEP", Buffer.from("key-material")); // 解包 const unwrapResult = await cryptoClient.unwrapKey("RSA-OAEP", wrapResult.result);Wrap/Unwrap 常用于信封加密(Envelope Encryption):用 Vault 中的主密钥加密数据密钥(DEK),数据密钥再加密业务数据。这样即使 DEK 泄露,没有主密钥也无法解开,且主密钥可独立轮换。
备份与恢复
const keyBackup = await keyClient.backupKey("MyKey"); const secretBackup = await secretClient.backupSecret("MySecret"); // 恢复(可以恢复到不同的 Vault) const restoredKey = await keyClient.restoreKeyBackup(keyBackup!); const restoredSecret = await secretClient.restoreSecretBackup(secretBackup!);备份返回的是二进制 blob,可用于跨 Vault 迁移或灾备恢复。技能文档特别注明「可以恢复到不同 Vault」——这是把密钥在订阅/区域之间搬运的官方途径之一(对应 CLI 的az keyvault secret backup/restore)。请把备份 blob 视为敏感数据妥善保管。
类型体系速查
技能文档给出了一份可直接使用的类型导入清单,便于在 TS 项目中声明变量类型:
import { KeyClient, KeyVaultKey, KeyProperties, DeletedKey, CryptographyClient, KnownEncryptionAlgorithms, KnownSignatureAlgorithms } from "@azure/keyvault-keys"; import { SecretClient, KeyVaultSecret, SecretProperties, DeletedSecret } from "@azure/keyvault-secrets";KeyVaultSecret/KeyVaultKey:读取到的完整对象,含value、properties;SecretProperties/KeyProperties:元数据(名称、版本、启用状态、过期时间、标签等);DeletedKey/DeletedSecret:软删除后的对象,可用于恢复前的信息核对;KnownEncryptionAlgorithms/KnownSignatureAlgorithms:SDK 导出的算法常量集合,避免手写字符串拼错。
错误处理
try { const secret = await secretClient.getSecret("NonExistent"); } catch (error: any) { if (error.code === "SecretNotFound") { console.log("Secret does not exist"); } else { throw error; } }Key Vault 的错误对象带有code字段。技能文档示范了基于SecretNotFound的判断分支——这是最常见的「密钥不存在」场景;此外还应关注Forbidden(权限不足)、Conflict(并发冲突)、KeyVaultError(服务端通用错误)等码位。合理的错误处理策略是:只捕获并处理预期错误,其余一律向上抛出,避免吞掉真正需要排查的异常。
最佳实践汇总
技能文档(Best Practices 一节)给出了六条可直接落地的准则:
- 使用 DefaultAzureCredential——一条代码覆盖开发与生产,无需多套认证分支;
- 开启软删除(soft-delete)——生产 Vault 的强制要求,防止误删不可恢复;
- 为密钥和加密密钥都设置过期时间——让临时凭据自动失效;
- 使用密钥轮换策略——把人工轮换升级为自动轮换(
updateKeyRotationPolicy); - 限制密钥操作(keyOps)——只授予
encrypt、sign等实际需要的操作; - 浏览器不支持——
@azure/keyvault-secrets系列 SDK 仅限 Node.js,前端必须经后端代理。
结合 azure-keyvault/SKILL.md 的运维手册,还有几条组织级实践值得补充:优先使用RBAC 授权而非传统访问策略(如Key Vault Secrets User角色只读、Key Vault Administrator全量管理);生产 Vault 建议--enable-purge-protection true防止清除保护被关闭;对 Vault 启用诊断日志(AuditEvent 类别)以便审计每次密钥访问。
适用场景与边界
何时使用本技能
技能的 frontmatter 与正文明确:当你需要在 TypeScript/JavaScript 应用中存储与读取应用密钥或配置值时,本技能适用。典型场景包括:数据库连接串、第三方 API Key、JWT 签名密钥等凭据的统一托管与按需读取。
使用限制
- 仅在任务明确匹配上述范围时使用本技能(Limitations 第 1 条);
- 技能输出不能替代环境专属的验证、测试或专家评审(Limitations 第 2 条);
- 若输入、权限、安全边界或成功标准缺失,应停下来请求澄清(Limitations 第 3 条);
risk: critical意味着执行删除、清除等破坏性操作前,必须确认拥有授权范围,并优先在非生产环境演练(这一点在 azure-keyvault/SKILL.md 中同样被强调)。
延伸阅读
- azure-keyvault-secrets-ts/SKILL.md —— 本文主体,完整代码示例
- azure-keyvault-keys-ts/SKILL.md —— 密钥(Key)与密码学操作的完整版
- azure-keyvault-py/SKILL.md —— Python 版 SDK 对应技能
- azure-keyvault/SKILL.md —— 含 Vault 创建、RBAC、AKS 集成(Secrets Store CSI Driver)的完整运维手册
- data/catalog.json —— 技能目录记录(category / risk / tags 元数据来源)
- docs/contributors/skill-anatomy.md —— AAS 技能结构规范
【免费下载链接】agentic-awesome-skillsAAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and planning, backed by 2,400+ agentic skills. Includes CLI, local MCP, catalog, plugins, and Workbench.项目地址: https://gitcode.com/gh_mirrors/an/agentic-awesome-skills
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考