Microsoft 365 PowerShell 用のユーザーを作成する方法を覚えましょう

前回ちょっと紹介した Microsoft 365 の PowerShell をバッチ実行するためのユーザー作成ですが、スクリプトだけだとなかなかわかりにくいので、画面を交えて説明していきたいと思います。

このログイン方法は、管理者権限を脅威にさらさないための数少ない方法なので、早期に対応しておくことをお薦めします。

まず、この PowerShell での接続方法では 証明書を利用してログインを行っていく方法となります。そのため、運用として証明書の期限チェックと、証明書変更時に証明書情報の書き直しが必要となります。この点を意識してコードを作っていくことを忘れないようにしましょう。

最初に行うことは証明書の作成です。証明書は利用用途が「接続時にすでに知っている相手であることを証明する」という使い方であるため、自己証明でも問題ありません。ただし、アクセスする側が証明書の秘密鍵を持っている必要があるため、その点への配慮が必要です。

前回説明した Example 3 と照らし合わせながら見ていきましょう。

https://docs.microsoft.com/en-us/powershell/module/azuread/connect-azuread?WT.mc_id=M365-MVP-5002496&view=azureadps-2.0#example-3--connect-a-session-as-a-service-principal

まず最初の自己証明書作成の部分です。

# Create the self signed cert

上記の場合 2 年間有効な証明書「 com.foo.bar 」を作成し、マシンのローカルストアに挿入、その後秘密鍵付き証明書ファイルを Temp フォルダーに保存しています。

作業マシン上で今後もログインし、自動化処理を行う場合は Export 以後のコマンドは実行しなくても問題ありません。

が、 Windows Server 上で動作させたり、 Azure Automate などで実行させる場合はこのこの証明書を移設して利用することになります。移設する証明書は秘密鍵を持っているため、利用後削除するなど、管理は厳格にしておきましょう。(証明書ファイルをなくした場合、再度作成して設定すればよいだけなので、無用なコピーを持たない運用がお薦めです。)

なお docs のスクリプトでは 2 年といった証明書期限の切り方をしていますが、運用で忘れないようにしておくためにも短い期間でローテーションさせることをお薦めします。

といった感じで、ちょっとカスタマイズしたスクリプトが以下です。
$cn の名前で証明書を作成し、 $pwd の値で秘密鍵付き証明書を保存しています。

PowerShell は管理者で起動して利用しましょう。

$currentDate = Get-Date
$notAfter = $currentDate.AddYears(1)
$pwd = "testcert"
$cn = "PowerShellCert2021"
$certfilePath = "c:\"
$thumb = (New-SelfSignedCertificate -CertStoreLocation cert:\localmachine\my -DnsName $cn -KeyExportPolicy Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -NotAfter $notAfter).Thumbprint
$pwd = ConvertTo-SecureString -String $pwd -Force -AsPlainText
Export-PfxCertificate -cert "cert:\localmachine\my\$thumb" -FilePath "$certfilePath$cn.pfx" -Password $pwd
Export-Certificate -cert "cert:\localmachine\my\$thumb" -FilePath "$certfilePath$cn.nokey.cer"

f:id:mohessu:20210515232415p:plain

mmc の証明書でローカルコンピューターを開くと作成したファイルが出ていると思います。

f:id:mohessu:20210515225006p:plain

今回は試験のため削除していませんが、最終的に動作させるマシン以外には証明書は不要なので必要に応じて証明書ストアからの削除を忘れずに行いましょう。
削除スクリプトは以下ですが、別タイミングで消す場合は UI から削除したほうが安全ですね。
Get-ChildItem "cert:\localmachine\my\$thumb" | Remove-Item

 

 

続いて Microsoft 365 側での設定です。

Example 3 では一部順序が入れ替わりますが以下 3 つが該当します。

# Login to Azure AD PowerShell With Admin Account
# Load the certificate
# Create the Azure Active Directory Application

このコードも若干違和感があるのでアレンジてみるとこんな感じです。

# Login to Azure AD PowerShell With Admin Account

# まずここで Microsoft 365 管理者でログインします。
# ログインは対話なので MFA などを利用していても問題ありません。
Connect-AzureAD

# Load the certificate

# ここでの違いは秘密鍵を持たない証明書を用いている点です。
# 基本的には秘密鍵はネットワーク経由でのやり取りは行わないようにしましょう。
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate("$certfilePath$cn.nokey.cer")
$keyValue = [System.Convert]::ToBase64String($cert.GetRawCertData())

# Create the Azure Active Directory Application

# ここにも手を加えています。
# 追加として所有者の設定、不要なURIの削除を行っています。
# なお CustomKeyIdentifier を設定しておくと UI 上で拇印が表示されなくなるようです
$session = Get-AzureADCurrentSessionInfo
$currentUser = Get-AzureADUser | Where-Object { $_.UserPrincipalName -eq $session.Account.Id}
$application = New-AzureADApplication -DisplayName "PowerShell向け"
Add-AzureADApplicationOwner -ObjectId $application.ObjectId -RefObjectId $currentUser.ObjectId

New-AzureADApplicationKeyCredential -ObjectId $application.ObjectId -CustomKeyIdentifier "Secret" -StartDate $currentDate -EndDate $endDate -Type AsymmetricX509Cert -Usage Verify -Value $keyValue

ちょっと長いですが、上記 PowerShell を実行すると PowerShell 用のユーザー作成が完了できます。 UI から実施するとかなりの道のりなので覚悟しておきましょう。笑

