😽

Microsoft Entra Private Access はどうやってパケットを曲げているのか (分からんかった)

2024/06/16に公開
2

TL;DR

  • Microsoft Entra Private Accss が何をやってるのか、明らかにし隊
  • ほとんど分からなかったけどちょっとだけ分かったかもしれない
  • routing じゃない方法でパケットをねじ曲げられるとトラブルシュートがめんどそう

はじめに

わたしが最近個人的に好きなサービスとして Microsoft Entra Private Access (MEPA) があります。
一般的な用語でいえば Zero Trust Network Access (ZTNA) であり、VPN を使ってないんだけど、リモートアクセスができる、というようなものです。
docs は Microsoft Entra Private Access について学習する を見ていただければと思いますが、なんかよくわからないかもしれません。

家にいて、自分の PC のプライベート IP アドレスが 192.168.0.5/24 だったとして、そのまま、VPN を張らずに、会社の 192.168.11.200/24 というプライベート IP アドレスを持つサーバにリモートデスクトップ接続できる、みたいな感じです。

remote access with SSE
remote access with SSE

VPN は使っていないのですが、専用の agent みたいなものはインストールが必要なので、まぁそいつが何かしてるんだろう、という感じです。
VPN の場合にはルーティング テーブル見れば、うん、そうだよね、ということでやってることがクリアなんですが、ちょっと試した感じだと MEPA ではルーティング上変化が起こっておらず、なんでだ?というところで少し潜ってみた感じです。

Get-Net* コマンドを叩きまくってみる

route print でなんも出てこないし、MEPA としてインターフェースが増えているようにも見えないし、まったく見当が付きません。。
とりあえず、Get-Net まで入力して、tab を押して、それっぽいコマンドを探します。。

いろいろ叩いてみた結果、Get-NetAdapterBinding の結果の中に「Global Secure Access Client」が見つかりました。
自分の PC での出力結果 (を一部割愛したもの) です。

PS C:\Users\ikko> Get-NetAdapterBinding

Name                           DisplayName                                        ComponentID          Enabled
----                           -----------                                        -----------          -------
Wi-Fi                          File and Printer Sharing for Microsoft Networks    ms_server            True
Wi-Fi                          Microsoft LLDP Protocol Driver                     ms_lldp              True
Wi-Fi                          Client for Microsoft Networks                      ms_msclient          True
Wi-Fi                          Microsoft Network Adapter Multiplexor Protocol     ms_implat            False
Wi-Fi                          Internet Protocol Version 6 (TCP/IPv6)             ms_tcpip6            True
Wi-Fi                          Internet Protocol Version 4 (TCP/IPv4)             ms_tcpip             True
Wi-Fi                          Link-Layer Topology Discovery Mapper I/O Driver    ms_lltdio            True
Wi-Fi                          Hyper-V Extensible Virtual Switch                  vms_pp               False
Wi-Fi                          Link-Layer Topology Discovery Responder            ms_rspndr            True
Wi-Fi                          Npcap Packet Driver (NPCAP)                        INSECURE_NPCAP       True
Wi-Fi                          Global Secure Access Client                        GlobalSecureAccessD… True
Wi-Fi                          Bridge Driver                                      ms_l2bridge          True
Wi-Fi                          QoS Packet Scheduler                               ms_pacer             True
<snipped>

これは、GUI だと Control Panel > Network and Internet > Network and Sharing Center に行ってから、左の Change adapter settings をクリックしてインターフェースの一覧を表示させ、Wi-Fi とかのそれっぽいインターフェースを右クリックしてから Properties を表示した感じです。

Wi-Fi properties
Wi-Fi properties

どこらへんに設定があるのか

ということで、procmon をにらめっこしながらいろいろ追いかけてみます。

registry

まずは、Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Global Secure Access Client\ForwardingProfile という registry key にたどり着きます。
MEPA が有効な状態だと、ここにいい感じの json フォーマットが書いてあり、これが Entra admin center で設定した内容と合致していそうです。
今回、192.168.11.0/24 を remote network として、22/tcp、80/tcp、443/tcp、3389/tcp を向けている感じです。

