はじめに

VPN Gateway の P2S VPN は、OpenVPN プロトコルと Entra ID 認証の組み合わせをサポートしています。通常は VPN Gateway が存在する自テナントの Entra ID を使いますが、カスタムオーディエンスアプリを利用することで、異なるテナントの Entra ID を使った P2S VPN 認証が構成できます。実際に試してみました。

異なるテナントでのカスタムオーディエンスアプリの登録

異なるテナントへの接続

Microsoft Graph を使って異なるテナントに接続します。

Connect-MgGraph `
  -TenantId "<異なるテナントのID>" `
  -Scopes "Application.ReadWrite.All", "AppRoleAssignment.ReadWrite.All", "Group.ReadWrite.All"

カスタムオーディエンスアプリの登録

P2S VPN の認証に使うカスタムオーディエンスアプリを登録します。

$app = New-MgApplication -DisplayName "p2s-vpn-custom-audience"
Get-MgApplication -Filter "displayName eq 'p2s-vpn-custom-audience'" |
  Select-Object DisplayName, AppId, Id

DisplayName             AppId                              Id
-----------             -----                              --
p2s-vpn-custom-audience <カスタムアプリのアプリケーションID> <オブジェクトID>

サービスプリンシパルの作成

登録したアプリのサービスプリンシパルを作成します。

$customSp = New-MgServicePrincipal -AppId $app.AppId
Get-MgServicePrincipal -Filter "appId eq '$($app.AppId)'" |
  Select-Object DisplayName, AppId, Id

DisplayName             AppId                              Id
-----------             -----                              --
p2s-vpn-custom-audience <カスタムアプリのアプリケーションID> <オブジェクトID>

Application ID URI とスコープの設定

Application ID URI を設定し、カスタムスコープ p2s-vpn を追加します。スコープの登録と PreAuthorizedApplications の設定は同時には行えないため、スコープを先に登録してから PreAuthorizedApplications を追加する 2 段階の手順が必要です。

まずスコープを登録します。

$scope = @{
    Id          = [System.Guid]::NewGuid().ToString()
    Value       = "p2s-vpn"
    Type        = "User"
    AdminConsentDisplayName = "P2S VPN Access"
    AdminConsentDescription = "Allow P2S VPN access"
    IsEnabled   = $true
}
$api = @{
    RequestedAccessTokenVersion = 2
    Oauth2PermissionScopes      = @($scope)
    IdentifierUris              = @("api://$($app.AppId)")
}
Update-MgApplication -ApplicationId $app.Id -IdentifierUris @("api://$($app.AppId)") -Api $api

スコープ登録後、Azure VPN クライアントアプリを PreAuthorizedApplications に追加します。

$registeredScope = (Get-MgApplication -ApplicationId $app.Id).Api.Oauth2PermissionScopes |
  Where-Object { $_.Value -eq "p2s-vpn" }
$preAuth = @{
    AppId                  = "c632b3df-fb67-4d84-bdcf-b95ad541b5c8"
    DelegatedPermissionIds = @($registeredScope.Id)
}
$apiUpdate = @{
    PreAuthorizedApplications = @($preAuth)
}
Update-MgApplication -ApplicationId $app.Id -Api $apiUpdate

Azure VPN クライアントアプリのサービスプリンシパル作成

Azure VPN クライアントアプリ(AppId: c632b3df-fb67-4d84-bdcf-b95ad541b5c8)のサービスプリンシパルを異なるテナントに作成します。

$azureVpnSp = New-MgServicePrincipal -AppId "c632b3df-fb67-4d84-bdcf-b95ad541b5c8"
Get-MgServicePrincipal -Filter "appId eq 'c632b3df-fb67-4d84-bdcf-b95ad541b5c8'" |
  Select-Object DisplayName, AppId, Id

DisplayName AppId                                Id
----------- -----                                --
Azure VPN   c632b3df-fb67-4d84-bdcf-b95ad541b5c8 <オブジェクトID>

管理者同意の付与

Azure VPN クライアントアプリからカスタムアプリへの管理者同意を付与します。

$consent = @{
    ClientId    = $azureVpnSp.Id
    ConsentType = "AllPrincipals"
    ResourceId  = $customSp.Id
    Scope       = "p2s-vpn"
}
New-MgOauth2PermissionGrant -BodyParameter $consent
Get-MgOauth2PermissionGrant -Filter "clientId eq '$($azureVpnSp.Id)'" |
  Select-Object ClientId, ConsentType, ResourceId

