Azure AD で、ロールを”ユーザー”と”アプリケーション”に割り当てる

##Introduction

アプリケーションや API のアクセスコントロールを RBAC で行う場合、ロールの定義が必要です。

ただし、定義したロールは、ユーザーに対する者とは限りません。WEB API の場合、そのアクセス元はネイティブアプリだったり WEB アプリだったりします。ユーザーは超能力でもない限り、どんなに頑張っても直接 API にアクセスすることはできないですから、当然です。

そうなると、WEB API にアクセスしてくるアプリケーションにロールを割り当てる必要が出てきます。

Azure Portal では、残念ながらアプリケーションに対してロールを割り当てる機能が用意されておらず、PowerShell を使用する必要があります。以降で、その方法について解説します。

##アプリケーションオブジェクトとマニフェスト

まずは少しだけ前提知識の解説をしておきます。

アプリケーションをAzure ADを使って認証するには、Azure AD にアプリケーションを登録する必要があります。このとき、Azure AD には、2つのオブジェクトが作成されます。

- アプリケーションオブジェクト
- サービスプリンシパルオブジェクト

これらについてはここで詳しくは触れませんが、以下で解説されていますので興味のある方はどうぞ。

Azure Active Directory のアプリケーション オブジェクトとサービス プリンシパル オブジェクト (Azure AD)
https://docs.microsoft.com/ja-jp/azure/active-directory/develop/active-directory-application-objects

ちなみに、Azure AD の管理画面だと、アプリケーションオブジェクトは「アプリケーションの登録」から、サービスプリンシパルオブジェクトは「エンタープライズアプリケーション」から参照することができます。

<img width="400" src="https://qiita-image-store.s3.amazonaws.com/0/134539/ee6ba5bb-a078-be20-7878-86aa7490d673.png">

PowerShell だと、それぞれ以下のコマンドを使用して参照できます。コマンドを実行するまえに、Connect-AzureAD コマンドを使用して、Azure AD にログインすることを忘れずに。

```
#アプリケーションオブジェクト
Get-AzureADApplication
```
```
#サービスプリンシパルオブジェクト
Get-AzureADServicePrincipal
```

話を戻します。

アプリケーションオブジェクトには「マニフェスト」を定義することができます。これは、[アプリケーション登録]画面でアプリケーションを選択し、「マニフェスト」をクリックすると参照/編集することができます。

<img width="500" src="https://qiita-image-store.s3.amazonaws.com/0/134539/33f61f59-99ac-82f5-5a0a-c897d26e9a6f.png">

マニフェストは、アプリケーションオブジェクトの各種プロパティが定義されており、その多くはGUIで設定可能です。が、一部、GUIで設定できないものがあります。Role はその一つです。

アプリケーションオブジェクトで定義したマニフェストは、サービスプリンシパルオブジェクトに自動的に引き継がれます。

##アプリケーションとロール

アプリケーションを RBAC（Role-Based Access Control）でアクセスコントロールする場合、以下の2か所にロールを定義する必要があります。

- 認証基盤（Azure AD）側 ： ”ユーザー”と”ロール”のマップ
- アプリケーション側 ： ”ロール”と”権限”のマップ

ユーザーは認証時にロールが決定され、このロールをアプリケーションに提示することでアクセス権が与えられます。以下の黄色い部分が該当します。

<img width="500" src="https://qiita-image-store.s3.amazonaws.com/0/134539/352f2601-79b6-5b1c-b5d2-cc1b96bcf863.png">

黄色い部分が具体的にどのように行われるのかについては、技術的にさまざまな方法が用意されています。アプリケーション側の実装にも依存するので、なかなか一口では言えませんが、およそ以下のようなタイプに分けられます。

- 事前にユーザーの Role を定義しておく
- ユーザーの特定の属性をそのまま Role として使用する（Title=Manager をそのまま使用するなど）
- ユーザーの特定の属性を Role に変換する（Title=部長 を Role=Manager に変換するなど）

一番シンプルなのは1番目です。例えば、特権を持つユーザーだけにロールを割り当て、その他のユーザーはロールを気にせずにフラットに扱うといった場合にはこの方法でもよいでしょう。

Azure AD にはユーザーまたはグループとロールを紐づける機能が標準で用意されています。それにはマニフェストと呼ばれるファイルにロールを定義しておく必要があります。

##アプリケーションロールとマニフェスト

Azure AD では「マニフェスト」と呼ばれる定義ファイルに Role を定義することが可能です。

Azure Active Directory アプリケーション マニフェスト
https://docs.microsoft.com/ja-jp/azure/active-directory/develop/active-directory-application-manifest

以下は Azure Blockchain Workbench という製品で使われているマニフェストの例ですが、appRoles タグに定義されているのがロールです。Administrator というロールが定義されていることがわかると思います。

```
{
  "appId": "xxxxxxxx-xxxx-xxxx-xxxx-d272ce281785",
  "appRoles": [
    {
      "allowedMemberTypes": [
        "User",
        "Application"
      ],
      "displayName": "Administrator",
      "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "isEnabled": true,
      "description": "Blockchain Workbench administrator role allows creation of applications, user to role assignments, etc.",
      "value": "Administrator"
    }
  ],
  "availableToOtherTenants": false,
  "displayName": "BC Workbench API",
  "errorUrl": null,
  "groupMembershipClaims": null,
  "optionalClaims": null,
  "acceptMappedClaims": null,
  "homepage": "https://bcworkbenchapi",
  "informationalUrls": {
    "privacy": null,
    "termsOfService": null
  },
```

