テナント制限の機能で制限できること、できないこと

#はじめに

テナント制限の機能は、2017 年 1 月末にリリースされた機能のため、ご存知の方も多い機能だと思います。
特徴としては、社内 LAN の環境からプロキシ サーバーを経由して外部の Office 365 などのクラウド サービスにアクセスする環境において、プロキシ サーバー側に特定の HTTP ヘッダーを挿入させることで、Azure AD 側がヘッダーに書かれている Azure AD テナントに対してのみトークンを発行し、それ以外のテナントに対してはトークンを発行しないことで、テナント単位でアクセスを制御する機能です。

内部的な動作についてなど、既に Microsoft からテナント制限に関する情報があがっておりますので参考にしてみてください。

-参考情報
自社テナント以外へのアクセス制御 - "テナントの制限" 機能 (Tenant Restrictions)
URL:https://docs.microsoft.com/ja-jp/archive/blogs/office365-tech-japan/tenant-restrictions

テナント制限
URL:https://jpazureid.github.io/blog/azure-active-directory/tenant-restriction/

テナント制限を使用して SaaS クラウド アプリケーションへのアクセスを管理する
URL:https://docs.microsoft.com/ja-jp/azure/active-directory/manage-apps/tenant-restrictions

プロキシ サーバー側の設定のみで制御可能で Azure AD 側での設定が不要、というのも特徴の一つで、便利な機能ではあるとは思いますが、シンプルな設定であるがゆえに、制御できないケースも当然存在します。
今回は Fiddler を利用して制御できない主な動作を 2 つご紹介したいと思います。

#やってみる
参考情報でご紹介した公開情報にも記載されていますが、Fiddler を利用することで簡単にテナント制限の動作を確認することができます。

-参考情報
テスト
URL:https://docs.microsoft.com/ja-jp/azure/active-directory/manage-apps/tenant-restrictions#testing

Fiddler は内部的にプロキシ サーバーの機能を持っています。つまり、社内クライアントからの HTTP リクエストに対して、HTTP ヘッダーを挿入することができるため、テナント制限の動作を再現することが可能です。

Fiddler のインストールについては、下記 Qiita 記事を参考にしてみてください。

-参考情報
HTTPS パケット キャプチャ ツール Fiddler のインストールから使用開始まで。
URL:https://qiita.com/Shinya-Yamaguchi/items/37347ec532824c2dccad

##### 検証内容
以下内容で動作検証してみます。
	1. テナント名「shyamag014.onmicrosoft.com」のみアクセスできるように設定する。
	2. テナント名「shyamag020.onmicrosoft.com」にアクセスした際にブロックされることを確認する。
	3. スマートフォン (Wi-Fi 経由) でテナント名「shyamag020.onmicrosoft.com」にアクセスした際に、アクセスできてしまうことを確認する。
	4. MSA (Microsoft アカウント) でテナント名「shyamag014.onmicrosoft.com」にアクセスした際にブロックされてしまうことを確認する。

##### 1. テナント名「shyamag014.onmicrosoft.com」のみアクセスできるように設定する。

Fiddler を起動し、「Rules」→「Customize Rules」の順にクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/531f7d3e-ccec-f9e6-9b6b-5e0b466e0661.png)

Fiddler ScriptEditor が開くので、***static function OnBeforeRequest(oSession: Session)*** 関数の項目に設定を行います。

変更前)

```c#


static function OnBeforeRequest(oSession: Session) {
        // Sample Rule: Color ASPX requests in RED
        // if (oSession.uriContains(".aspx")) {	oSession["ui-color"] = "red";	}

        // Sample Rule: Flag POSTs to fiddler2.com in italics
        // if (oSession.HostnameIs("www.fiddler2.com") && oSession.HTTPMethodIs("POST")) {	oSession["ui-italic"] = "yup";	}

        // Sample Rule: Break requests for URLs containing "/sandbox/"
        // if (oSession.uriContains("/sandbox/")) {
        //     oSession.oFlags["x-breakrequest"] = "yup";	// Existence of the x-breakrequest flag creates a breakpoint; the "yup" value is unimportant.
        // }
```

変更後)