ClientId     ConsentType   ResourceId
--------     -----------   ----------
<オブジェクトID> AllPrincipals <オブジェクトID>

グループによるアクセス制限の設定

AppRoleAssignmentRequiredTrue に設定することで、割り当てられたユーザーやグループのみが認証を通過できるようにします。

Update-MgServicePrincipal -ServicePrincipalId $customSp.Id -AppRoleAssignmentRequired:$true

Get-MgServicePrincipal -ServicePrincipalId $customSp.Id |
  Select-Object DisplayName, AppRoleAssignmentRequired

DisplayName             AppRoleAssignmentRequired
-----------             -------------------------
p2s-vpn-custom-audience                      True

P2S VPN を利用させるセキュリティグループを作成し、カスタムアプリのサービスプリンシパルに割り当てます。

$group = New-MgGroup `
  -DisplayName "p2svpn" `
  -MailEnabled:$false `
  -MailNickname "p2svpn" `
  -SecurityEnabled:$true

Get-MgGroup -Filter "displayName eq 'p2svpn'" | Select-Object DisplayName, Id

DisplayName Id
----------- --
p2svpn      <グループID>
$group = Get-MgGroup -Filter "displayName eq 'p2svpn'"
New-MgGroupAppRoleAssignment `
  -GroupId $group.Id `
  -PrincipalId $group.Id `
  -ResourceId $customSp.Id `
  -AppRoleId "00000000-0000-0000-0000-000000000000"

Get-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $customSp.Id |
  Select-Object PrincipalDisplayName, PrincipalType, AppRoleId

PrincipalDisplayName PrincipalType AppRoleId
-------------------- ------------- ---------
p2svpn               Group         00000000-0000-0000-0000-000000000000

自テナントでのネットワークリソースの作成

自テナントに接続し、ネットワークリソースを作成します。

リソースグループと仮想ネットワークを作成します。

New-AzResourceGroup -Name "rg-p2s-cross-tenant" -Location "japaneast"

$vnet = New-AzVirtualNetwork `
  -Name "vnet-p2s-cross-tenant" `
  -ResourceGroupName "rg-p2s-cross-tenant" `
  -Location "japaneast" `
  -AddressPrefix "10.0.0.0/16"

GatewaySubnet と VM 用サブネットを追加します。

Add-AzVirtualNetworkSubnetConfig `
  -Name "GatewaySubnet" `
  -VirtualNetwork $vnet `
  -AddressPrefix "10.0.0.0/27" | Set-AzVirtualNetwork

Add-AzVirtualNetworkSubnetConfig `
  -Name "snet-vm" `
  -VirtualNetwork $vnet `
  -AddressPrefix "10.0.1.0/24" | Set-AzVirtualNetwork

VPN Gateway 用のパブリック IP を作成します。

$pip = New-AzPublicIpAddress `
  -Name "pip-vpngw-p2s-cross-tenant" `
  -ResourceGroupName "rg-p2s-cross-tenant" `
  -Location "japaneast" `
  -AllocationMethod Static `
  -Sku Standard

Get-AzPublicIpAddress -Name "pip-vpngw-p2s-cross-tenant" -ResourceGroupName "rg-p2s-cross-tenant" |
  Select-Object Name, Location, PublicIpAllocationMethod, IpAddress

Name                       Location  PublicIpAllocationMethod IpAddress
----                       --------  ------------------------ ---------
pip-vpngw-p2s-cross-tenant japaneast Static                   xx.xx.xx.xx

VPN Gateway の作成と P2S 設定

VPN Gateway を作成します。作成には 30 分ほどかかります。

$vnet = Get-AzVirtualNetwork -Name "vnet-p2s-cross-tenant" -ResourceGroupName "rg-p2s-cross-tenant"
$pip  = Get-AzPublicIpAddress -Name "pip-vpngw-p2s-cross-tenant" -ResourceGroupName "rg-p2s-cross-tenant"
$gwSubnet = Get-AzVirtualNetworkSubnetConfig -Name "GatewaySubnet" -VirtualNetwork $vnet
$gwIpConfig = New-AzVirtualNetworkGatewayIpConfig `
  -Name "gwipconfig" `
  -SubnetId $gwSubnet.Id `
  -PublicIpAddressId $pip.Id

