MSAL Node (Web アプリ、デーモン アプリなど) を使用して、機密クライアント アプリケーションを構築できます。 機密 クライアントには、クライアント資格情報 が必須です。
Prerequisites
MSAL Node (Web アプリ、デーモン アプリなど) を使用して、機密クライアント アプリケーションを構築できます。 機密 クライアントには、クライアント資格情報 が必須です。 クライアント資格情報は次のようになります。
-
managed identity: これは証明書なしのシナリオであり、Azure インフラストラクチャを介して信頼が確立されます。 シークレット/証明書の管理は必要ありません。 MSAL はまだこの機能を実装していませんが、代わりに Azure Identity SDK を使用できます。 Azure リソースのマネージド ID に関するドキュメントを参照してください -
clientSecret: アプリの登録中に生成されたシークレット文字列、または既存のアプリケーションの登録後に更新されたシークレット文字列。 運用環境では、これはお勧めしません。 -
clientCertificate: アプリの登録中に設定された証明書。 MSAL によって生成される アサーション の署名に使用されるため、証明書には秘密キーが必要です。thumbprintSha256は証明書の X.509 SHA-256 拇印であり、privateKeyは PEM でエンコードされた秘密キーです。 -
clientAssertion: MSAL に アサーションを作成させる代わりに、アプリ開発者が制御します。 アサーションに追加の要求を追加する場合や、ローカル証明書ではなく署名に KeyVault を使用する場合に便利です。 アサーションの署名に使用する証明書は、アプリ登録時に引き続き設定する必要があります。
注: 1p アプリも x5cを送信する必要があります。 これは、サブジェクト名/発行者認証シナリオで使用される X.509 証明書チェーンです。
シークレットと証明書を安全に使用する
シークレットはハードコーディングしないでください。 dotenv npm パッケージを使用すると、シークレットの誤アップロードを防ぐために、.gitignore に含める必要がある .env ファイル (プロジェクトのルート ディレクトリにある) にシークレットまたは証明書を格納できます。
証明書は、NodeJS の fs モジュールを介してファイルから読み取ることもできます。 ただし、プロジェクトのディレクトリに保存しないでください。 運用アプリでは、Azure KeyVault またはその他のセキュリティで保護されたキー コンテナーから証明書をフェッチする必要があります。
詳細については、 証明書とシークレットを 参照してください。
MSAL サンプルを参照してください。 auth-code-with-certs
証明書の登録
証明書がない場合は、PowerShell または keyVault を使用して自己署名証明書Azure作成できます。
証明書をMicrosoft Entra IDにアップロードする必要があります。
- Azure ポータルに移動し、Microsoft Entra アプリの登録を選択します。
- 左側の [証明書とシークレット ] ブレードを選択します。
- [証明書の アップロード ] をクリックし、アップロードする証明書ファイル (例: example.crt) を選択します。
- 追加をクリックします。 証明書がアップロードされると、 拇印 (SHA-256)、 開始日、 および有効期限 の値が表示されます。
詳細については、「証明書をMicrosoft ID プラットフォームに登録する」を参照してください。
証明書を使用した MSAL ノードの初期化
const msal = require('@azure/msal-node');
require('dotenv').config(); // process.env now has the values defined in a .env file
const config = {
auth: {
clientId: "YOUR_CLIENT_ID",
authority: "https://login.microsoftonline.com/YOUR_TENANT_ID",
clientCertificate: {
thumbprintSha256: process.env.thumbprint,
privateKey: process.env.privateKey,
}
}
};
// Create msal application object
const cca = new msal.ConfidentialClientApplication(config);
thumbprintSha256とprivateKeyの両方が文字列である必要があります。
privateKey は、さらに次の形式である必要があります (PKCS#8)。
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDkpKPrsfpIijS3
z2HCpDsa7dxOsKIrm7F1AtGBjyB0yVDjlh/FA7jT5sd2ypBh3FVsZGJudQsLRKfE
// ...
-----END ENCRYPTED PRIVATE KEY-----
Note
または、秘密キーは、 -----BEGIN PRIVATE KEY----- (暗号化されていない PKCS#8) または -----BEGIN RSA PRIVATE KEY----- (PKCS#1) で始まる場合があります。 これらの形式も許容されます。 互換性のあるキーを PKCS#8 キー型に変換するには、次のコマンドを使用できます。
openssl pkcs8 -topk8 -inform PEM -outform PEM -in example.key -out example.key
秘密キーをパススルーで暗号化した場合 (または秘密キーが既に暗号化されている場合)、MSAL ノードに渡す前に暗号化を解除する必要があります。
重要: パスワードをソース コードにハードコーディングしないでください。 証明書の秘密キーと省略可能な descryption パスワードの両方を安全な場所 (例: Azure KeyVault) からフェッチし、Web API を使用して安全にデプロイする必要があります。
これは、Node の 暗号化モジュールを使用して行うことができます。 キーを解析してエクスポートするには、 createPrivateKey() メソッドを使用します。
const fs = require('fs');
const crypto = require('crypto');
const privateKeySource = fs.readFileSync('<path_to_key>/example.key')
const privateKeyObject = crypto.createPrivateKey({
key: privateKeySource,
passphrase: process.env.YOUR_PASSPHRASE,
format: 'pem'
});
const privateKey = privateKeyObject.export({
format: 'pem',
type: 'pkcs8'
});
(省略可能)pfx から pem への変換
OpenSSL は、 pfx でエンコードされた証明書ファイルを pem に変換するために使用できます。
openssl pkcs12 -in certificate.pfx -out certificate.pem
変換をプログラムで行う必要がある場合は、サード パーティのパッケージに依存する必要がある場合があります。Node.js にはネイティブメソッドが用意されていないためです。 たとえば、 node-forge のような一般的な TLS 実装を使用すると、次のことができます。
const forge = require('node-forge');
/**
* @param {string} pfx: certificate + private key combination in pfx format
* @param {string} passphrase: passphrase used to encrypt pfx file
* @returns {Object}
*/
function convertPFX(pfx, passphrase = null) {
const asn = forge.asn1.fromDer(forge.util.decode64(pfx));
const p12 = forge.pkcs12.pkcs12FromAsn1(asn, true, passphrase);
// Retrieve key data
const keyData = p12.getBags({ bagType: forge.pki.oids.pkcs8ShroudedKeyBag })[forge.pki.oids.pkcs8ShroudedKeyBag]
.concat(p12.getBags({ bagType: forge.pki.oids.keyBag })[forge.pki.oids.keyBag]);
// Retrieve certificate data
const certBags = p12.getBags({ bagType: forge.pki.oids.certBag })[forge.pki.oids.certBag];
const certificate = forge.pki.certificateToPem(certBags[0].cert)
// Convert a Forge private key to an ASN.1 RSAPrivateKey
const rsaPrivateKey = forge.pki.privateKeyToAsn1(keyData[0].key);
// Wrap an RSAPrivateKey ASN.1 object in a PKCS#8 ASN.1 PrivateKeyInfo
const privateKeyInfo = forge.pki.wrapRsaPrivateKey(rsaPrivateKey);
// Convert a PKCS#8 ASN.1 PrivateKeyInfo to PEM
const privateKey = forge.pki.privateKeyInfoToPem(privateKeyInfo);
console.log("Converted certificate: \n", certificate);
console.log("Converted key: \n", privateKey);
return {
certificate: certificate,
key: privateKey
};
}
(省略可能)HTTPS サーバーの作成
OAuth 2.0 プロトコルでは、可能な限り HTTPS 接続を使用することをお勧めします。 Azure App Serviceなどのほとんどのクラウド サービスでは、既定でプロキシ経由で HTTPS 接続が提供されます。 テスト目的で独自の HTTPS サーバーをセットアップする場合は、HTTPS サーバーの作成に関するガイダンス Node.js ドキュメントを参照してください。
ブラウザーのセキュリティ ポリシーをバイパスするには、OS の資格情報マネージャー / キー チェーンに自己署名証明書を追加する必要もあります。 その後もブラウザーに警告が表示されることがあります (Chrome など)。
Windowsユーザーの場合は、「方法: MMC スナップインで証明書を表示する」のガイドに従ってください。
Linux および MacOS ユーザーの場合は、証明書のインストール方法に関するオペレーティング システムのドキュメントを参照してください。
Warning
上記のコマンドを実行するには、 管理者 特権が必要な場合があります。
一般的な問題
場合によっては、AADSTS700027: Client assertion contains an invalid signature エラーなど、証明書を使用して認証しようとすると、Microsoft Entra IDからエラーが発生し、MSAL ノードの初期化に使用する証明書や秘密キーの形式が正しくないことを示す場合があります。 よくある理由は、MSAL Node に渡している証明書 / 秘密キーの文字列に、キャリッジ リターン(\r)や 改行(\n)などの予期しない文字が含まれていることです:
-----BEGIN CERTIFICATE-----\nMIIDDzCCAfegAwIBAgIJAMkyzQVK88NHMA0GCSqGSIb3DQEBBQUAMIGCMQswCQYDVQQGEwJTRTESMBAGA1UECBMJU3RvY2tob2xtMQ4wDAYDVQQHEwVLaXN0YTEQMA4G0fbkqbKulrchGbNgkankZtEVg4PGjobZq7B+njvcVa7SsWF/WLq5AUbw==\r\n-----END CERTIFICATE-----
または、証明書/キー ファイルに バッグ属性が含まれている場合があります。
Bag Attributes
localKeyID: 28 B5 8E 16 11 88 E9 00 58 D5 76 30 12 B9 59 B8 E4 CE 7C AA
subject=/C=UK/ST=Suffolk/L=Ipswich/O=Example plc/CN=alice
issuer=/C=UK/ST=Suffolk/L=Ipswich/O=Example plc/CN=Certificate Authority/emailAddress=ca@example.com\n
-----BEGIN CERTIFICATE-----
MIIDDzCCAfegAwIBAgIJAMkyzQVK88NHMA0GCSqGSIb3DQEBBQUAMIGCMQswCQYD
VQQGEwJTRTESMBAGA1UECBMJU3RvY2tob2xtMQ4wDAYDVQQHEwVLaXN0YTEQMA4G
0fbkqbKulrchGbNgkankZtEVg4PGjo+Y8MdMjtfSZB29hwYvfMX09jzJ68ZqmpYQ
njvcVtLbEZN5OGCkaslb/f2OxLbsUNgIbws538WnaaufDvKmQe2kUdWmpl9Wn9Bf
bZq7B+njvcVa7SsWF/WLq5AUbw==
-----END CERTIFICATE-----
このような場合は、MSAL ノード構成に渡す前に、文字列をクリーニングする必要があります。 次に例を示します。
const msal = require('@azure/msal-node');
const fs = require('fs');
const privateKeySource = fs.readFileSync('<path_to_key>/certs/example.key');
const privateKey = Buffer.from(privateKeySource, 'base64').toString().replace(/\r/g, "").replace(/\n/g, "");
const config = {
auth: {
clientId: "YOUR_CLIENT_ID",
authority: "https://login.microsoftonline.com/YOUR_TENANT_ID",
clientCertificate: {
thumbprintSha256: process.env.thumbprint,
privateKey: privateKey,
}
}
};
// Create msal application object
const cca = new msal.ConfidentialClientApplication(config);