サービス プリンシパルを使用したローカル開発時に Azure サービスに対して JavaScript アプリを認証する

クラウド アプリケーションを作成する場合、開発者はローカル ワークステーションでアプリケーションをデバッグおよびテストする必要があります。 ローカル開発時に開発者のワークステーションでアプリケーションを実行する場合でも、アプリで使用されるすべての Azure サービスに対して認証する必要があります。 この記事では、ローカル開発時に使用する専用のアプリケーション サービス プリンシパル オブジェクトを設定する方法について説明します。

ローカルで開発中の JavaScript アプリが、開発者の資格情報を使用し、ローカルにインストールされた開発ツールから資格情報を取得することで Azure に接続する方法を示す図。

ローカル開発用の専用アプリケーション サービス プリンシパルを使用すると、アプリ開発時に最小限の特権の原則に従うことができます。 アクセス許可のスコープは開発時にアプリに必要なものだけに設定されるため、別のアプリで使用することを目的とした Azure リソースにアプリ コードが誤ってアクセスすることはありません。 また、この方法では、開発環境でアプリが過剰な特権を持っていたために、アプリが運用環境に移動されたときにバグが発生するのを防ぐことができます。

アプリが Azure に登録されると、アプリケーション サービス プリンシパルがアプリ用に設定されます。 ローカル開発用にアプリを登録する場合は、次の手順を実行することをお勧めします。

  • アプリで作業する開発者ごとに個別のアプリ登録を作成します。 この方法では、ローカル開発時に使用する各開発者に対して個別のアプリケーション サービス プリンシパルが作成され、開発者が 1 つのアプリケーション サービス プリンシパルの資格情報を共有する必要がなくなります。
  • アプリごとに個別のアプリ登録を作成します。 これにより、アプリのアクセス許可のスコープがアプリに必要なものだけに設定されます。

ローカル開発時に、環境変数はアプリケーション サービス プリンシパルの ID で設定されます。 Azure SDK for JavaScript では、これらの環境変数を読み取り、この情報を使用して、必要な Azure リソースに対してアプリが認証されます。

1 - Azure にアプリケーションを登録する

アプリケーション サービス プリンシパル オブジェクトは、Azure でアプリの登録を使用して作成されます。 サービス プリンシパルは、Azure portal または Azure CLI を使用して作成できます。

Azure portal にサインインして、次の手順を実行します。

手順 Screenshot
Azure portal で、次の操作を行います。
  1. Azure portal の上部にある検索バーに「アプリの登録」と入力します。
  2. 検索バーの下に表示されるメニューの [サービス] の下にある [アプリの登録] と書かれた項目を選択します。
Azure portal の上部の検索バーを使用して、[アプリの登録] ページを検索してそこに移動する方法を示すスクリーンショット。
[アプリの登録] ページで、[+ 新規登録] を選択します。 [アプリの登録] ページの [新規登録] ボタンの場所を示すスクリーンショット。
[アプリケーションの登録] ページで、次のようにフォームに入力します。
  1. 名前 → Azure でのアプリ登録の名前を入力します。 この名前には、アプリ名、アプリ登録の対象となるユーザー、このアプリの登録がローカル開発で使用されることを示す識別子 ("dev" など) を含めるようにすることをお勧めします。
  2. サポートされているアカウントの種類この組織のディレクトリ内のアカウントのみ
[登録] を選択してアプリを登録し、アプリケーション サービス プリンシパルを作成します。
アプリに名前を付け、サポートされているアカウントの種類をこの組織ディレクトリ内のアカウントとしてのみ指定することで、[アプリケーションの登録] ページに入力する方法を示すスクリーンショット。
お使いのアプリの [アプリの登録] ページで、次の操作を行います。
  1. アプリケーション (クライアント) ID → ローカル開発時にアプリが Azure にアクセスするために使用するアプリ ID です。 この値は、後の手順で必要になるので、テキスト エディターで一時的な場所にコピーします。
  2. ディレクトリ (テナント) ID → この値は、Azure に対して認証するときにもアプリで必要になります。 この値も後の手順で必要になるので、テキスト エディターで一時的な場所にコピーします。
  3. クライアント資格情報 → アプリが Azure に対して認証して Azure サービスを使用する前に、アプリのクライアント資格情報を設定する必要があります。 [証明書またはシークレットの追加] を選択して、アプリの資格情報を追加します。