Entra admin center - Network access properties
Entra admin center - Network access properties

ForwardingProfile
{
    "policy": {
        "id": "xxxxxxxx-xxxx-xxxx-xxxx-92d6d4889ec8",
        "tenantId": "xxxxxxxx-xxxx-xxxx-xxxx-92d6d4889ec8",
        "channels": [
            {
                "id": "xxxxxxxx-xxxx-xxxx-xxxx-2a8ff07f474c",
                "name": "Private",
                "naasAuthorizationTokenContext": {
                    "clientAppId": "xxxxxxxx-xxxx-xxxx-xxxx-c8e0298fee16",
                    "audienceScope": "xxxxxxxx-xxxx-xxxx-xxxx-168f2376341c/NetworkProfile.Private",
                    "clientRedirectUri": "https://login.microsoftonline.com/common/oauth2/nativeclient"
                },
                "edgesSettings": {
                    "primaryEdges": [
                        {
                            "edgeAddress": "xxxxxxxx-xxxx-xxxx-xxxx-92d6d4889ec8.private.client.globalsecureaccess.microsoft.com",
                            "edgePort": 443,
                            "isSecure": true
                        }
                    ],
                    "secondaryEdges": []
                },
                "diagnosticUri": "https://private.edgediagnostic.globalsecureaccess.microsoft.com/connectivitytest/ping"
            }
        ],
        "rules": [
            {
                "id": "xxxxxxxx-xxxx-xxxx-xxxx-111111111111",
                "channelId": "xxxxxxxx-xxxx-xxxx-xxxx-2a8ff07f474c",
                "order": 0.0,
                "action": "Bypass",
                "hardening": "Bypass",
                "matchingCriteria": {
                    "address": {
                        "ips": [],
                        "fqdns": [
                            ".+\\.client\\.globalsecureaccess\\.microsoft\\.com",
                            ".+\\.client\\.globalsecureaccess\\.microsoft\\.com\\..+",
                            "aps\\.globalsecureaccess\\.microsoft\\.com"
                        ]
                    },
                    "ports": [
                        {
                            "start": 0,
                            "end": 65535
                        }
                    ],
                    "protocol": "Tcp"
                },
                "appAuthorizationTokenContext": null
            },
            {
                "id": "xxxxxxxx-xxxx-xxxx-xxxx-333333333333",
                "channelId": "xxxxxxxx-xxxx-xxxx-xxxx-2a8ff07f474c",
                "order": 1.0,
                "action": "Tunnel",
                "hardening": "Bypass",
                "matchingCriteria": {
                    "address": {
                        "ips": [],
                        "fqdns": [
                            "private\\.edgediagnostic\\.globalsecureaccess\\.microsoft\\.com"
                        ]
                    },
                    "ports": [
                        {
                            "start": 0,
                            "end": 65535
                        }
                    ],
                    "protocol": "Tcp"
                },
                "appAuthorizationTokenContext": null
            },
            {
                "id": "xxxxxxxx-xxxx-xxxx-xxxx-a7240ed867b4",
                "channelId": "xxxxxxxx-xxxx-xxxx-xxxx-2a8ff07f474c",
                "order": 2.0,
                "action": "Tunnel",
                "hardening": "Bypass",
                "matchingCriteria": {
                    "address": {
                        "ips": [
                            {
                                "start": 3232238336,
                                "end": 3232238591
                            }
                        ],
                        "fqdns": []
                    },
                    "ports": [
                        {
                            "start": 22,
                            "end": 22
                        },
                        {
                            "start": 80,
                            "end": 80
                        },
                        {
                            "start": 443,
                            "end": 443
                        },
                        {
                            "start": 3389,
                            "end": 3389
                        }
                    ],
                    "protocol": "Tcp"
                },
                "appAuthorizationTokenContext": {
                    "clientAppId": "xxxxxxxx-xxxx-xxxx-xxxx-c8e0298fee16",
                    "audienceScope": "api://xxxxxxxx-xxxx-xxxx-xxxx-0ec73e857d9e/user_impersonation",
                    "clientRedirectUri": "https://login.microsoftonline.com/common/oauth2/nativeclient"
                }
            }
        ],
        "privateDnsRules": []
    },
    "configuration": {
        "apsSettings": {
            "requestPollingIntervalInSeconds": 300
        },
        "flowHandler": {
            "graceTimeInMs": 3500
        },
        "userModeLogs": {
            "logSizeInMB": 2.0,
            "fileCount": 3,
            "directoryPath": "c:\naaslogs"
        },
        "managementService": {
            "hostAcquisitionInternalSubNet": {
                "subnetAddress": 101056512,
                "subnetMask": 4294901760
            },
            "policyUpdateFlushOsCache": false,
            "cacheAuthenticationToken": true,
            "authenticationCacheRefreshIntervalInSeconds": 20
        },
        "edsSettings": {
            "pollingIntervalInSeconds": 10
        }
    },
    "settingsVersion": "CPV:RV:2024-06-11T08:12:31.9106340Z_CPLM:20240611081007.000_NAV:CommonVersion_14",
    "controlPlanePoliciesVersion": "20240611081007.000",
    "apsContextData": "{\"LastModifiedAt\":\"2024-06-16T07:47:14.2347672+00:00\",\"AttemptsCountOnConfigSyncInProgress\":0,\"LastResponseStatus\":\"SettingsNotModified\",\"AssignedGSAApplicationsIds\":[\"xxxxxxxx-xxxx-xxxx-xxxx-f1b4b9798fe0\"],\"InternetIpBasedCatchAllRuleInjected\":false,\"InjectorsResults\":{\"InternetIpBasedAcquireAllRuleInjector\":{\"NewDataInjected\":false,\"InjectorSettingsJson\":\"{\\\"IpSubnets\\\":[{\\\"Value\\\":\\\"0.0.0.0/0\\\"}],\\\"IpRanges\\\":null}\"},\"InternetFqdnBaseAcquireAllRuleInjector\":{\"NewDataInjected\":false,\"InjectorSettingsJson\":\"{\\\"Regex\\\":\\\"\\\"}\"}}}"
}

