ゲスト ユーザーを Active Directory に Writeback してみる - その 1

みなさん初めまして。以前までは ITBeginner という個人ブログに技術記事を投稿していたのですが、運営が追い付かず仕方なく閉鎖となり、プラットフォームを note へ移行しました。最近はアウトプットが出来ていませんでしたが、備忘録も兼ねてやっぱり継続したいと思いますので、よろしくお願いいたします。

早速ですが、記事名を見たとき、頭の中に「?」が浮かぶ方もいらっしゃるかもしれません。

というのも、「ゲスト ユーザーを Writeback させたい」なんて要件を耳にすることはあまりありませんし、Azure AD Connect には、そのような機能がないためです。

私自身も「ゲスト ユーザー なんて Writeback できません~」と思っていたのですが、下記リンクにそれらしきマイクロソフトの公開情報が...。

本記事では、上記の内容に基づいて、記事タイトルにある通り "ゲスト ユーザーを Active Directory に Writeback してみる"

なぜ、Writeback させる必要があるのか?

一言でいうと、「ゲスト ユーザーが、Azure AD Application Proxy で外部公開したオンプレミス アプリケーションに、Kerberos 制約付き委任を使用してアクセスするため」です。

Azure AD Application Proxy (AADAP) を使ったオンプレミス アプリケーションの外部公開については下記が参考になります。

Kerberos 制約付き委任 (KCD) を使った SSO 認証フローについては下記の公開情報に詳細な情報が記載されいいます。

アプリケーションへのログインに Kerberos を使用しているため、当然ですが、Azure AD ユーザーの対となる AD アカウントを作成しておく必要があります。この辺りは認証認可の話ですね。

通常、ディレクトリ同期で Azure AD に同期されたユーザーは、上述を意識しなくてもいいのですが、ゲスト ユーザーは Azure AD にのみ存在するユーザーであるため、Writeback が必要になります。

今回のような要件においては、ゲスト ユーザー自身が直接 AD に認証を要求するのではなく、AADAP の Connector がゲスト ユーザーになりすまして AD へ認証を要求 および Kerberos のサービスチケットを取得する、つまりは KCD を使用するということです。

スライド1

Connector は、認証を要求してきたゲスト ユーザーになりすまして認証を要求します。この時、Connector はなりすましのために、「あなたの AD アカウントはどれですか?」を解決できる必要があります。
このため、Azure AD と AD に存在する両アカウントの UserPrincipalName を同値にしておく必要があります。

スライド2

つまり、Azure AD のユーザー アカウントと、AD のユーザー アカウントの UPN が同値になるよう手動で作成すれば、KCD を使ってオンプレミス アプリにアクセスできるようになるということです。

ただ、手動で作成するのは面倒くさいので、これをシステマチックに行えるように構成することが本記事の目的です。

