Defender for Endpoint のデバイスタグで Azure サブスクリプション ID を設定 - Microsoft Defender for Endpoint API を Python コードで扱う

# 本記事について

Defender for Cloud (Defender for Servers P1/P2) から Defender for Endpoint を Azure 仮想マシンに対してオンボードする際に、よく課題に挙げられるのが、[**Azure の IAM と Microsoft Defender XDR のアクセス権管理が独立になっており連動していない**](https://qiita.com/YoshiakiOi/items/9a9fe2261c1cbefa6501)ことです。

https://qiita.com/YoshiakiOi/items/9a9fe2261c1cbefa6501

**Azure はサブスクリプションやリソースグループで IAM を設定**する一方、**Microsoft Defender XDR ではデバイスグループを利用してアクセス権管理**を行います。

https://learn.microsoft.com/ja-jp/microsoft-365/security/defender-endpoint/rbac?view=o365-worldwide

しかし、このギャップを埋めるためのヒントとして、**Defender for Cloud (Defender for Servers P1/P2) から Defender for Endpoint を Azure 仮想マシンに対してオンボードすると、Defender for Endpoint (Microsoft Defender XDR) 側では、メタデータとして、サブスクリプション ID や Azure リソース ID の値を記録して保持**してくれるということがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/336127b9-46d4-8926-25ae-20703f16a0a6.png)


今回は、このメタデータを利用して、Defender for Endpoint で**各デバイスに Azure 側で所属している Azure サブスクリプション ID をデバイスタグ情報として付与**する方法を見ていきます。

https://learn.microsoft.com/ja-jp/microsoft-365/security/defender-endpoint/machine-tags?view=o365-worldwide

**デバイスタグを付与することで、簡単にデバイスグループを構成**することができるようになります。たとえば **Azure サブスクリプションごとにひとつずつデバイスグループを作成し、そのデバイスグループに対して Azure サブスクリプションの利用者にアクセス権を付与することができるようになる**というわけです。

# 本記事の実行内容の概念図

実現したいことの大まかな図は下記になります。独立して動作する Azure と Microsoft Defender XDR において、**メタデータを介してデバイスタグを付与**し、**Azure サブスクリプションの ID 情報で Defender 側のデバイスグループを分割**することを目指します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/b74e296d-5e98-70fb-8c35-c6ce69352144.png)

そして、実現方式は下記になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/346b0524-8316-7c4d-2af1-c366c15422ee.png)

[**Microsoft Defender for Endpoint API**](https://learn.microsoft.com/ja-jp/microsoft-365/security/defender-endpoint/api/management-apis?view=o365-worldwide#microsoft-defender-for-endpoint-apis) では、各デバイスの詳細情報を取得でき、その中にはサブスクリプション ID を含むメタデータも含まれます。そのデータからマシンID とサブスクリプション ID の対応表を Python のコードで作成し、その値を使って各マシンにデバイスタグとしてそのサブスクリプション ID の値を付与します。

https://learn.microsoft.com/ja-jp/microsoft-365/security/defender-endpoint/api/exposed-apis-list?view=o365-worldwide

残念ながら、**デバイスグループ自体の作成はこの API では行えない**ので、**Microsoft Defender XDR ポータルで行い**ます。

# サンプルの実装

ここから簡単にサンプルの実装を見ていきます。

## Microsoft Defender for Endpoint API を呼び出すための Entra ID アプリケーション (サービスプリンシパル) の作成

下記ドキュメントを確認し、Microsoft Defender for Endpoint API を呼び出すための **Entra ID アプリケーション (サービスプリンシパル)** の作成を行います。このサービスプリンシパルは Python コード内で利用します。

https://learn.microsoft.com/ja-jp/microsoft-365/security/defender-endpoint/api/exposed-apis-create-app-webapp?view=o365-worldwide

## Python コードによるメタデータの取得とデバイスタグの追加

本題の Python コードのサンプルを見ていきます。

まず、作成した Entra ID のアプリケーションを利用して、Bearer トークンを取得します。次に、そのトークンを使って、Microsoft Defender for Endpoint API でメタデータの取得を行い、情報を整理します。そして、各マシンに対してデバイスタグ追加の処理を同 API を介して行います。

```Python: Microsoft Defender for Endpoint API を使ったメタデータの取得とデバイスタグの追加

import requests
import urllib

# Bearer Tokenを取得するための Microsoft Entra ID の URL
url = 'https://login.microsoftonline.com/<Entra ID テナント ID>/oauth2/token' 

# Bearer Tokenを取得するためのパラメータ
params = {
'client_id': '<アプリケーションのクライアント ID>',
'client_secret': '<アプリケーションのシークレット>',
'resource': 'https://api.securitycenter.microsoft.com',
'grant_type': 'client_credentials'
}

# URLをエンコード
params = urllib.parse.urlencode(params)

# header で Content-Type を application/x-www-form-urlencoded に指定
headers = {'Content-Type': 'application/x-www-form-urlencoded'}

# Bearer Tokenを取得
r = requests.post(url=url, data=params, headers=headers)
access_token=r.json().get('access_token')

# Bearer Tokenを使って、Microsoft Defender for Endpoint API でマシンの一覧を取得
url_machine = "https://api.securitycenter.microsoft.com/api/machines"
headers_machine = {'Authorization': 'Bearer {}'.format(access_token)}
r_machine = requests.get(url=url_machine, headers=headers_machine)
machine_list = r_machine.json().get('value')

# マシンのIDとサブスクリプションIDを取得
machine_id_subscription = []
for machine in machine_list:
    vm_id = machine.get('id')
    vm_name = machine.get('computerDnsName')
    vm_metadata = machine.get('vmMetadata')
    if type(vm_metadata) == dict:
        machine_id_subscription.append({'vmId': vm_id, 'subscriptionId': vm_metadata.get('subscriptionId'), 'vmName': vm_name})

# Microsoft Defender for Endpoint API で各マシンのタグを追記
for machine in machine_id_subscription:
    if str(machine.get('subscriptionId')) != "None":
        url_tag = "https://api.securitycenter.microsoft.com/api/machines/" + machine.get('vmId') + "/tags"
        headers_tag =  {'Authorization': 'Bearer {}'.format(access_token)}
        body_tag = {"Value" : str(machine.get('subscriptionId')), "Action": "Add"}
        r_tag = requests.post(url=url_tag, headers=headers_tag, data=str(body_tag))
```

## デバイスグループの作成

上記が無事完了すると、Defender XDR Portal のデバイスページで各デバイスにタグが付与されていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/b3bca067-135c-6c5b-3c37-1f103555875c.png)


このタグが付いているデバイスが、同デバイスグループに属するように[デバイスグループの作成](https://learn.microsoft.com/ja-jp/microsoft-365/security/defender-endpoint/machine-groups?view=o365-worldwide)を行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/14df8f4f-ddd2-af49-fc4e-16f9438a0177.png)

これにより同一サブスクリプションのサーバーが同じデバイスグループに属することになり、Defender XDR 側のアクセス管理の設定がしやすくなります。

# 最後に

＊本稿は、個人の見解に基づいた内容であり、所属する会社の公式見解ではありません。また、いかなる保証を与えるものでもありません。正式な情報は、各製品の販売元にご確認ください。