アプリの登録が完了した後のスクリーンショット。アプリケーション ID、テナント ID の場所が表示されている。
[証明書とシークレット] ページで、[+ 新しいクライアント シークレット] を選びます。 証明書とシークレット ページで新しいクライアント シークレットを作成するために使用するリンクの場所を示すスクリーンショット。
[クライアント シークレットの追加] ダイアログがページの右側から表示されます。 このダイアログで、次の操作を行います。
  1. 説明現在の値を入力します。
  2. 有効期限 → "24 か月"の値を選択します。
[追加] を選択してシークレットを追加します。
アプリ登録プロセスによって作成されるアプリケーション サービス プリンシパル用に新しいクライアント シークレットが追加されるページを示すスクリーンショット。
[証明書とシークレット] ページに、クライアント シークレットの値が表示されます。

この値は、後の手順で必要になるので、テキスト エディターで一時的な場所にコピーします。

重要: この値が表示されるのはこのタイミングだけです。 このページを終了または更新すると、この値を再度表示できなくなります。 このクライアント シークレットを無効にすることなく、さらにクライアント シークレットを追加できますが、この値は再度表示されません。
生成されたクライアント シークレットを含むページを示すスクリーンショット。

2 - ローカル開発用の Microsoft Entra セキュリティ グループを作成する

通常、アプリケーションで作業する開発者は複数いるため、個々のサービス プリンシパル オブジェクトにロールを割り当てるのではなく、Microsoft Entra グループを作成して、アプリがローカル開発で必要とするロール (アクセス許可) をカプセル化することをお勧めします。 これには次のような利点があります。

  • ロールはグループ レベルで割り当てられるため、すべての開発者に同じロールが割り当てられることが保証されます。
  • アプリに新しいロールが必要な場合は、アプリの Microsoft Entra グループに追加するだけで済みます。
  • 新しい開発者がチームに参加する場合は、アプリで作業するための適切なアクセス許可が開発者に与えられるように、その開発者用に新しいアプリケーション サービス プリンシパルを作成してグループに追加します。
手順 Screenshot
ページの上部にある検索ボックスに「Microsoft Entra ID」と入力し、サービスの下から Microsoft Entra ID を選択して、Azure Portal の [Microsoft Entra ID] ページに移動します。 Azure portal の上部にある検索バーを使用して Microsoft Entra ID ページを検索し、移動する方法を示すスクリーンショット。
[Microsoft Entra ID] ページで、左側のメニューから [グループ] を選択します。 Microsoft Entra ID の既定のディレクトリ ページの左側のメニューにある「グループ」メニュー項目の場所を示すスクリーンショット。
[すべてグループ] ページで、[新しいグループ] を選択します。 [すべてのグループ] ページの [新しいグループ] ボタンの場所を示すスクリーンショット。
[新しいグループ] ページで、次の操作を行います。
  1. グループの種類セキュリティ
  2. グループ名 →通常はアプリケーション名から作成される、セキュリティ グループの名前です。 また、グループの名前に "local-dev" のような文字列を含め、グループの目的も示すと便利です。
  3. グループの説明 → グループの目的の説明。
  4. [メンバー] の下の [メンバーが選択されていません] リンクを選択して、グループにメンバーを追加します。
アプリケーションの新しい Microsoft Entra グループを作成する方法を示すスクリーンショット。
[メンバーの追加] ダイアログ ボックスで、次の操作を行います。
  1. 検索ボックスを使用して、一覧で、プリンシパル名の一覧をフィルター処理します。
  2. このアプリのローカル開発用のアプリケーション サービス プリンシパルを選択します。 オブジェクトを選択すると、灰色表示され、ダイアログの下部にある [選択された項目] リストに移動します。
  3. 終わったら、[選択] ボタンを選択します。
グループに含めるアプリケーション サービス プリンシパルを選択する方法を示す [メンバーの追加] ダイアログ ボックスのスクリーンショット。
[新規グループ] ページに戻り、[作成] を選択して、グループを作成します。

