你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

适用于 JavaScript 的 Azure Key Vault 密钥客户端库 - 版本 4.10.0

Azure Key Vault 是一项服务,可用于使用安全密钥加密身份验证密钥、存储帐户密钥、数据加密密钥、.pfx 文件和密码。 若要详细了解 Azure Key Vault,可能需要查看:什么是 Azure Key Vault?

Azure Key Vault 托管 HSM 是一种完全托管、高度可用的单租户标准云服务,可用于使用 FIPS 140-2 级别 3 验证的 HSM 来保护云应用程序的加密密钥。 若要详细了解 Azure Key Vault 托管 HSM,可能需要查看:什么是 Azure Key Vault 托管 HSM?

Azure Key Vault 密钥库客户端在针对托管 HSM 运行时支持 RSA 密钥、椭圆曲线(EC)密钥以及对称(oct)密钥,每个密钥在硬件安全模块(HSM)中具有相应的支持。 它提供用于创建、检索、更新、删除、清除、备份、还原以及列出密钥及其版本的作。

使用 Node.js 应用程序中 Azure Key Vault 密钥的客户端库可以:

  • 使用椭圆曲线或 RSA 加密创建密钥,(可选)由硬件安全模块(HSM)提供支持。
  • 导入、删除和更新密钥。
  • 获取一个或多个密钥和已删除的密钥及其属性。
  • 恢复已删除的密钥并还原备份的密钥。
  • 获取密钥的版本。

使用此库中提供的加密客户端,还可以访问:

  • 加密
  • 解密
  • 签名
  • 验证
  • 包装键
  • 解包密钥

注意:由于 Azure Key Vault 服务限制,无法在浏览器中使用此包,请参阅本文档 获取指导

关键链接:

入门指南

当前支持的环境

先决条件

  • 一个 Azure 订阅
  • 现有的 azure Key Vault 。 如果需要创建密钥保管库,可以按照本文档 中的步骤在 Azure 门户中执行此操作。 或者,按照 这些步骤使用 Azure CLI。
  • 如果使用托管 HSM,则现有的 Azure Key Vault 托管 HSM。 如果需要创建托管 HSM,可以按照本文档 中的步骤使用 Azure CLI。

安装软件包

使用 npm 安装 Azure Key Vault 密钥客户端库

npm install @azure/keyvault-keys

安装标识库

Azure Key Vault 客户端使用 Azure 标识库进行身份验证。 安装它以及使用 npm

npm install @azure/identity

配置 TypeScript

TypeScript 用户需要安装 Node 类型定义:

npm install @types/node

还需要在 tsconfig.json中启用 compilerOptions.allowSyntheticDefaultImports。 请注意,如果已启用 compilerOptions.esModuleInterop,则默认启用 allowSyntheticDefaultImports。 有关详细信息,请参阅 TypeScript 的编译器选项手册

重要概念

  • 密钥客户端 是与 JavaScript 应用程序中的密钥相关的 API 方法交互的主要接口。 初始化后,它提供可用于创建、读取、更新和删除密钥的基本方法集。
  • 密钥版本 是 Key Vault 中的密钥版本。 每当用户向唯一密钥名称分配值时,都会创建该密钥的新 版本。 除非向查询提供特定版本,否则按名称检索密钥将始终返回分配的最新值。
  • 软删除 允许 Key Vault 支持删除和清除作为两个单独的步骤,因此删除的密钥不会立即丢失。 仅当 Key Vault 已启用软删除 时,才会发生这种情况。
  • 可以从任何创建的密钥生成 密钥备份。 这些备份是二进制数据,只能用于重新生成以前删除的密钥。
  • 加密客户端 是一个单独的接口,与 Key Vault API 中的密钥 API 方法交互。 此客户端仅侧重于可以使用已在 Key Vault 中创建的密钥执行的加密作。 有关此客户端的详细信息,请参阅 加密 部分。

使用 Azure Active Directory 进行身份验证

Key Vault 服务依赖于 Azure Active Directory 对其 API 的请求进行身份验证。 @azure/identity 包提供了应用程序可用于执行此操作的各种凭据类型。 自述文件提供了更多详细信息和示例来帮助你入门。

若要与 Azure Key Vault 服务交互,需要创建 KeyClient 类的实例、保管库 URL 和凭据对象。 本文档中显示的示例使用名为 DefaultAzureCredential的凭据对象,该对象适用于大多数方案,包括本地开发和生产环境。 此外,我们建议在生产环境中使用 托管标识 进行身份验证。

