Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8906

NodeアプリからAzure Key Vaultに接続する方法

$
0
0
Key Vaultに接続するためには必ず認証を行う必要がある。 主に どうやって認証を行うか が課題。 また前提条件として、Key Vaultにアクセスする際に APIキーのようなものを使わない (いくらkey-vault上に暗号化キーをセキュアに保存しても、APIキーなどをコード内に置いていたら意味ないため) Azure App ServiceにNodeアプリを デプロイ してからKey Vaultに接続する場合と、 ローカル のNodeアプリからKey Vaultに接続する場合に分けて紹介する。 Azure App ServiceにNodeアプリをデプロイしてからKey Vaultに接続する方法 マネージドID を使ってKey Vaultに接続するための認証を行う。 マネージドIDとは システム割り当てマネージド IDとユーザー割り当てマネージド IDの2種類がある。 簡単に説明すると、システム割り当てマネージドIDはAzureサービス(今回でいうとAzure App Service)の特有のIDで、このIDからの接続をKey Vaultの方で許可することで認証をパスすることができる。 ユーザー割り当てマネージドIDは、これ自体が1つのリソースとなっており、このIDをユーザーがAzureサービスに割り当てることで、マネージドIDをAzureサービスに持たせることができる。 今回はシステム割り当てマネージドIDを使う。 詳しくはAzure リソースのマネージド ID とは を参照。 設定方法 Azure App Serviceのリソースを作成する。 Azure App Serviceの設定→IDからシステム割り当て済みの状態を「オン」にする。 NodeアプリをApp Serviceにデプロイする。 Azure Key Vaultに戻り、設定→アクセスポリシーから「アクセスポリシーの追加」を押す。 適当な許可を選択し、プリンシパルの選択から先程のApp Serviceを選択し追加。 以上で設定は完了。 コードの中身と結果 まずはモジュールをインストール npm install @azure/identity npm install @azure/keyvault-keys npm install @azure/keyvault-secrets コードの中身 index.js const { ManagedIdentityCredential } = require("@azure/identity"); const { KeyClient,CryptographyClient } = require("@azure/keyvault-keys"); const { SecretClient } = require('@azure/keyvault-secrets') // Build the URL to reach your key vault const vaultName = "xxxxxxxxxxxxx"; //Key Vaultのリソース名 const url = `https://${vaultName}.vault.azure.net`; // Lastly, create our keys client and connect to the service const credential = new ManagedIdentityCredential() const keyName = "MyKeyName"; //キーの名前 const secretName = "secret-test" //シークレットの名前 async function main() { const client = new KeyClient(url, credential); //キー取得のためのclient const secretClient = new SecretClient(url, credential) //シークレット取得のためのclient const key = await client.getKey(keyName, "RSA"); const cryptographyClient = new CryptographyClient(key.id, credential) //暗号化、復号化のclient const encryptResult = await cryptographyClient.encrypt("RSA1_5", Buffer.from("My Message")); //暗号化結果 console.log("encrypt result: ", encryptResult.result); const decryptResult = await cryptographyClient.decrypt("RSA1_5", encryptResult.result); //復号化結果 console.log("decrypt result: ", decryptResult.result.toString()); const secretResult = await secretClient.getSecret(secretName) //シークレットの取得結果 console.log("secret result: ",secretResult) } main(); 結果 encrypt result: <Buffer xx xx xx xx xx xx xx xx xx xx ... 206 more bytes> decrypt result: My Message secret result: { value: 'test', name: 'secret-test', properties: { vaultUrl: 'https://xxxxxxxxxxxxxxxxx.vault.azure.net', expiresOn: undefined, createdOn: 2020-03-31T08:38:01.000Z, updatedOn: 2020-04-10T07:15:30.000Z, value: 'test', id: 'https://xxxxxxxxxxxxxx.vault.azure.net/secrets/secret-test/xxxxxxxxxxxxxxx', name: 'secret-test', version: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx', enabled: true, recoveryLevel: 'Recoverable+Purgeable' } } 参考: システム割り当てマネージドIDを使用してAzure Key Vaultにアクセスする クイック スタート:Node.js 用 Azure Key Vault クライアント ライブラリ (v4) @azure/identity - npm ローカルのNodeアプリからKey Vaultに接続する方法 こちらでは成功例と失敗例を示す まずは成功例(1個)を示した後、失敗例(複数個)を示す 成功例 DeviceCodeCredential(モジュール : @azure/identity)を使って認証を行う。 Nodeアプリを起動させると、URLとデバイスコードといわれる9桁のコードがコンソールに出力される。 そのURLにアクセスし、デバイスコードを入力するとAzureのアプリ(後述するところのrpa-test)にサインインすると認証をパスできる。 設定方法 AzureのホームからAzure Active Directory(AAD)にて、管理→アプリの登録→新規作成(今回はrpa-testと名付けた) 2. rpa-testの概要からテナントID、クライアントIDを取得 3. これらのIDを環境変数に書き込む(今回は、環境変数に書き込むのは面倒なので、.envファイルに書き込む) 4. rpa-testの認証から下の方にある アプリケーションは、パブリック クライアントとして扱います を「はい」にする 5. サポートされているアカウントの種類を、この組織ディレクトリのみに含まれるアカウント にする 6. key-vaultの方に戻る 7. key-vaultのアクセスポリシーにアクセスできるユーザーを追加する 以上で設定は完了 コードの中身と結果 コードの中身 index.js const { DeviceCodeCredential } = require("@azure/identity"); const { KeyClient,CryptographyClient } = require("@azure/keyvault-keys"); const { SecretClient } = require('@azure/keyvault-secrets') require('dotenv').config() // Build the URL to reach your key vault const vaultName = "xxxxxxxxxxxxxxxx"; const url = `https://${vaultName}.vault.azure.net`; // DeviceCodeCredentialの引数にさっき取得したテナントIDとクライアントIDを渡す const credential = new DeviceCodeCredential(process.env.AZURE_TENANT_ID,process.env.AZURE_CLIENT_ID,async function(err,credential){ if(err) console.log(err) else console.log(credential) }) const keyName = "MyKeyName"; const secretName = "secret-test" async function main() { const client = new KeyClient(url, credential); const secretClient = new SecretClient(url, credential) //シークレットのclient const key = await client.getKey(keyName, "RSA"); const cryptographyClient = new CryptographyClient(key.id, credential) //暗号化、復号化のclient const encryptResult = await cryptographyClient.encrypt("RSA1_5", Buffer.from("My Message")); //暗号化結果 console.log("encrypt result: ", encryptResult.result); const decryptResult = await cryptographyClient.decrypt("RSA1_5", encryptResult.result); //復号化結果 console.log("decrypt result: ", decryptResult.result.toString()); const secretResult = await secretClient.getSecret(secretName) //シークレットの取得結果 console.log("secret result: ",secretResult) } main(); 結果 { userCode: 'H3LSY66TU', verificationUri: 'https://microsoft.com/devicelogin', message: 'To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code XXXXXXXXX to authenticate.' } コンソールに出力されたURLにいくと... 先程のコンソールに出力されたコードを入力 サインインをする これでコンソールに結果が表示される { userCode: 'XXXXXXXXX', verificationUri: 'https://microsoft.com/devicelogin', message: 'To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code XXXXXXXXX to authenticate.' } encrypt result: <Buffer xx xx xx xx xx xx xx xx xx... > decrypt result: My Message secret result: { value: 'test', name: 'secret-test', properties: { vaultUrl: 'https://xxxxxxxxxxxxxxx.vault.azure.net', expiresOn: undefined, createdOn: 2020-03-31T08:38:01.000Z, updatedOn: 2020-04-10T07:15:30.000Z, value: 'test', id: 'https://xxxxxxxxxxxxx.vault.azure.net/secrets/secret-test/xxxxxxxxxxxxxxxxxxx', name: 'secret-test', version: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', enabled: true, recoveryLevel: 'Recoverable+Purgeable' } } 参考: DeviceCodeCredential | @azure/identity 失敗例 ここから失敗例を挙げていく なるべく簡潔に書くように努める DefaultAzureCredential(モジュール : @azure/identity) クイック スタート:Node.js 用 Azure Key Vault クライアント ライブラリ (v4) にも書いてあるやり方で、設定方法は途中まで成功例と似ている。コードも上述のURL内に書いてあるため省略。 設定方法 Azure Active Directory(AAD)にて、管理→アプリの登録→新規作成(今回はrpa-testと名付けた) rpa-testの概要からテナントID、クライアントIDを取得し、管理→証明書とシークレットから新しいクライアントシークレットを作成&クライアントシークレットIDを取得 これらのIDを環境変数に書き込む(今回は、環境変数に書き込むのは面倒なので、.envファイルに書き込む) Key Vaultに戻り、アクセスポリシーでrpa-testを追加 結果 キーやシークレットを取得でき、使用もできるが 結局、クライアントシークレットIDはAPIキーのようなものなので前提条件に当てはまらないため保留(失敗) msRestAzure.interactiveLogin(モジュール : ms-rest-azure) 成功例と非常に似ていて、nodeで起動させるとコンソールにURLとコードが出力される。成功例と異なる点は、成功例のDeviceCodeCredentialの引数にアプリケーション(先程のrpa-test)のテナントIDとクライアントIDを渡し、ブラウザではアプリケーションにサインインしていたが、こちらのinteractiveLoginは引数に何も渡さないので単純にAzureにログインしているだけという点。 結果 Key Vaultのアクセスポリシーにサインインするユーザーを追加していれば行けそうな気がしたが、エラーがでた →credentials must be one of: ApplicationTokenCredentials, UserTokenCredentials, DeviceTokenCredentials, MSITokenCredentials とのことで、そもそもこの認証ではアクセスできないため失敗 loginWithUsernamePassword(モジュール : ms-rest-azure) .NETとかNode.jsでKeyVaultを触るを参考にした。 引数にユーザー名とユーザーのパスワード渡すもの。 結果 以下のようなエラーが出た Error: Failed to acquire token for the user. you must use multi-factor authentication to access アクセスするためにはMFA(多段階認証)が必要といわれたため失敗 ほかに様々の方法を試したが、 このloginWithUsernamePasswordにマウスホバーすると Provides a UserTokenCredentials object. This method is applicable only for organizational ids that are not 2FA enabled. Otherwise please use interactive login. と書いてあって、2ファクタ認証には対応してない、interactiveなlogin を使えと書いてあるのに気づいた 先程のinteractiveLogin以外で、interactiveなloginする方法はないかと探したところ成功例にたどり着いた。 UserTokenCredentials(モジュール : ms-rest-azure) アプリケーションのclientIdとtenantId、またユーザー名とユーザーのパスワードを引数に渡す認証 Failed to acquire token for the user となり失敗 InteractiveBrowserCredential なぜかnode非対応 UsernamePasswordCredential 引数に要求されているのはアプリケーションのtenantId, clientId, ユーザー名, ユーザーのパスワードのみだが、なぜかエラーが出てアプリケーションのクライアントシークレットを要求されたため却下 http requestでauthorization codeを取得する OAuth 2.0 auth code grantを参考に、 http requestでauthorization codeを取得→accesstokenを取得→リソースにアクセス をやってみたが、レスポンスで返ってきたauthorizatin codeが見つからないので、保留 この記事について この記事はThinkings株式会社にて長期インターンの業務として社内Qiitaに投稿したものを、私の個人用Qiitaに再投稿したものになります。許可を受けて再投稿しております。 また、この記事は2020/04/17に社内Qiitaに投稿されたものです。

Viewing all articles
Browse latest Browse all 8906

Trending Articles