グループが作成され、[すべてのグループ] ページに戻ります。 グループが表示されるまでに最大 30 秒かかる場合があり、Azure portal でのキャッシュのためにページの更新が必要になる場合があります。
[作成] ボタンを選択してプロセスを完了する方法を示す [新しいグループ] ページのスクリーンショット。

3 - アプリケーションにロールを割り当てる

次に、アプリで必要なリソースに対して必要なロール (アクセス許可) を決定し、それらのロールをアプリに割り当てる必要があります。 この例では、手順 2 で作成した Microsoft Entra グループにロールが割り当てられます。 ロールは、リソース、リソース グループ、またはサブスクリプション スコープで割り当てることができます。 次に、ほとんどのアプリケーションがすべてのAzureリソースを1つのリソースグループにグループ化するため、リソースグループスコープでロールを割り当てる例を示します。

手順 Screenshot
Azure portal の上部にある検索ボックスを使用してリソース グループ名を検索し、アプリケーションのリソース グループを見つけます。

ダイアログ ボックスの [リソース グループ] 見出しの下にあるリソース グループ名を選択して、リソース グループに移動します。
Azure portal の上部にある検索ボックスを使って、ロール (アクセス許可) の割り当て対象のリソース グループを検索してそこに移動する方法を示すスクリーンショット。
リソース グループのページで、左側のメニューから [アクセス制御 (IAM)] を選択します。 アクセス制御 (IAM) メニュー項目の場所を示すリソース グループ ページのスクリーンショット。
[アクセス制御 (IAM)] ページで、次の操作を行います。
  1. [ロールの割り当て] タブを選択します。
  2. 上部のメニューから [+ 追加] を選択し、次に結果のドロップダウン メニューから [ロールの割り当ての追加] を選択します。
[ロールの割り当て] タブへの移動方法と、ロールの割り当てをリソース グループに追加するボタンの場所を示すスクリーンショット。
[ロールの割り当ての追加] ページには、リソース グループで割り当てることができるすべてのロールが一覧表示されます。
  1. 検索ボックスを使用して、より管理しやすいサイズにリストをフィルター処理します。 この例では、Storage BLOB ロールをフィルター処理する方法を示します。
  2. 割り当てるロールを選択します。
    [次へ] を選択して、次の画面に進みます。
リソース グループに追加するロールの割り当てを見つけるためにフィルター処理して選択する方法を示すスクリーンショット。
次の [ロールの割り当ての追加] ページでは、ロールを割り当てるユーザーを指定できます。
  1. [アクセスの割り当て先] で、[ユーザー、グループ、またはサービス プリンシパル] を選択します。
  2. [メンバー][+ メンバーの選択] を選択する
Azure portal の右側でダイアログ ボックスが開きます。
Microsoft Entra グループにロールを割り当てる際に選択するラジオ ボタンと、ロールを割り当てるグループを選択する際に使用されるリンクを示すスクリーンショット。
[メンバーの選択] ダイアログで、次の操作を行います。
  1. [選択] テキスト ボックスを使用して、サブスクリプション内のユーザーとグループの一覧をフィルター処理できます。 必要に応じて、アプリ用に作成したローカル開発 Microsoft Entra グループの最初の数文字を入力します。
  2. アプリケーションに関連付けられているローカル開発 Microsoft Entra グループを選択します。
ダイアログの下部にある [選択] を選択して続行します。
「メンバーの選択」ダイアログ ボックスでアプリケーションの Microsoft Entra グループをフィルター処理し選択する方法を示すスクリーンショット。
Microsoft Entra グループが、[ロールの割り当ての追加] 画面に選択済みとして表示されます。

[レビューと割り当て] を選択して最終ページに移動し、もう一度レビューと割り当てを行ってプロセスを完了します。
完了した [ロールの割り当ての追加] ページと、プロセスを完了するために使用する [レビューと割り当て] ボタンの場所を示すスクリーンショット。

4 - ローカル開発の環境変数を設定する