可以在 Azure 标识文档中找到有关身份验证的不同方式及其相应凭据类型的详细信息。

下面是一个快速示例。 首先,导入 DefaultAzureCredentialKeyClient。 导入这些项后,接下来可以连接到 Key Vault 服务:

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

// Build the URL to reach your key vault
const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`; // or `https://${vaultName}.managedhsm.azure.net` for managed HSM.

// Lastly, create our keys client and connect to the service
const client = new KeyClient(url, credential);

指定 Azure Key Vault 服务 API 版本

默认情况下,此包使用 7.2的最新 Azure Key Vault 服务版本。 可以通过在客户端构造函数中设置选项 serviceVersion 来更改正在使用的服务版本,如下所示:

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

// Build the URL to reach your key vault
const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`; // or `https://${vaultName}.managedhsm.azure.net` for managed HSM.

// Change the Azure Key Vault service API version being used via the `serviceVersion` option
const client = new KeyClient(url, credential, {
  serviceVersion: "7.0", // Or 7.1
});

例子

以下部分提供了代码片段,这些代码片段涵盖了使用 Azure Key Vault 密钥完成的一些常见任务。 此处介绍的方案包括:

创建密钥

createKey 创建要存储在 Azure Key Vault 中的密钥。 如果已存在同名的密钥,则会创建密钥的新版本。

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

const keyName = "MyKeyName";
const result = await client.createKey(keyName, "RSA");
console.log("result: ", result);

发送到 createKey 的第二个参数是键的类型。 支持的密钥类型取决于 SKU,以及使用的是 Azure Key Vault 还是 Azure 托管 HSM。 有关支持的密钥类型的 up-to日期列表,请参阅 关于密钥

获取密钥

从保管库中读取密钥的最简单方法是按名称获取密钥。 这将检索密钥的最新版本。 如果将其指定为可选参数的一部分,可以选择获取不同版本的密钥。

getKey 检索 Key Vault 中的以前存储的密钥。

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

const keyName = "MyKeyName";

const latestKey = await client.getKey(keyName);
console.log(`Latest version of the key ${keyName}: `, latestKey);

const specificKey = await client.getKey(keyName, { version: latestKey.properties.version! });
console.log(`The key ${keyName} at the version ${latestKey.properties.version!}: `, specificKey);

使用属性创建和更新密钥

还可以将以下属性分配给 Key Vault 中的任何密钥:

  • tags:可用于搜索和筛选键的任何键值集。
  • keyOps:此键能够执行的作数组(encryptdecryptsignverifywrapKeyunwrapKey)。
  • enabled:一个布尔值,用于确定是否可以读取键值。
  • notBefore:一个给定日期,之后可以检索键值。
  • expires:给定日期,之后无法检索键值。

可以将具有这些属性的对象作为 createKey的第三个参数发送到键的名称和值之后,如下所示:

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

const keyName = "MyKeyName";

const result = await client.createKey(keyName, "RSA", {
  enabled: false,
});
console.log("result: ", result);

这将创建同一密钥的新版本,其中包含最新提供的属性。

还可以将属性更新为具有 updateKeyProperties的现有密钥版本,如下所示:

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

const keyName = "MyKeyName";

const result = await client.createKey(keyName, "RSA");
await client.updateKeyProperties(keyName, result.properties.version, {
  enabled: false,
});

删除密钥

beginDeleteKey 方法开始删除密钥。 一旦提供必要的资源,此过程就会在后台进行。

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

const keyName = "MyKeyName";

const poller = await client.beginDeleteKey(keyName);
await poller.pollUntilDone();

如果为 Key Vault 启用了软删除 ,此作只会将密钥标记为已删除 密钥。 无法更新已删除的密钥。 它们只能读取、恢复或清除。

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

const keyName = "MyKeyName";

const poller = await client.beginDeleteKey(keyName);

// You can use the deleted key immediately:
const deletedKey = poller.getResult();

// The key is being deleted. Only wait for it if you want to restore it or purge it.
await poller.pollUntilDone();

// You can also get the deleted key this way:
await client.getDeletedKey(keyName);

// Deleted keys can also be recovered or purged:

// recoverDeletedKey also returns a poller, just like beginDeleteKey.
const recoverPoller = await client.beginRecoverDeletedKey(keyName);
await recoverPoller.pollUntilDone();

// And here is how to purge a deleted key
await client.purgeDeletedKey(keyName);

由于密钥需要一些时间才能完全删除,beginDeleteKey 返回一个 Poller 对象,该对象根据我们的准则跟踪基础长时间运行作:https://azure.github.io/azure-sdk/typescript_design.html#ts-lro