```c#

    static function OnBeforeRequest(oSession: Session) {
        // Sample Rule: Color ASPX requests in RED
        // if (oSession.uriContains(".aspx")) {	oSession["ui-color"] = "red";	}

        // Sample Rule: Flag POSTs to fiddler2.com in italics
        // if (oSession.HostnameIs("www.fiddler2.com") && oSession.HTTPMethodIs("POST")) {	oSession["ui-italic"] = "yup";	}

        // Sample Rule: Break requests for URLs containing "/sandbox/"
        // if (oSession.uriContains("/sandbox/")) {
        //     oSession.oFlags["x-breakrequest"] = "yup";	// Existence of the x-breakrequest flag creates a breakpoint; the "yup" value is unimportant.
        // }
		
		if (
			oSession.HostnameIs("login.microsoftonline.com") ||
			oSession.HostnameIs("login.microsoft.com") ||
			oSession.HostnameIs("login.windows.net")
			)
		{
			oSession.oRequest["Restrict-Access-To-Tenants"] = "shyamag014.onmicrosoft.com";
			oSession.oRequest["Restrict-Access-Context"] = "e0998cfb-e95c-44d6-9c5f-1a5198006d05";
		}
```

 oSession.oRequest["Restrict-Access-Context"] はテナント制限に関するログの出力先の設定になるので、今回の検証では意識する必要はありません。

重要なのは、***oSession.oRequest["Restrict-Access-To-Tenants"] = "<tenant domain>";*** になります。
***アクセスを許可させたい Azure AD テナント名*** を設定します。「, (カンマ)」で複数テナントを指定することができますが、HTTP ヘッダーに挿入できる値の上限までに収まるように設定しないと動作しないので気を付けてください。

-参考情報
Windows 用の Http.sys レジストリ設定
URL:https://support.microsoft.com/ja-jp/help/820129/http-sys-registry-settings-for-windows

| 項目     |  上限値 (Bytes)       |      
|:-----------------|:------------------|
|MaxFieldLength        |              65534 |   
| MaxRequestBytes|            16777216 |  

「Save」→「Exit」で設定を保存して閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/e910b4e7-db17-5df1-e1ad-58ba0e7e3e5c.png)

Fiddler の「File」→「Capture Traffic」の順にクリックし、キャプチャを開始します。キャプチャを開始することで、Fiddler 内のプロキシ サーバーが動作します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/d3c66c1e-095b-e238-c2eb-27bf8360da8b.png)

#####2.  テナント名「shyamag020.onmicrosoft.com」にアクセスした際にブロックされることを確認する。

Fiddler でキャプチャを開始させたまま、Azure ポータルの「shyamag020.onmicrosoft.com」テナントにアクセスしてみます。
当該テナントのグローバル管理者の UPN を入力し、「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/fba1bf8c-2e31-eb8d-65f0-a56e093c91d9.png)

パスワードを入力し、「サインイン」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/07bf7190-6e89-b1fc-254e-7c1b6e036c3f.png)

下記画面ショットのようにアクセスがブロックされることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/d92b76bd-47b8-b0ae-97f4-5920ded05ad2.png)

「詳細」のリンクをクリックすると、IT 部門によって承認されていないテナントにアクセスしようとしている旨のメッセージが表示されていることが確認できます。これがテナント制限の機能になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/c1da4323-c62c-b1bb-3d56-39225809e5a2.png)

Fiddler で Azure ポータルのエンドポイント「login.microsoftonline.com」の HTTP パケットを見てみると、「Restrict-Access-To-Tenants」と「Restrict-Access-Context」が HTTP ヘッダーに挿入されていることが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/2a9fdae5-b41c-bed4-e91c-e120b1efd78e.png)

下記が抜粋したヘッダー情報になります。

```
Referer: https://portal.azure.com/
Restrict-Access-Context: e0998cfb-e95c-44d6-9c5f-1a5198006d05
Restrict-Access-To-Tenants: shyamag014.onmicrosoft.com
```

#####3. スマートフォン (Wi-Fi 経由) でテナント名「shyamag020.onmicrosoft.com」にアクセスした際に、アクセスできてしまうことを確認する。

既に勘付いている方もいると思いますが、本機能はプロキシ サーバーを経由しない通信では制御できません。
例えば、社員が社外から Azure AD 上のアプリケーションにアクセスした場合や、社内 LAN ではなく、社内 Wi-Fi からアクセスするようなプロキシ サーバーを経由しない通信の場合は、テナント制限は機能しません。

簡単に確認できる方法として、Fiddler でテナント制限の機能を有効化した状態で、スマートフォンから shyamag020.onmicrosoft.com テナントにアクセスしてみます。

当該テナントのグローバル管理者の UPN を入力し、「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/f74267f7-040f-9487-5607-c59db28cf5b8.png)

パスワードを入力し、「サインイン」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/c0a9fcab-970a-45ef-bcaf-8b6bb5545773.png)

KMSI の画面で「いいえ」をタップします。(「はい」でも問題ありません。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/6e610e69-5826-d4d6-5457-2ba100d603f1.png)

下記画面ショットのように、テナント制限の機能では制御できず、Azure ポータルにアクセスできてしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/4c5fb4fa-466b-b71e-4144-568b29b5fa7e.png)