allowMemberTypes は、このロールを割り当てることができるオブジェクトタイプを指定します。ここでは、User と Application が定義されていることがわかります。User は”ユーザー”と”グループ”が、Application は”サービスプリンシパル”を意味します。

id はこのロールの識別子で、新しく発行した GUID を指定します。

ちなみに、GUID を新しく発行するには PowerShell を使用するのが簡単です。パラメタ無しに以下のコマンドを実行すれば、新しい GUID が発行されます。

```
New-GUID
```

##ロールをユーザーに割り当てる

マニフェストで定義したロールを”ユーザー”に割り当てるのは、GUI から簡単に行えます。

Azure Portal の Azure Active Directory の管理画面で、[エンタープライズアプリケーション]を開いてください。 

<img width="500" src="https://qiita-image-store.s3.amazonaws.com/0/134539/dad11884-58a2-3b72-6aa9-a8ed044cfb1d.png">

アプリ一覧からアプリケーションを選択し、[ユーザーとグループ]を選択しましょう。この画面で、アプリケーションに対して、誰がどんなロールでアクセス可能であるか。。。。を定義することができます。

<img width="500" src="https://qiita-image-store.s3.amazonaws.com/0/134539/cb501287-0731-933b-17de-0ab047e64243.png">

ユーザーのかわりにグループを選択することも可能です。この場合は、グループのメンバーに、ロールが割り当てられます。

##サービスプリンシパルにロールを割り当てる

マニフェストの allowedMemberTypes に”Application”を指定した場合には、サービスプリンシパルオブジェクトにロールを割り当てることができます。

ただし、残念ながら GUI からは行えません。PowerShell を使用します。

PowerShell ISE を管理者で起動しましょう。

<img width="300" src="https://qiita-image-store.s3.amazonaws.com/0/134539/e95fe7a2-8494-ffe4-40e2-f7241a29c02d.png">

以下のコマンドで Azure AD にログオンします。-TenantID には、Azure AD のテナントID（ディレクトリID）を指定します。

```
Connect-AzureAD -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxc84edb67
``` 

ここからロール割り当てるためのコマンドを実行していくのですが、まずは何をしようとしているのかを頭にイメージしてください。やろうとしていることは以下の通りです。

1. あるアプリケーション（サービスプリンシパルオブジェクト）に対して、
2. 別のアプリケーション（サービスプリンシパルオブジェクト）が、
3. Administrator ロールを持つように設定する

必要な情報は、上記それぞれの ObjectID（GUID）です。

まずはサービスプリンシパルオブジェクトの Object ID を取得します。ログオンしている状態で、以下のコマンドを実行しましょう。

```
Get-AzureADServicePrincipal
```

以下のような実行結果が出力されるはずです。各サービスプリンシパルの ObjectID、AppID、DisplayNameが出力されていることがわかります。

<img width="500" src="https://qiita-image-store.s3.amazonaws.com/0/134539/90fbeea3-c268-18ef-cf1b-cd70719a5f91.png">

この中から、「1.あるアプリケーション」と「2.別のアプリケーション」を探し、それぞれの ObjectID を控えておきましょう。

「3. Administrator のロール」のObjectIDは、マニフェストに指定した id プロパティです。

```
  "appRoles": [
    {
      "allowedMemberTypes": [
        "User",
        "Application"
      ],
      "displayName": "Administrator",
      "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "isEnabled": true,
      "description": "Blockchain Workbench administrator role allows creation of applications, user to role assignments, etc.",
      "value": "Administrator"
    }
```

3つの情報がそろったら、以下のコマンドを実行しましょう。以下は1行で実行してください。

```
New-AzureADServiceAppRoleAssignment -ObjectId <1.のObjectID> -Id <3.のObjectID> -PrincipalId <2.のObjectID> -ResourceId <再び 1.のObject ID>
```

```
（例）
New-AzureADServiceAppRoleAssignment -ObjectId xxxxxxxx-xxxx-xxxx-xxxx-82dbcc7d399b -Id yyyyyyyy-yyyy-yyyy-yyyy-b68df60d9672 -PrincipalId zzzzzzzz-zzzz-zzzz-zzzz-4306160b1a43 -ResourceId xxxxxxxx-xxxx-xxxx-xxxx-82dbcc7d399b
```

実行できたら、以下のコマンドを結果を見てみましょう。

```
 Get-AzureADServiceAppRoleAssignment -ObjectId <1.のObjectID>
```
以下のような出力結果の中に、「2.別のアプリケーション」が追加されていることがわかります。
 
<img width="600" src="https://qiita-image-store.s3.amazonaws.com/0/134539/9e554f38-5a1b-3887-2387-8a2988680650.png">

ちなみに、この結果をAzure AD の管理GUIで参照すると以下のようになります。追加したアプリケーションは「不明」と表示されていることがわかりますね。

<img width="600" src="https://qiita-image-store.s3.amazonaws.com/0/134539/c09dfe6a-920f-f669-0a9d-cd4e9bba311c.png">

ユーザーではなくアプリケーションに対してロールを与えたいというニーズは少なくありません。覚えておくと役に立つと思います。