DefaultAzureCredential オブジェクトは、一連の環境変数ランタイムでサービス プリンシパル情報を検索します。 ほとんどの開発者は複数のアプリケーションで作業するため、dotenv などのパッケージを使用して、開発時にアプリケーションのディレクトリに格納されている .env ファイルから環境にアクセスすることをお勧めします。 このようにすると、Azure に対してアプリケーションを認証するために使用される環境変数のスコープが設定され、このアプリケーションのみで使用できます。

.env ファイルには Azure のアプリケーション シークレット キーが含まれているので、ソース管理にチェックインされることはありません。 JavaScript 用の標準の .gitignore ファイルでは、チェックインから .env ファイルが自動的に除外されます。

dotenv パッケージを使用するには、まずアプリケーションにパッケージをインストールします。

npm install dotenv

次に、アプリケーションのルート ディレクトリに .env ファイルを作成します。 次のように、アプリ登録プロセスから取得した値を使用して環境変数の値を設定します。

  • AZURE_CLIENT_ID → アプリ ID の値です。
  • AZURE_TENANT_ID → テナント ID の値です。
  • AZURE_CLIENT_SECRET →アプリ用に生成されたパスワード/資格情報。
AZURE_CLIENT_ID=00001111-aaaa-2222-bbbb-3333cccc4444
AZURE_TENANT_ID=ffffaaaa-5555-bbbb-6666-cccc7777dddd
AZURE_CLIENT_SECRET=Aa1Bb~2Cc3.-Dd4Ee5Ff6Gg7Hh8Ii9_Jj0Kk1Ll2

最後に、アプリケーションのスタートアップ コードで、dotenv ライブラリを使用して、起動時に .env ファイルから環境変数を読み取ります。

import 'dotenv/config'

5 - アプリケーションに DefaultAzureCredential を実装する

Azure SDK クライアント オブジェクトを Azure に対して認証するには、アプリケーションで DefaultAzureCredential パッケージから @azure/identity クラスを使用する必要があります。 このシナリオでは、DefaultAzureCredential が環境変数AZURE_CLIENT_IDAZURE_TENANT_ID を検出し、AZURE_CLIENT_SECRET が設定され、これら変数を読み取り Azure に接続するためのアプリケーション サービス プリンシパル情報を取得します。

まず、@azure/identity パッケージを アプリケーションに追加します。

npm install @azure/identity

次に、アプリで Azure SDK クライアント オブジェクトを作成する JavaScript コードの場合、次のことが必要になります。

  1. DefaultAzureCredential モジュールから @azure/identity クラスをインポートします。
  2. DefaultAzureCredential オブジェクトを作成します。
  3. Azure SDK クライアント オブジェクト コンストラクターに DefaultAzureCredential オブジェクトを渡します。

この例を次のコード セグメントに示します。

// Azure authentication dependency
import { DefaultAzureCredential } from '@azure/identity';

// Azure resource management dependency
import { SubscriptionClient } from "@azure/arm-subscriptions";

// Acquire credential
const tokenCredential = new DefaultAzureCredential();

async function listSubscriptions() {
  try {

    // use credential to authenticate with Azure SDKs
    const client = new SubscriptionClient(tokenCredential);

    // get details of each subscription
    for await (const item of client.subscriptions.list()) {
      const subscriptionDetails = await client.subscriptions.get(
        item.subscriptionId
      );
      /* 
        Each item looks like:
      
        {
          id: '/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e',
          subscriptionId: 'aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e',
          displayName: 'YOUR-SUBSCRIPTION-NAME',
          state: 'Enabled',
          subscriptionPolicies: {
            locationPlacementId: 'Internal_2014-09-01',
            quotaId: 'Internal_2014-09-01',
            spendingLimit: 'Off'
          },
          authorizationSource: 'RoleBased'
        },
    */
      console.log(subscriptionDetails);
    }
  } catch (err) {
    console.error(JSON.stringify(err));
  }
}

listSubscriptions()
  .then(() => {
    console.log("done");
  })
  .catch((ex) => {
    console.log(ex);
  });

DefaultAzureCredential では、アプリ用に構成された認証メカニズムを自動的に検出し、Azure に対してアプリを認証するために必要なトークンを取得します。 アプリケーションで複数の SDK クライアントを使用する場合は、各 SDK クライアント オブジェクトで同じ資格情報オブジェクトを使用できます。