以下の部分に書かれている 3232238336 はいろいろ計算すると 192.168.11.0 を 10 進数表現したもので、3232238591 は 192.168.11.255 を表しています。
portsprotocol はそのままなのでわかりやすいですね。

matchingCriteria
                "matchingCriteria": {
                    "address": {
                        "ips": [
                            {
                                "start": 3232238336,
                                "end": 3232238591
                            }
                        ],
                        "fqdns": []
                    },
                    "ports": [
                        {
                            "start": 22,
                            "end": 22
                        },
                        {
                            "start": 80,
                            "end": 80
                        },
                        {
                            "start": 443,
                            "end": 443
                        },
                        {
                            "start": 3389,
                            "end": 3389
                        }
                    ],
                    "protocol": "Tcp"
                },

NDIS lightweight filter (LWF)

先ほどのスクリーンショットの description に「LWF Driver that acquires traffic for the Global Secure Access Client」と書いてあり、「LWF」というのを使っていそうな雰囲気があります。
調べてみると、仮想スイッチ フィルターの使用 に「これらのレイヤーは、仮想スイッチ拡張フィルターという NDIS ライトウェイト フィルター (LWF) ドライバーの一種からアクセスされます。」と書いてあります。
何かよくわからないものではあるんですが、とりあえずパケット フィルター的なさむしんぐかと思われるので、そのインターフェースを通るパケットをこのフィルターを経由してごにょごにょしている感じかと思われます。

フィルター ドライバー にも、なんかフィルター モジュールを複数経由できるっぽい感じの絵があります。
これのうちの一つとして、MEPA を挟み込んだ、という感じでしょうか。

netcfg

そのほか色々調べているうちに、この LWF をいじるためのコマンドとして netcfg があることがわかりました。
結局詳細は分からなかったのですが、.inf ファイルをつくって netcfg コマンドでインストールする?ような感じです。

