クイックスタート: JavaScript 用 Azure Key Vault 証明書クライアント ライブラリ
JavaScript 用 Azure Key Vault 証明書クライアント ライブラリを使ってみます。 Azure Key Vault は、証明書のセキュリティで保護されたストアを提供するクラウド サービスです。 キー、パスワード、証明書、およびその他のシークレットを安全に保管することができます。 Azure Key Vault は、Azure Portal を使用して作成および管理できます。 このクイックスタートでは、JavaScript クライアント ライブラリを使って Azure キー コンテナー内の証明書を作成、取得、削除する方法について説明します。
Key Vault クライアント ライブラリのリソースは、次のとおりです。
API リファレンスのドキュメント | ライブラリのソース コード | パッケージ (npm)
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 パッケージをインストールする
ターミナルを使用して、Node.js 用の Azure Key Vault シークレット ライブラリ、@azure/keyvault-certificates をインストールします。
npm install @azure/keyvault-certificates
Key Vault の認証を行うために、Azure ID ライブラリ @azure/identity をインストールします。
npm install @azure/identity
キー コンテナーへのアクセス許可を付与する
ロールベースのアクセス制御 (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 ID クライアント ライブラリによって提供される DefaultAzureCredential メソッドを使うことは、コード内の Azure サービスへのパスワードレス接続を実装するための推奨される方法です。 DefaultAzureCredential
は複数の認証方法をサポートしており、実行時に使用する方法が決定されます。 このアプローチを採用すると、環境固有のコードを実装することなく、異なる環境 (ローカルと運用環境) で異なる認証方法をアプリに使用できます。
このクイックスタートでは、DefaultAzureCredential
は Azure CLI にログインしたローカル開発ユーザーの資格情報を使って、キー コンテナーに対して認証されます。 アプリケーションが Azure にデプロイされると、同じDefaultAzureCredential
コードで、App Service、仮想マシン、またはその他のサービスに割り当てられているマネージド ID を自動的に検出して使用できます。 詳細については、マネージド ID の概要に関するページを参照してください。
このコードでは、キー コンテナーのエンドポイントを使って、キー コンテナー クライアントを作成します。 エンドポイントの形式は https://<your-key-vault-name>.vault.azure.net
のようになりますが、ソブリン クラウドでは変わる可能性があります。 キー コンテナーに対する認証の詳細については、開発者ガイドを参照してください。
コードの例
このコードでは、次の Key Vault Certificate クラスとメソッドを使用します。
アプリのフレームワークを設定する
新しいテキスト ファイルを作成し、次のコードを 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 } }
App Configuration との統合
Azure SDK には、指定された Key Vault 証明書 ID を解析するためのヘルパー メソッド parseKeyVaultCertificateIdentifier が用意されています。これは、Key Vault への App Configuration 参照を使用する場合に必要です。 アプリ構成には、Key Vault 証明書 ID が格納されます。 証明書名を取得するには、その ID を解析するために parseKeyVaultCertificateIdentifier メソッドが必要です。 証明書名を取得したら、このクイックスタートのコードを使用して現在の証明書を取得できます。
次のステップ
このクイックスタートでは、キー コンテナーを作成し、証明書を格納して、その証明書を取得しました。 Key Vault およびアプリケーションとの統合方法の詳細については、引き続き以下の記事を参照してください。