以降では ゲスト ユーザーの Writeback を実際に構成するための手順を記載しております。(本当は AADAP 辺りの話も含めた包括な記事にしたいのですが、ボリュームが多くなっちゃうので適宜追加していきます...💦

システム構成

ゲスト ユーザーを Writeback させるには 2 つの方法があります。

1. MIM 2016 に Microsoft Graph の MA を追加して Writeback する方法
2. スクリプトを介して Writeback する方法

1. は MIM Server が既に環境に存在していればいいのですが、多くの組織には無いような気がするので、今回はお手軽な 2. の方法で実際に Writeback させたいと思います。

本記事では、ゲスト ユーザーの Writeback までの紹介とします。AADAP や KCD については別途まとめていきたいと思います。

画像3

それでは、上図の環境を構築していきましょう。
なお、AD は既に構築済みであることが前提です。

スクリプトのダウンロード

まずは、下記サイトから「Script and Readme to pull Azure AD B2B users on-prem_v1.0.3.ip」をダウンロード・解凍します。

解凍したら、「AppProxy-GuestAccountCreation-v1.0.3.ps1」を Writeback Server の任意のディレクトリに配置します。

アプリケーションの登録

本スクリプトでは、Azure AD から発行される Access Token を使って API にアクセスしています。

# AppProxy-GuestAccountCreation-v1.0.3.ps1 - 64行目 ~ 68行目

$loginURL = "https://login.microsoftonline.com/" # AAD Instance; for example https://login.microsoftonline.com for public or https://login.microsoftonline.us for government cloud
$resource = "https://graph.windows.net"
$body = @{grant_type="client_credentials";resource=$resource;client_id=$appID;client_secret=$appSecret}
$oauth = Invoke-RestMethod -Method Post -Uri $loginURL/$tenantdomain/oauth2/token?api-version=1.5 -Body $body 
Connect-AzureAD -AadAccessToken $oauth.access_token -TenantId $tenantID -AccountId $appID

そのため、スクリプトを Azure AD にアプリとして登録し、必要な API アクセス許可を付与した後、シークレット キーを発行します。

Azure ポータルの [アプリの登録] メニューから、[+ 新規登録] をクリックします。

画像4

アプリ名は任意のものを入力し、[シングル テナント] を選択して [登録] します。

画像5

登録したアプリの [概要] にある、[アプリケーション] ID を控えておきましょう。

画像6

スクリプトに API のアクセス許可を付与します。
[API のアクセス許可] - [+ アクセス許可の追加] をクリックします。

画像7

[Azure Active Directory Graph] の ”Directory.Read.All” を選択して、[アクセス許可の追加] します。

画像8

今回は、ユーザーが介入することなくアプリケーション自身が Access Token を取得するため、管理者の同意 (admin_consent) を付与しておく必要があります。
[既定のディレクトリに管理者の同意を与えます] から、管理者の同意を付与します。付与が完了すると、下図のように「既定のディレクトリに付与されました」と表示されます。

画像9

最後に、シークレット キー発行します。
[証明書とシークレット] - [新しいクライアント シークレット] をクリックします。

画像10

シークレットの有効期限を設定したら、[追加] します。

画像11

発行されたシークレット キーを控えておきましょう。

画像12

WritebackGuestUsers グループの作成

テナント上のすべてのゲスト ユーザーを Writeback するのではなく、特定のグループに属しているゲスト ユーザーのみを Writeback するよう実装されています。

Azure ポータルの [グループ] - [+ 新しいグループ] から、グループを一つ作成します。

画像13

作成したグループの [オブジェクト ID] を控えておきましょう。

画像14

ちなみに、このグループのメンバーシップが Writeback の対象ユーザーとして評価されるのですが、UserType が Guest ではなく、Member が紛れ込んでいる場合は除外するように設計されております。

# AppProxy-GuestAccountCreation-v1.0.3.ps1 - 95行目 ~ 104行目

ForEach($key in $($UsersInB2BGroupHash.Keys))
   {
   # remove non-guest users from the AAD Group list
   if($TenantGuestUsersHash.ContainsKey($key) -eq $false)
       {
       # if we want to output anything about non-Guest users it needs to pull from the Group Membership hash 
       # as these users will not be in the guest users hash table e.g. 
       # $UsersInB2BGroupHash[$key].emailaddress
       $UsersInB2BGroupHash.Remove($key)
       }

AD の準備

新しく招待されたゲストユーザーは、指定された OU に Writeback されます。また、既に Writeback されたゲストユーザーが、Azure AD 上で削除された場合、指定されたリタイア用の OU にアカウント無効状態で移動されます。

# AppProxy-GuestAccountCreation-v1.0.3.ps1 - 163行目 ~ 169行目

ForEach ($shadow in $($B2bShadowAccountsHash.keys))
{
   # $upn = the key from B2bShadowAccountsHash = $shadow
   # disable operation takes precedence over deletion
   Get-AdUser -Filter {UserPrincipalName -eq $shadow} -SearchBase $ShadowAccountOU| Set-ADUser -Enabled $false -Description 'Disabled pending removal' 
   Get-AdUser -Filter {UserPrincipalName -eq $shadow} -SearchBase $ShadowAccountOU | Move-ADObject -TargetPath $ShadowAccountOUArchive            
}

[Active Directory ユーザーとコンピューター] から以下の OU 2 つを新規作成します。
※ Writeback された AD アカウントが、Azure AD Connect で再び Azure AD に同期されないよう、同期対象外 OU にしてください。

画像15

作成した 2 つの OU の distinguishedName を控えておきましょう。OU の [プロパティ] - [属性エディター] から確認可能です。

画像17

次に、ゲスト ユーザーの UPN サフィックス を AD に登録しておく必要があります。[Active Directory ドメインと信頼関係] を開きます。
[Active Directory ドメインと信頼関係] - [プロパティ] からゲスト ユーザーの UPN サフィックスを追加します。

画像17

Writeback Server の準備

スクリプトでは、Active Directory および Azure Active Directory v2 のモジュールを使用します。

Writeback Server の PowerShell からインストールしておきます。

# Install Active Directory PowerShell Module
Install-WindowsFeature -Name RSAT-AD-PowerShell

# Install Azure Active Directory v2 Module
Install-Module -Name AzureAD

次に、スクリプトを実行するための gMSA (グループ管理サービスアカウント) を作成します。

$cpu = Get-ADComputer <ComputerName> # Server that will be running the script
$acctName = "gmsa_b2b_script"  

New-ADServiceAccount -Description "Account for creating B2B users" -DisplayName $acctName -DNSHostName "$acctName.contoso.com" -Name $acctName -PrincipalsAllowedToRetrieveManagedPassword $cpu  

Install-ADServiceAccount $acctName

コマンド実行後、gmsa_b2b_script という名前の gMSA が作成されていることが確認できます。

画像18

gmsa_b2b_script に Writeback Server のローカル Administrator 権限を付与します。

急ぎ

さて、いよいよスクリプトの準備へ移ります。
冒頭にコピーした AppProxy-GuestAccountCreation-v1.0.3.ps1 をメモ帳 または PowerShell ISE で開きます。

49 行目 ~ 56 行目に、それぞれ控えた値をコピペしていきます。

$B2BGroupSid = "XXXXXXXX-a302-475a-b62f-c74faec4e5ff" #Cloud group's ObjectID
$ShadowAccountOU = "OU=B2B Writeback,OU=contoso,DC=contoso,DC=com" #Organizational Unit for placing shadow accounts
$ShadowAccountOUArchive = "OU=B2B Writeback Retired,OU=contoso,DC=contoso,DC=com" #Organizational Unit for moving disabled shadows

# Requires Azure AD configuration - refer to documentation
$appID = "XXXXXXXX-1916-4d4c-b820-27c01c5f2c65" # Insert your application's Client ID, a Globally Unique ID (registered by Global Admin)
$appSecret = "XXXXXXXXXXZaDEBm6zvKq2mDmQ9"  # Insert your application's Client Key/Secret string
$tenantdomain   = "XXXXX.onmicrosoft.com"    # AAD Tenant; for example, contoso.onmicrosoft.com
$tenantID = "XXXXXXXX-077b-4548-8004-da63aeddf0db" # Identifier of the tenant domain

ちなみに、tenantID は Azure ポータル画面から確認できます。

画像20

スクリプトが定期的に実行されるようにタスクスケジューラーに登録します。各種パラメーター値は環境に応じて変更してください。

$action = New-ScheduledTaskAction -Execute powershell.exe -Argument '-NonInteractive -NoLogo -NoProfile -File "C:\Users\administrator.CONTOSO\Desktop\AppProxy-GuestAccountCreation-v1.0.3.ps1"'
$trigger = New-ScheduledTaskTrigger -At 7:00 -Daily
$principal = New-ScheduledTaskPrincipal -UserId contoso\gmsa_b2b_script$ -LogonType Password 
Register-ScheduledTask CreateB2BGuestUserObjects -Principal $principal -Action $action -Trigger $trigger

最後に、gMSA アカウントに対して Writeback 用の OU の委任を付与します。各種パラメーター値は環境に応じて変更してください。

dsacls.exe "OU=B2B Writeback,OU=contoso,DC=contoso,DC=com" /G  "contoso\gmsa_b2b_script$:GA" /I:T 
dsacls.exe "OU=B2B Writeback Retired,OU=contoso,DC=contoso,DC=com" /G  "contoso\gmsa_b2b_script$:GA" /I:T 

実際に Writeback させてみる

それでは早速 Writeback してみたいと思います。
適当に招待したゲスト ユーザーを作成したセキュリティグループのメンバーに入れてあげます。

その状態でタスクスケジューラーを手動実行するか、スクリプトを実行してみてください。

実行後、指定した OU に AD ユーザーが作成されていることが確認できます。

画像21

UPN も Azure AD のものと同値であることが確認できます。このアカウントの用途はあくまで Kerberos 制約付き委任 であるため、意図しないログオンが発生しないよう [対話型ログオンにはスマート カードが必要] にチェックが入った状態となります。

また、Writeback されたゲスト ユーザーが、Azure AD 上で削除されると、アカウントは無効な状態となり、リタイア用の OU に移動されます。

画像23

確認できているスクリプトの不具合

Preview なので仕方ないのですが、2020 年 3 月現在、このスクリプトでは Writeback に失敗するケースがあります。

スクリプト内では、下記のようにゲスト ユーザーの UPN の先頭から 20 文字を抽出して sAMAccountName にしているのですが、末尾が「.」になっている場合、sAMAccountName の禁則文字に該当し、New-ADUser コマンドが失敗します。

# AppProxy-GuestAccountCreation-v1.0.3.ps1 - 131行目

$samaccountname = $TenantGuestUsersHash[$key].userprincipalname.Substring(0, 20)

「.」を「_」に置換するように、書き換えるなどして対策しましょう。

$prefix = $TenantGuestUsersHash[$key].userprincipalname.Substring(0, 20)

if ($prefix.Substring($prefix.Length - 1,1) -eq "."){
$samaccountname = $prefix.Substring(0,19) + "_"
} 
else
{
$samaccountname = $prefix
}


いいなと思ったら応援しよう!