GlobalSecureAccessDriver.inf

んで、じゃあそれっぽい .inf ファイルを探しに行くと「C:\Program Files\Global Secure Access Client\GlobalSecureAccessDriver.inf」にありました。
細かい内容はやっぱりわからなかったのですが、同じフォルダにある GlobalSecureAccessDriver.sys がフィルターの本体っぽい感じがあります。

GlobalSecureAccessDriver.inf
<snipped>
;-------------------------------------------------------------------------
; Installation Section
;-------------------------------------------------------------------------
[Install]
AddReg=Inst_Ndi
; All LWFs must include the 0x40000 bit (NCF_LW_FILTER). Unlike miniports, you
; don't usually need to customize this value.
Characteristics=0x40000
NetCfgInstanceId="{000062a1-04c5-4758-8497-5d7e655dc0d3}"
Copyfiles = globalsecureaccessdriver.copyfiles.sys

[SourceDisksNames]
1=%Mnap_Desc%,"",,

[SourceDisksFiles]
; TODO: Customize the name of your binary here.
; Also include any related files that should be installed with your driver.
globalsecureaccessdriver.sys=1

[DestinationDirs]
DefaultDestDir=12
globalsecureaccessdriver.copyfiles.sys=12

[globalsecureaccessdriver.copyfiles.sys]
; Customize the name of your binary here.
globalsecureaccessdriver.sys,,,2
<snipped>

GlobalSecureAccessDriver.sys はバイナリ ファイルのため中身を開いて読み取ることはできませんでした。。

GlobalSecureAccessStartServices.ps1

また、同じフォルダに「C:\Program Files\Global Secure Access Client\GlobalSecureAccessStartServices.ps1」を含むいくつかの PowerShell スクリプトがおいてありました。

$tunnelingServiceReturnCode = StartService -ServiceName "GlobalSecureAccessTunnelingService"
$pluginInstanceHostReturnCode = StartService -ServiceName "GlobalSecureAccessManagementService"
$policyProviderDaemonReturnCode = StartService -ServiceName "GlobalSecureAccessPolicyRetrieverService"

なんとなく雰囲気を見るに GlobalSecureAccessTunnelingService が MEPA の本体であり、GlobalSecureAccessPolicyRetrieverService が registry に書く内容を取得している感じがします。

とらぶるしゅーとやりづらそう

という印象になりますよねはい、完全に同意です。
そのためなのか、Microsoft Entra の Global Secure Access としてのアプリケーションに状態の表示からログの取得、表示まで、様々な機能が備わっています。
以前のようにコマンドを実行したりコントロール パネルなどを見て、、というよりかはこのアプリケーションでの表示内容と、Entra admin center の内容を見ながらトラブルシュートすることになりそうです。

実際、Microsoft Entra ユーザーではなくローカル ユーザーでログインすると Global Secure Access から「disbaled by your organization」というメッセージが出てしまい、いやどのテナントの話をしてるんだよ、というのが分かりづらいように思いますね。。

まとめ

今のところの理解だと、以下のような感じです。

  • GlobalSecureAccessPolicyRetrieverService が Microsoft Entra から該当の設定を取得してくる
    • 取得した内容は Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Global Secure Access Client\ForwardingProfile あたりの registry に書かれる
    • この動作については procmon でも見れたので確定です
  • GlobalSecureAccessTunnelingService がたぶん MEPA の本体
    • わからんけど取得した内容をもとに LWF の設定変更したりしてるんじゃあないか
    • procmon で見てても、GlobalSecureAccessTunnelingService がおそらく MEPA のエンドポイントである 150.x.x.x:https にアクセスしているように見えています
  • C:\Program Files\Global Secure Access Client\GlobalSecureAccessDriver.inf によって、GlobalSecureAccessDriver.sys がインストールされている
    • これが LWF の本体っぽい
    • コントロール パネルからインターフェースのプロパティにいくと見えるそれっぽいものがたぶんこれ
    • フィルター ドライバーという仕組みで、インターフェースをとおるパケットにいろんな処理を追加できる
    • GlobalSecureAccessPolicyRetrieverService により registry が書き換えられた後、GlobalSecureAccessManagementService が GlobalSecureAccessTunnelingService を再起動してるような感じなんでしょうが、その際にこの registry が読み込まれる様子がまだ procmon では見れていません。。

