你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
快速入门:适用于 JavaScript 的 Azure 密钥保管库证书客户端库
适用于 JavaScript 的 Azure Key Vault 证书客户端库入门。 Azure Key Vault 是一项云服务,它为证书提供了安全的存储。 可以安全地存储密钥、密码、证书和其他机密。 可以通过 Azure 门户创建和管理 Azure Key Vault。 本快速入门介绍如何使用 JavaScript 客户端库在 Azure 密钥保管库中创建、检索和删除证书。
Key Vault 客户端库资源:
有关 Key Vault 和证书的详细信息,请参阅:
先决条件
- Azure 订阅 - 免费创建订阅。
- 当前 Node.js LTS。
- Azure CLI
- 现有的 Key Vault - 可以使用以下方法创建一个:
- Azure 订阅 - 免费创建订阅。
- 当前 Node.js LTS。
- TypeScript 5+
- Azure CLI
- 现有的 Key Vault - 可以使用以下方法创建一个:
本快速入门假设你运行 Azure CLI。
登录 Azure
运行
login
命令。az login
如果 CLI 可以打开默认浏览器,它将这样做并加载 Azure 登录页。
否则,请在 https://aka.ms/devicelogin 处打开浏览器页,然后输入终端中显示的授权代码。
在浏览器中使用帐户凭据登录。
创建新的 Node.js 应用程序
创建一个使用密钥保管库的 Node.js 应用程序。
在终端中,创建一个名为
key-vault-node-app
的文件夹并更改为该文件夹:mkdir key-vault-node-app && cd key-vault-node-app
初始化 Node.js 项目:
npm init -y
安装 Key Vault 包
使用终端安装 Azure Key Vault 机密库(适用于 Node.js 的 @azure/keyvault-certificates)。
npm install @azure/keyvault-certificates
安装 Azure 标识客户端库(@azure.identity)以对密钥保管库进行身份验证。
npm install @azure/identity
授予对 Key Vault 的访问权限
若要通过基于角色的访问控制 (RBAC) 授予对密钥保管库的权限,请使用 Azure CLI 命令 az role assignment create 将角色分配给你的“用户主体名称”(UPN)。
az role assignment create --role "Key Vault Certificate Officer" --assignee "<upn>" --scope "/subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.KeyVault/vaults/<your-unique-keyvault-name>"
将 <upn>、<subscription-id>、<resource-group-name> 和 <your-unique-keyvault-name> 替换为你的实际值。 你的 UPN 通常采用电子邮件地址格式(例如 username@domain.com)。
设置环境变量
此应用程序使用密钥保管库终结点作为名为 KEY_VAULT_URL
的环境变量。
set KEY_VAULT_URL=<your-key-vault-endpoint>
进行身份验证并创建客户端
对大多数 Azure 服务的应用程序请求必须获得授权。 要在代码中实现与 Azure 服务的无密码连接,推荐使用由 Azure 标识客户端库提供的 DefaultAzureCredential 方法。 DefaultAzureCredential
支持多种身份验证方法,并确定应在运行时使用哪种方法。 通过这种方法,你的应用可在不同环境(本地与生产)中使用不同的身份验证方法,而无需实现特定于环境的代码。
在本快速入门中,DefaultAzureCredential
使用登录到 Azure CLI 的本地开发用户的凭据对密钥保管库进行身份验证。 将应用程序部署到 Azure 时,相同的 DefaultAzureCredential
代码可以自动发现并使用分配给应用服务、虚拟机或其他服务的托管标识。 有关详细信息,请参阅托管标识概述。
在此代码中,密钥保管库的终结点用于创建密钥保管库客户端。 终结点格式类似于 https://<your-key-vault-name>.vault.azure.net
,但可能会根据不同的主权云而变化。 有关向密钥保管库进行身份验证的详细信息,请参阅开发人员指南。
代码示例
此代码使用以下密钥保管库证书类和方法:
设置应用框架
创建新文本文件并将以下代码粘贴到 index.js 文件中。
const { CertificateClient, DefaultCertificatePolicy } = require("@azure/keyvault-certificates"); const { DefaultAzureCredential } = require("@azure/identity"); async function main() { // If you're using MSI, DefaultAzureCredential should "just work". // Otherwise, DefaultAzureCredential expects the following three environment variables: // - AZURE_TENANT_ID: The tenant ID in Azure Active Directory // - AZURE_CLIENT_ID: The application (client) ID registered in the AAD tenant // - AZURE_CLIENT_SECRET: The client secret for the registered application const credential = new DefaultAzureCredential(); const keyVaultUrl = process.env["KEY_VAULT_URL"]; if(!keyVaultUrl) throw new Error("KEY_VAULT_URL is empty"); const client = new CertificateClient(keyVaultUrl, credential); const uniqueString = new Date().getTime(); const certificateName = `cert${uniqueString}`; // Creating a self-signed certificate const createPoller = await client.beginCreateCertificate( certificateName, DefaultCertificatePolicy ); const pendingCertificate = createPoller.getResult(); console.log("Certificate: ", pendingCertificate); // To read a certificate with their policy: let certificateWithPolicy = await client.getCertificate(certificateName); // Note: It will always read the latest version of the certificate. console.log("Certificate with policy:", certificateWithPolicy); // To read a certificate from a specific version: const certificateFromVersion = await client.getCertificateVersion( certificateName, certificateWithPolicy.properties.version ); // Note: It will not retrieve the certificate's policy. console.log("Certificate from a specific version:", certificateFromVersion); const updatedCertificate = await client.updateCertificateProperties(certificateName, "", { tags: { customTag: "value" } }); console.log("Updated certificate:", updatedCertificate); // Updating the certificate's policy: await client.updateCertificatePolicy(certificateName, { issuerName: "Self", subject: "cn=MyOtherCert" }); certificateWithPolicy = await client.getCertificate(certificateName); console.log("updatedCertificate certificate's policy:", certificateWithPolicy.policy); // delete certificate const deletePoller = await client.beginDeleteCertificate(certificateName); const deletedCertificate = await deletePoller.pollUntilDone(); console.log("Recovery Id: ", deletedCertificate.recoveryId); console.log("Deleted Date: ", deletedCertificate.deletedOn); console.log("Scheduled Purge Date: ", deletedCertificate.scheduledPurgeDate); } main().catch((error) => { console.error("An error occurred:", error); process.exit(1); });
运行示例应用程序
运行应用:
node index.js
create 和 get 方法为证书返回完整的 JSON 对象:
{ "keyId": undefined, "secretId": undefined, "name": "YOUR-CERTIFICATE-NAME", "reuseKey": false, "keyCurveName": undefined, "exportable": true, "issuerName": 'Self', "certificateType": undefined, "certificateTransparency": undefined }, "properties": { "createdOn": 2021-11-29T20:17:45.000Z, "updatedOn": 2021-11-29T20:17:45.000Z, "expiresOn": 2022-11-29T20:17:45.000Z, "id": "https://YOUR-KEY-VAULT-NAME-ENDPOINT/certificates/YOUR-CERTIFICATE-NAME/YOUR-CERTIFICATE-VERSION", "enabled": false, "notBefore": 2021-11-29T20:07:45.000Z, "recoveryLevel": "Recoverable+Purgeable", "name": "YOUR-CERTIFICATE-NAME", "vaultUrl": "https://YOUR-KEY-VAULT-NAME-ENDPOINT", "version": "YOUR-CERTIFICATE-VERSION", "tags": undefined, "x509Thumbprint": undefined, "recoverableDays": 90 } }
创建新的文本文件,并将以下代码粘贴到 index.ts 文件中。
import { CertificateClient, DefaultCertificatePolicy, KeyVaultCertificate, DeletedCertificate, CertificatePolicy, KeyVaultCertificateWithPolicy, } from "@azure/keyvault-certificates"; import { DefaultAzureCredential } from "@azure/identity"; import "dotenv/config"; const credential = new DefaultAzureCredential(); // Get Key Vault name from environment variables // such as `https://${keyVaultName}.vault.azure.net` const keyVaultUrl = process.env.KEY_VAULT_URL; if (!keyVaultUrl) throw new Error("KEY_VAULT_URL is empty"); function printCertificate( certificate: KeyVaultCertificate | KeyVaultCertificateWithPolicy ): void { console.log("-- printCertificate ---------------------------"); // if policy is defined, it's a KeyVaultCertificateWithPolicy if ((certificate as KeyVaultCertificateWithPolicy).policy) { const { name, properties, policy } = certificate as KeyVaultCertificateWithPolicy; const { createdOn, updatedOn, expiresOn, vaultUrl, version, tags } = properties; console.log("Certificate: ", { name, createdOn, updatedOn, expiresOn, vaultUrl, version, }); console.log("Certificate Policy: ", policy); printObjectProperties(tags); return; } else { const { name, properties } = certificate; const { createdOn, updatedOn, expiresOn, vaultUrl, version, tags } = properties; console.log("Certificate: ", { name, createdOn, updatedOn, expiresOn, vaultUrl, version, }); printObjectProperties(tags); } } // Object properties are tags and CertificatePolicy function printObjectProperties(obj: Record<string, any>): void { if (!obj) return; console.log("-- printObjectProperties ---------------------------"); Object.entries(obj).forEach(([key, value]) => { if (key === "lifetimeActions") { console.log(`${key}: ${JSON.stringify(value)}`); } else { console.log(`${key}: ${value}`); } }); } function printDeletedCertificate(deletedCertificate: DeletedCertificate): void { const { recoveryId, deletedOn, scheduledPurgeDate } = deletedCertificate; console.log("Deleted Certificate: ", { recoveryId, deletedOn, scheduledPurgeDate, }); } async function main(): Promise<void> { // Create a new CertificateClient const client = new CertificateClient(keyVaultUrl, credential); // Create a unique certificate name const uniqueString = new Date().getTime().toString(); const certificateName = `cert${uniqueString}`; // Creating a self-signed certificate const createPoller = await client.beginCreateCertificate( certificateName, DefaultCertificatePolicy ); // Get the created certificate const pendingCertificate = await createPoller.getResult(); printCertificate(pendingCertificate); // Get certificate by name let certificateWithPolicy = await client.getCertificate(certificateName); printCertificate(pendingCertificate); // Get certificate by version const certificateFromVersion = await client.getCertificateVersion( certificateName, certificateWithPolicy.properties.version! ); printCertificate(certificateFromVersion); // Update properties of the certificate const updatedCertificate = await client.updateCertificateProperties( certificateName, certificateWithPolicy.properties.version!, { tags: { customTag: "my value", }, } ); printCertificate(updatedCertificate); // Updating the certificate's policy const certificatePolicy = await client.updateCertificatePolicy( certificateName, { issuerName: "Self", subject: "cn=MyOtherCert", } ); printObjectProperties(certificatePolicy); // Get certificate again to see the updated policy certificateWithPolicy = await client.getCertificate(certificateName); printCertificate(certificateWithPolicy); // Delete certificate const deletePoller = await client.beginDeleteCertificate(certificateName); const deletedCertificate = await deletePoller.pollUntilDone(); printDeletedCertificate(deletedCertificate); } main().catch((error) => { console.error("An error occurred:", error); process.exit(1); });
运行示例应用程序
构建 TypeScript 应用:
tsc
运行应用:
node index.js
create 和 get 方法为证书返回完整的 JSON 对象:
{ "keyId": undefined, "secretId": undefined, "name": "YOUR-CERTIFICATE-NAME", "reuseKey": false, "keyCurveName": undefined, "exportable": true, "issuerName": 'Self', "certificateType": undefined, "certificateTransparency": undefined }, "properties": { "createdOn": 2021-11-29T20:17:45.000Z, "updatedOn": 2021-11-29T20:17:45.000Z, "expiresOn": 2022-11-29T20:17:45.000Z, "id": "https://YOUR-KEY-VAULT-NAME-ENDPOINT/certificates/YOUR-CERTIFICATE-NAME/YOUR-CERTIFICATE-VERSION", "enabled": false, "notBefore": 2021-11-29T20:07:45.000Z, "recoveryLevel": "Recoverable+Purgeable", "name": "YOUR-CERTIFICATE-NAME", "vaultUrl": "https://YOUR-KEY-VAULT-NAME-ENDPOINT", "version": "YOUR-CERTIFICATE-VERSION", "tags": undefined, "x509Thumbprint": undefined, "recoverableDays": 90 } }
与应用配置集成
Azure SDK 提供了帮助程序方法 parseKeyVaultCertificateIdentifier,用于解析给定的 Key Vault 证书 ID。如果你使用对 Key Vault 的应用配置引用,则该 ID 是必需的。 应用配置存储 Key Vault 证书 ID。 需要 parseKeyVaultCertificateIdentifier 方法来分析该 ID 以获取证书名称。 获取证书名称后,可以使用本快速入门中的代码获取当前证书。
后续步骤
在本快速入门中,你创建了一个密钥保管库,存储了一个证书,然后检索了该证书。 若要详细了解 Key Vault 以及如何将其与应用程序集成,请继续阅读以下文章。