UI での設定は AzureAD ポータルからとなります。 Microsoft 365 の管理者であれば AzureAD の管理者となるため、以下のサイトへアクセスすることが可能です。

まずはアプリの登録に移動しましょう。

https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/Overview

f:id:mohessu:20210515215828p:plain

続いて右ペインに出てくる新規登録ボタンを押し、 PowerShell 用のユーザーをアプリとして登録していきます。

f:id:mohessu:20210515220535p:plain

アプリケーションの登録画面で実際にアクセスするユーザーを作っていきます。

このユーザーでアクセスすることになるため、ロールに即した名前にしておきましょう。アカウントの種類は初期設定のシングルテナントで問題ありません。

f:id:mohessu:20210515230829p:plain

登録すると PowerShell でアクセスするユーザーの主体が完成です。
この画面のアプリケーション(クライアント) ID とディレクトリ(テナント) ID はメモしておきましょう。接続時に利用することになります。

続いて右側にある Add a certificate or secret を押しましょう。
このボタンを押すことで証明書の登録を行うことができます。

f:id:mohessu:20210515231138p:plain

ここで必要な証明書は秘密鍵なし証明書となるため、先ほど作成した.nokey.cerで終わるファイルを登録していきます。証明書のアップロードを押し、登録していきましょう。

f:id:mohessu:20210515232723p:plain

f:id:mohessu:20210515232957p:plain

登録が完了すると拇印が表示されるので、この値をメモしておきましょう。

先ほどのアプリケーション(クライアント) ID とディレクトリ(テナント) ID と共に、 PowerShell からの接続で利用します。

f:id:mohessu:20210515233130p:plain

時間があれば、手元の証明書とずれがないことも確認しておくとよいですね。

mmc 上で拇印を確認できます。

f:id:mohessu:20210515230405p:plain

証明書の有効期限が切れそうになったら、この画面から新しい証明書を登録することで同じアプリを継続して利用することができます。

続いてロールの管理です。
この時点で PowerShell から Microsoft 365 へアクセスするためのユーザーが作成されました。が、このユーザーは管理者でも何でもないので、 PowerShell から Microsoft 365 の機能を操作することが許可されていません。

権限がないと、以下のような形でアクセスを拒絶されてしまいます。

f:id:mohessu:20210515235438p:plain

各種許可を与えていき、操作が行えるようにしていきます。

Example 3 では以下の 2 か所に当たります。

# Create the Service Principal and connect it to the Application
# Give the Service Principal Reader access to the current tenant

ここも若干手直しが必要だったのでコードを記述していきます。

# Create the Service Principal and connect it to the Application
$sp=New-AzureADServicePrincipal -AppId $application.AppId

# Give the Service Principal Reader access to the current tenant (Get-AzureADDirectoryRole)
Get-AzureADDirectoryRole | Where-Object {$_.DisplayName -eq "License Administrator" } | Add-AzureADDirectoryRoleMember -RefObjectId $sp.ObjectId

変更点はアクセス権の割り当てですが、行いたいことにより付与するアクセス権が違うと思います。

先に Get-AzureADDirectoryRole でロール名を調べておき、上記の License Administrator の個所を変更するとよいでしょう。(この例ではライセンス管理者の権限を付与しています。)

f:id:mohessu:20210516014946p:plain

UI で設定する場合は以下のアドレスにアクセスし、テナントのロールと管理者を開きます。

https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RolesAndAdministrators

f:id:mohessu:20210515234333p:plain

ここで選べるものは Microsoft 365 管理センターの役割と同等と考えましょう。
Azure の管理権限もあるため、もうちょっと広く設定できます。

例えばライセンス管理者の権限を与えてみましょう。

f:id:mohessu:20210516000010p:plain

名称をクリックするとライセンス割り当ての画面に移動します。
割り当ての追加を押し、先ほど作成したアプリを検索、追加します。

f:id:mohessu:20210516000628p:plain

この画面、検索結果を選択しなくても追加のボタンが押せてしまうので、検索した後に選択することを忘れないようにしましょう。

f:id:mohessu:20210516000834p:plain

これでライセンス関連の操作が許可されました。

f:id:mohessu:20210516001022p:plain

ここまで対応するとようやく外部から利用できるようになります。

Example 3 では、各種情報を直接オブジェクトからとってきていますが、バッチスクリプトではそうもいきません。そのため、ここまでにメモした値を設定して接続に入ります。
PowerShell で見てきた場合は以下コマンドでそれぞれの値を表示することができます。

# 拇印

$thumb

ディレクトリ(テナント) ID 
Get-AzureADTenantDetail | Where-Object {Write-host $_.ObjectId}
# アプリケーション(クライアント) ID
$application.AppId

上記の値を以下 PowerShell コマンドにコピーし、保存しておけばいつでも証明書を使った接続が行えるようになるという訳です。

$thumprintId = "拇印"
$tenantId = "ディレクトリ(テナント) ID "
$appId = "アプリケーション(クライアント) ID"

Connect-AzureAD -CertificateThumbprint $thumprintId -TenantId $tenantId -ApplicationId $appId

ライセンス一覧を表示する以下コマンドを打ってみると、見事読み取ることに成功しています。

Get-AzureADSubscribedSku

f:id:mohessu:20210516020633p:plain

単にログインするだけでここまで手間をかけるのか。と思いたくもなりますが、バッチスクリプトではこれだけのことを行わないと危ない。というのが現在の状況です。

ただ、一度覚えてしまえばそれほど難しくもないので、まだパスワードベースのアカウントを利用している場合はぜひ置き換えを行っていくようにして下さい。

音楽:モンゴル帝国