このように、プロキシ サーバーを経由しない通信の場合は、テナント制限したい Azure AD テナントにもアクセスできてしまいます。

#####4. MSA (Microsoft アカウント) でテナント名「shyamag014.onmicrosoft.com」にアクセスした際にブロックされてしまうことを確認する。

理由については後述しますが、ゲスト ユーザーとして招待した Microsoft アカウント (MSA) でもテナント制限の機能を使って、アクセスさせたい場合となった場合は制御することができません。実際に動作確認してみましょう。

まず、テナント制限でアクセスを許可しているテナント名「shyamag014.onmicrosoft.com」上にいる、ゲスト ユーザー (xxxxx@gmail.com) で Azure ポータルにサインインしてみます。Fiddler によるキャプチャを有効化した状態です。

「shyamag014.onmicrosoft.com」に登録されている Microsoft アカウント「xxxxx@gmail.com」を入力し、「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/62c00045-4a86-fe53-fe4b-573defecfd13.png)

パスワードを入力して「サインイン」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/bea9392c-f57c-9f4e-aeae-bfc1fe14d3a4.png)

下記画面ショットのように、アクセスがブロックされてしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/ef77e9ce-ac08-5feb-e1cb-ca4b8d5f363f.png)

「詳細」のリンクをクリックすると、承認されていない組織にアクセスを試みている旨のメッセージが表示されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/9ea34a11-0aec-7bfb-e54b-ef040ba2fd05.png)

なぜこのような動作になるのか、Fiddler のパケットを見てみましょう。
通信の流れとしては、

1. 「portal.azure.com」を入力
2. Azure ポータルの認証エンドポイント「login.microsoft.com」にて UPN を入力する画面が要求され、ここで Microsoft の UPN を入力する
3. Microsoft アカウント (MSA) の認証エンドポイントである「login.live.com」に遷移する
4. 「login.live.com」はテナント制限で制御できる認証エンドポイントに含まれていないため、プロキシ サーバーが「Restrict-Access-To-Tenants: shyamag014.onmicrosoft.com」ヘッダーを挿入できない。
5. Azure AD が当該のヘッダーが含まれていないため、トークンを発行せず、結果ブロックされる。

という動作になります。

実際に「login.live.com」にアクセスした際の HTTP ヘッダーを見てみると、下記のとおり、「Restrict-Access-To-Tenants: shyamag014.onmicrosoft.com」ヘッダーならびに「Restrict-Access-Context: e0998cfb-e95c-44d6-9c5f-1a5198006d05」ヘッダーは挿入されていません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/5d515b88-77ff-732a-2038-929924f688e7.png)

```
Referer: https://login.microsoftonline.com/
```

公開情報にも書いてあるとおり、テナント制限で制御できる認証エンドポイントは下記 URL に限定されています。つまり、Microsoft アカウントの認証エンドポイントである「login.live.com」は対象に含まれていないため、テナント制限で制御することはできません。


テナント制限で制御可能な認証エンドポイント
login.microsoftonline.com
login.microsoft.com
login.windows.net 

-参考情報
URL と IP アドレス
URL:https://docs.microsoft.com/ja-jp/azure/active-directory/manage-apps/tenant-restrictions#urls-and-ip-addresses

>テナント制限を使用するには、クライアントは、認証のために login.microsoftonline.com、login.microsoft.com、および login.windows.net の Azure AD URL に接続できる必要があります。 さらに、Office 365 にアクセスするために、クライアントは「Office 365 の URL と IP アドレスの範囲」で定義されている完全修飾ドメイン名 (FQDN)、URL、および IP アドレスにも接続できる必要があります。 

***追記***
改めて検証してみましたが、Microsoft アカウントでアクセスした場合の通信を許可する方法がありました。
下記 2 つのエンドポイントを「Restrict-Access-To-Tenants」に追記することで、Microsoft アカウントでアクセスした際も許可の対象とすることができます。

microsoftservices.onmicrosoft.com
MSARealms.onmicrosoft.com

変更前)

```c#

    static function OnBeforeRequest(oSession: Session) {
        // Sample Rule: Color ASPX requests in RED
        // if (oSession.uriContains(".aspx")) {	oSession["ui-color"] = "red";	}

        // Sample Rule: Flag POSTs to fiddler2.com in italics
        // if (oSession.HostnameIs("www.fiddler2.com") && oSession.HTTPMethodIs("POST")) {	oSession["ui-italic"] = "yup";	}

        // Sample Rule: Break requests for URLs containing "/sandbox/"
        // if (oSession.uriContains("/sandbox/")) {
        //     oSession.oFlags["x-breakrequest"] = "yup";	// Existence of the x-breakrequest flag creates a breakpoint; the "yup" value is unimportant.
        // }
		
		if (
			oSession.HostnameIs("login.microsoftonline.com") ||
			oSession.HostnameIs("login.microsoft.com") ||
			oSession.HostnameIs("login.windows.net")
			)
		{
			oSession.oRequest["Restrict-Access-To-Tenants"] = "shyamag014.onmicrosoft.com";
			oSession.oRequest["Restrict-Access-Context"] = "e0998cfb-e95c-44d6-9c5f-1a5198006d05";
		}
```