接收的轮询器将通过调用 poller.getResult()来获取已删除的密钥。 还可以等待删除完成,方法是运行单个服务调用,直到删除密钥,或者等待进程完成:

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

const keyName = "MyKeyName";

const poller = await client.beginDeleteKey(keyName);

// You can use the deleted key immediately:
let deletedKey = poller.getResult();

// Or you can wait until the key finishes being deleted:
deletedKey = await poller.pollUntilDone();
console.log(deletedKey);

等待密钥完全删除的另一种方法是执行单个调用,如下所示:

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

const keyName = "MyKeyName";

const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const poller = await client.beginDeleteKey(keyName);

while (!poller.isDone()) {
  await poller.poll();
  await delay(5000);
}

console.log(`The key ${keyName} is fully deleted`);

配置自动密钥轮换

使用 KeyClient,可以通过指定轮换策略为密钥配置自动密钥轮换。 此外,KeyClient 还提供一种方法,通过创建给定密钥的新版本来按需轮换密钥。

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

const keyName = "MyKeyName";

// Set the key's automated rotation policy to rotate the key 30 days before expiry.
const policy = await client.updateKeyRotationPolicy(keyName, {
  lifetimeActions: [
    {
      action: "Rotate",
      timeBeforeExpiry: "P30D",
    },
  ],
  // You may also specify the duration after which any newly rotated key will expire.
  // In this case, any new key versions will expire after 90 days.
  expiresIn: "P90D",
});

// You can get the current key rotation policy of a given key by calling the getKeyRotationPolicy method.
const currentPolicy = await client.getKeyRotationPolicy(keyName);

// Finally, you can rotate a key on-demand by creating a new version of the given key.
const rotatedKey = await client.rotateKey(keyName);

循环访问密钥列表

使用 KeyClient,可以检索和循环访问 Azure Key Vault 中的所有密钥,以及所有已删除的密钥和特定密钥的版本。 可以使用以下 API 方法:

  • listPropertiesOfKeys 将按其名称列出所有未删除的密钥,仅按最新版本列出。
  • listDeletedKeys 将按其名称列出所有已删除的密钥,仅在最新版本中列出。
  • listPropertiesOfKeyVersions 将基于密钥名称列出密钥的所有版本。

可按如下所示使用:

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

const keyName = "MyKeyName";

for await (const keyProperties of client.listPropertiesOfKeys()) {
  console.log("Key properties: ", keyProperties);
}

for await (const deletedKey of client.listDeletedKeys()) {
  console.log("Deleted: ", deletedKey);
}

for await (const versionProperties of client.listPropertiesOfKeyVersions(keyName)) {
  console.log("Version properties: ", versionProperties);
}

所有这些方法将同时返回 所有可用结果。 若要按页面检索它们,请在调用要使用的 API 方法后立即添加 .byPage(),如下所示:

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

const keyName = "MyKeyName";

for await (const page of client.listPropertiesOfKeys().byPage()) {
  for (const keyProperties of page) {
    console.log("Key properties: ", keyProperties);
  }
}

for await (const page of client.listDeletedKeys().byPage()) {
  for (const deletedKey of page) {
    console.log("Deleted key: ", deletedKey);
  }
}

for await (const page of client.listPropertiesOfKeyVersions(keyName).byPage()) {
  for (const versionProperties of page) {
    console.log("Version: ", versionProperties);
  }
}

密码学

此库还提供一组通过 CryptographyClient提供的加密实用工具。 与 KeyClient类似,CryptographyClient 将使用提供的凭据集连接到 Azure Key Vault。 连接后,CryptographyClient 可以加密、解密、签名、验证、包装密钥和解包密钥。

接下来可以像 KeyClient一样连接到 Key Vault 服务。 我们需要从要连接到环境变量的密钥保管库复制一些设置。 进入环境后,可以使用以下代码访问它们:

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient, CryptographyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

// Create or retrieve a key from the keyvault
const myKey = await client.createKey("MyKey", "RSA");

// Lastly, create our cryptography client and connect to the service
const cryptographyClient = new CryptographyClient(myKey, credential);

加密

encrypt 将加密消息。

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient, CryptographyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

const myKey = await client.createKey("MyKey", "RSA");
const cryptographyClient = new CryptographyClient(myKey.id, credential);

const encryptResult = await cryptographyClient.encrypt({
  algorithm: "RSA1_5",
  plaintext: Buffer.from("My Message"),
});
console.log("encrypt result: ", encryptResult.result);