New-AzVirtualNetworkGateway `
  -Name "vpngw-p2s-cross-tenant" `
  -ResourceGroupName "rg-p2s-cross-tenant" `
  -Location "japaneast" `
  -IpConfigurations $gwIpConfig `
  -GatewayType "Vpn" `
  -VpnType "RouteBased" `
  -GatewaySku "VpnGw1" `
  -VpnGatewayGeneration "Generation2"
Get-AzVirtualNetworkGateway `
  -Name "vpngw-p2s-cross-tenant" `
  -ResourceGroupName "rg-p2s-cross-tenant" |
  Select-Object Name, ProvisioningState, GatewayType, VpnType

Name                   ProvisioningState GatewayType VpnType
----                   ----------------- ----------- -------
vpngw-p2s-cross-tenant Succeeded         Vpn         RouteBased

P2S 設定を構成します。AadTenant と AadIssuer には異なるテナントの ID を、AadAudience にはカスタムアプリのアプリケーション ID を指定します。

$gw = Get-AzVirtualNetworkGateway `
  -Name "vpngw-p2s-cross-tenant" `
  -ResourceGroupName "rg-p2s-cross-tenant"
Set-AzVirtualNetworkGateway `
  -VirtualNetworkGateway $gw `
  -VpnClientAddressPool "172.16.0.0/24" `
  -VpnClientProtocol OpenVPN `
  -VpnAuthenticationType AAD `
  -AadTenantUri "https://login.microsoftonline.com/<異なるテナントのID>/" `
  -AadAudienceId "<カスタムアプリのアプリケーションID>" `
  -AadIssuerUri "https://sts.windows.net/<異なるテナントのID>/"

設定を確認します。

$gw = Get-AzVirtualNetworkGateway `
  -Name "vpngw-p2s-cross-tenant" `
  -ResourceGroupName "rg-p2s-cross-tenant"
$gw.VpnClientConfiguration |
  Select-Object VpnClientProtocols, VpnAuthenticationTypes, AadTenant, AadAudience, AadIssuer
VpnClientProtocols     : {OpenVPN}
VpnAuthenticationTypes : {AAD}
AadTenant              : https://login.microsoftonline.com/<異なるテナントのID>/
AadAudience            : <カスタムアプリのアプリケーションID>
AadIssuer              : https://sts.windows.net/<異なるテナントのID>/

VPN クライアント設定ファイルの生成と接続確認

VPN クライアント設定ファイルを生成します。

$urls = New-AzVpnClientConfiguration `
  -ResourceGroupName "rg-p2s-cross-tenant" `
  -Name "vpngw-p2s-cross-tenant" `
  -AuthenticationMethod EAPTLS
Invoke-WebRequest -Uri $urls.VpnProfileSASUrl -OutFile "vpnclient.zip"
Expand-Archive -Path "vpnclient.zip" -DestinationPath ".\outputs\vpnclient" -Force

生成された outputs\vpnclient\AzureVPN\azurevpnconfig.xml を Azure VPN Client でインポートし、異なるテナントのユーザーアカウントで接続します。接続後、確認用 VM(10.0.1.4)へのポート疎通を確認します。

Test-NetConnection -ComputerName 10.0.1.4 -Port 3389

ComputerName     : 10.0.1.4
RemoteAddress    : 10.0.1.4
RemotePort       : 3389
InterfaceAlias   : vnet-p2s-cross-tenant
SourceAddress    : 172.16.0.2
TcpTestSucceeded : True

P2S アドレスプール(172.16.0.0/24)からクライアントに 172.16.0.2 が払い出され、VM の RDP ポートへの疎通が確認できました。いい感じです。

また、p2svpn グループに所属するユーザーは P2S VPN に接続でき、グループ外のユーザーは認証エラーで接続が拒否されました。こちらもいい感じです。

まとめ

カスタムオーディエンスアプリを利用することで、VPN Gateway P2S VPN の Entra ID 認証を異なるテナントで構成できることを確認しました。Microsoft 365 で使っている普段使いの Entra ID と Azure サブスクリプションが紐づく Entra ID が分かれているようなケースで役に立ちそうです。

参考リンク

  • 当サイトは個人のブログです。このブログに示されている見解や意見は個人的なものであり、所属組織の見解や意見を表明するものではありません。
  • 公開情報を踏まえて正確な情報を掲載するよう努めますが、その内容の完全性や正確性、有用性、安全性、最新性について一切保証しません。
  • 添付文章やリンク先などを含む本サイトの内容は作成時点でのものであり、予告なく変更される場合があります。