変更後)

```c#

  static function OnBeforeRequest(oSession: Session) {
        // Sample Rule: Color ASPX requests in RED
        // if (oSession.uriContains(".aspx")) {	oSession["ui-color"] = "red";	}

        // Sample Rule: Flag POSTs to fiddler2.com in italics
        // if (oSession.HostnameIs("www.fiddler2.com") && oSession.HTTPMethodIs("POST")) {	oSession["ui-italic"] = "yup";	}

        // Sample Rule: Break requests for URLs containing "/sandbox/"
        // if (oSession.uriContains("/sandbox/")) {
        //     oSession.oFlags["x-breakrequest"] = "yup";	// Existence of the x-breakrequest flag creates a breakpoint; the "yup" value is unimportant.
        // }
		
		if (
			oSession.HostnameIs("login.microsoftonline.com") ||
			oSession.HostnameIs("login.microsoft.com") ||
			oSession.HostnameIs("login.windows.net")
			)
		{
			oSession.oRequest["Restrict-Access-To-Tenants"] = "shyamag014.onmicrosoft.com,microsoftservices.onmicrosoft.com,MSARealms.onmicrosoft.com";
			oSession.oRequest["Restrict-Access-Context"] = "e0998cfb-e95c-44d6-9c5f-1a5198006d05";
		}
```

複数のテナントを指定する場合は、上記のとおり、先頭と末尾を「""」で囲うようにしてください、1 エンドポイント単位で「""」で囲ってしまうと、先頭のテナントのみが、制御対象となりますので、注意してください。

正)

```
"shyamag014.onmicrosoft.com,microsoftservices.onmicrosoft.com,MSARealms.onmicrosoft.com";
```
誤)

```
"shyamag014.onmicrosoft.com","microsoftservices.onmicrosoft.com","MSARealms.onmicrosoft.com";
```

下記画面ショットのように、Microsoft アカウントでも許可したいテナント (shyamag014.onmicrosoft.com) にアクセスできました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/4f82f320-a7e0-084f-6e74-a844d13ea11c.png)

Microsoft アカウントもアクセスできるようになりましたが、設定したエンドポイントは***全 Microsoft アカウント***がアクセスするエンドポイントになります。
つまり、本来アクセスをブロックしたいテナントに対しても、Microsoft アカウントによるアクセスが許可されてしまいます。

例えば、shyamag020.onmicrosoft.com という本来アクセスさせたくないテナント上にいる、Microsoft アカウントを利用して普通に Office 365 等のアプリケーションにサインインができてしまうという動作になります。

#####じゃあどうすればいいのか
検証内容 3. および 4. で見てきたとおり、働き方改革が叫ばれる中で、自宅からリモート ワークする企業も多く、企業間のコラボレーションとして、ゲスト ユーザーとして Azure AD テナントに招待し、 Microsoft アカウントで当該の Azure AD リソースにアクセスするケースは日常的にあり得ます。

この場合はテナント制限ではなく、例えば、「条件付きアクセス」を利用して、ユーザー単位やリソース単位、デバイス単位で Azure AD 上の認証を制御することで、社内、社外の環境に依存しない制御をすることが可能になります。

条件付きアクセスは Azure AD Premium P1 以上のライセンスが必要なので、費用がかかるじゃないか、というご意見もあるかと思いますが、それがクラウド サービスです。

Azure に限らず、ライセンスの機能レベルにより制御できる内容が異なるのは、クラウド サービスの一般的な考え方であり、逆に言うと、テナント制限の機能で実現できる内容は限定的であると言えます。

もちろん条件付きアクセスだけではなく、Application Gateway など、NW 機器側でトラフィックを制御することも可能です。
繰り返しになりますが、伝えたいことは、テナント制限を設定したからと言って、すべての通信を制御できるわけではない、ということです。

#まとめ
今回はテナント制限の機能を使って、制限できること、できないことを実際に動作検証しながら確認してみました。
今回お見せしたように、通信経路によってはテナント制限の機能が効かないケースがあります。

今後本機能を検討されている方は、テナント制限の機能を理解した上でご利用いただければと思います。
今回の記事が少しでも参考になれば幸いです。