解密

decrypt 将解密加密的消息。

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient, CryptographyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

const myKey = await client.createKey("MyKey", "RSA");
const cryptographyClient = new CryptographyClient(myKey.id, credential);

const encryptResult = await cryptographyClient.encrypt({
  algorithm: "RSA1_5",
  plaintext: Buffer.from("My Message"),
});
console.log("encrypt result: ", encryptResult.result);

const decryptResult = await cryptographyClient.decrypt({
  algorithm: "RSA1_5",
  ciphertext: encryptResult.result,
});
console.log("decrypt result: ", decryptResult.result.toString());

签名

sign 将使用签名对消息的摘要(哈希)进行加密签名。

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient, CryptographyClient } from "@azure/keyvault-keys";
import { createHash } from "node:crypto";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

let myKey = await client.createKey("MyKey", "RSA");
const cryptographyClient = new CryptographyClient(myKey, credential);

const signatureValue = "MySignature";
const hash = createHash("sha256");

const digest = hash.update(signatureValue).digest();
console.log("digest: ", digest);

const signResult = await cryptographyClient.sign("RS256", digest);
console.log("sign result: ", signResult.result);

对数据进行签名

signData 将使用签名对消息进行加密签名。

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient, CryptographyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

const myKey = await client.createKey("MyKey", "RSA");
const cryptographyClient = new CryptographyClient(myKey, credential);

const signResult = await cryptographyClient.signData("RS256", Buffer.from("My Message"));
console.log("sign result: ", signResult.result);

验证

verify 将通过加密方式验证签名摘要是否已使用给定签名进行签名。

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient, CryptographyClient } from "@azure/keyvault-keys";
import { createHash } from "node:crypto";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

const myKey = await client.createKey("MyKey", "RSA");
const cryptographyClient = new CryptographyClient(myKey, credential);

const hash = createHash("sha256");
hash.update("My Message");
const digest = hash.digest();

const signResult = await cryptographyClient.sign("RS256", digest);
console.log("sign result: ", signResult.result);

const verifyResult = await cryptographyClient.verify("RS256", digest, signResult.result);
console.log("verify result: ", verifyResult.result);

验证数据

verifyData 将以加密方式验证签名的消息是否已使用给定签名进行签名。

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient, CryptographyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

const myKey = await client.createKey("MyKey", "RSA");
const cryptographyClient = new CryptographyClient(myKey, credential);

const buffer = Buffer.from("My Message");

const signResult = await cryptographyClient.signData("RS256", buffer);
console.log("sign result: ", signResult.result);

const verifyResult = await cryptographyClient.verifyData("RS256", buffer, signResult.result);
console.log("verify result: ", verifyResult.result);

打包密钥

wrapKey 将使用加密层包装密钥。

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient, CryptographyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

const myKey = await client.createKey("MyKey", "RSA");
const cryptographyClient = new CryptographyClient(myKey, credential);

const wrapResult = await cryptographyClient.wrapKey("RSA-OAEP", Buffer.from("My Key"));
console.log("wrap result:", wrapResult.result);

解包密钥

unwrapKey 将解包包装包装的密钥。

import { DefaultAzureCredential } from "@azure/identity";
import { KeyClient, CryptographyClient } from "@azure/keyvault-keys";

const credential = new DefaultAzureCredential();

const vaultName = "<YOUR KEYVAULT NAME>";
const url = `https://${vaultName}.vault.azure.net`;

const client = new KeyClient(url, credential);

const myKey = await client.createKey("MyKey", "RSA");
const cryptographyClient = new CryptographyClient(myKey, credential);

const wrapResult = await cryptographyClient.wrapKey("RSA-OAEP", Buffer.from("My Key"));
console.log("wrap result:", wrapResult.result);

const unwrapResult = await cryptographyClient.unwrapKey("RSA-OAEP", wrapResult.result);
console.log("unwrap result: ", unwrapResult.result);

故障排除

有关如何诊断各种故障方案的详细信息,请参阅 故障排除指南

启用日志记录可能有助于发现有关故障的有用信息。 若要查看 HTTP 请求和响应的日志,请将 AZURE_LOG_LEVEL 环境变量设置为 info。 或者,可以通过在 setLogLevel中调用 @azure/logger 在运行时启用日志记录:

import { setLogLevel } from "@azure/logger";

setLogLevel("info");

后续步骤

可以通过以下链接查找更多代码示例:

贡献

若要参与此库,请阅读 贡献指南 了解有关如何生成和测试代码的详细信息。