docs の グローバル セキュア アクセス クライアント にも書いてあったみたいです。

Global Secure Access クライアントは軽量フィルター (LWF) ドライバーを使ってトラフィックを取得しますが、他の多くの Security Service Edge (SSE) ソリューションは、仮想プライベート ネットワーク (VPN) 接続として統合されます。この違いにより、Global Secure Access クライアントは、これらの他のソリューションと共存できます。Global Secure Access クライアントは、構成されたトラフィック転送プロファイルに基づいてトラフィックを取得します。

ZTNA をうたうサービスはいくつかあり、ZTNA といえば VPN フリー!ということが多いように思うので他も同じような実装なのかもしれませんが、Zscaler なり Prisma Access も見てみたいですね。

参考

  • Microsoft Entra Private Access の出口

    こちらの記事では MEPA の出口側について調べてみています

https://zenn.dev/skmkzyk/articles/mepa-tunnel-exit

  • ZTNA と VPN の違い (Microsoft Entra Private Access を念頭に)

    そもそも ZTNA と VPN と何が違うの、うれしいの、というのを簡単にまとめています

https://zenn.dev/skmkzyk/articles/mepa-ztna-vs-vpn

  • Microsoft Entra Private Access について学習する

https://learn.microsoft.com/entra/global-secure-access/concept-private-access?wt.mc_id=MVP_391314

  • グローバル セキュア アクセス クライアント

https://learn.microsoft.com/entra/global-secure-access/concept-clients?wt.mc_id=MVP_391314

  • procmon

https://learn.microsoft.com/sysinternals/downloads/procmon?wt.mc_id=MVP_391314

  • Get-NetAdapterBinding

https://learn.microsoft.com/powershell/module/netadapter/get-netadapterbinding?wt.mc_id=MVP_391314

  • netcfg

https://learn.microsoft.com/windows-server/administration/windows-commands/netcfg?wt.mc_id=MVP_391314

  • 仮想スイッチ フィルターの使用

https://learn.microsoft.com/windows-hardware/drivers/network/using-virtual-switch-filtering?wt.mc_id=MVP_391314

  • フィルター ドライバー

https://learn.microsoft.com/windows-hardware/drivers/network/ndis-filter-drivers?wt.mc_id=MVP_391314

  • ドライバー パッケージのコンポーネント

https://learn.microsoft.com/windows-hardware/drivers/install/components-of-a-driver-package?wt.mc_id=MVP_391314

  • Microsoft Entra の Global Secure Access を使ってみる (Private Access 編)

https://zenn.dev/sugar3kg/articles/645e632231735f

  • Wireshark

https://www.wireshark.org/


Update log

  • グローバル セキュア アクセス クライアント への docs のリンクを追加 - 2024/06/17
  • Secure Service Edge (SSE) のイメージ画像を追加 - 2024/06/17
  • Entra admin center のスクリーンショット追加 - 2024/06/17
  • Wireshark と似てるな、みたいな話とかを追加 - 2024/07/14

Discussion

k.satok.sato

大変勉強になります!私もリリース当初に仕組みが気になり、ログ漁っていろいろ調べてました。Zscaler も Windows フィルタ ドライバーが使えるようになっているようです。(以前は仮想 NIC + ルーティングだった)
https://help.zscaler.com/ja/client-connector/using-windows-filter-driver-zscaler-client-connector

お互いに他のソリューションと共存を謳っていますが、フィルタ ドライバー同士の場合にどうなるか気になりますね。

skmkzykskmkzyk

わーい!お返事ありがとうございます!
そう、仕組みが気になっちゃうのでいろいろ調べてみました!聞いてる感じだと Cisco の Secure Access も filter らしいので全然かち合いそうだなという気がしています。。試せる範囲で組み合わせて検証してみたいと思っていますー!