Azure Service Principal の設定: 不在時アクセスガイド

Azureのスクリプトやツールを使用してタスクを自動化する必要がある場合、サービスアカウントまたはAzureサービスプリンシパルを使用することを検討しますか?一部の人々は、新しいサービスアカウントを作成し、必要なすべての管理者ロールを付与し、MFAの除外対象としますが、これは珍しいことではありません。

I know what you’re thinking – “that is a horrible idea”. Of course, it is! And for sure, your IT Sec will give you a lot of grief if you did all that.

しかし、代替案はありますか?MFAの除外が必要ない制限されたスコープを持つ特権資格情報を使用する方法はありますか?この記事では、幸運なことに、それについて学ぶことができます。

この記事では、Azureサービスプリンシパルについて学びます。パスワード、シークレットキー、証明書など、さまざまなタイプの資格情報を使用してサービスプリンシパルを作成する方法について学びます。

Azureサービスプリンシパルを作成するための多くのツールがあります。これには、AzureポータルAzure Active Directory管理センターAzure AD PowerShellAzure CLI、およびAzure PowerShellが含まれます。この記事の焦点となるツールは、Azure PowerShellです。

まだ興味がありますか?読み続けて始めましょう!

要件

これは学習中に行う記事なので、一緒に進めるためのいくつかの前提条件を紹介します。

  • Azureのサブスクリプションへのアクセスが必要です。テストテナントで作業すると最適です。持っていない場合は、無料トライアルに登録してください。
  • PowerShell 5.1を実行しているWindows 10のコンピュータへのアクセスが必要です。
  • Azure PowerShellモジュールがインストールされている必要があります。

Azure Service Principal vs. Service Account

自動化ツールやスクリプトでは、管理者や特権アクセスが必要なことがよくあります。たとえば、ストレージアカウントのプロビジョニングやスケジュールに基づいた仮想マシンの起動と停止などです。そして、ほとんどの管理者は、スクリプトの認証要件を設定するために完全特権のユーザーアカウント(サービスアカウントと呼ばれる)を使用するでしょう。

A service account is essentially a privileged user account used to authenticate using a username and password. And, if used with automation, a service account is most likely excluded from any conditional access policies or multi-factor authentication.

一方、Azureのサービスプリンシパルは、ユーザー名とパスワードまたは証明書を使用して設定することができます。ユーザーではなく、アプリケーションのためのアイデンティティと考えてください。

Azureのサービスプリンシパルは、特定の単一のAzureリソースに対して必要最小限のアクセス権限を割り当てることができます。たとえば、Azureのサービスプリンシパルを作成して、サブスクリプション全体または単一のAzure仮想マシンにロールベースのアクセスを持たせることができます。

Azureサービスプリンシパルを作成する際の主な考慮事項

Azureサービスプリンシパルを作成する前に、計画するために必要な基本的な詳細を把握しておく必要があります。これらの詳細はシンプルに見えるかもしれませんが、効率的かつ簡単にAzureサービスプリンシパルを作成するために役立ちます。

表示名。名前から始まり、Azureサービスプリンシパルには名前が必要です。ルールはありませんが、組織によっては指定された命名規則があるかもしれません。

  • 使用する資格情報の種類。パスワードまたは証明書を使用するAzureサービスプリンシパルを作成することができます。これは、1つだけを選択する必要があるという意味ではありません。両方を使用することもできます。

サービスプリンシパルの場合、ユーザー名とパスワードは応用プログラムIDとシークレットキーとしてより適切に参照されます。

  • 資格情報の有効期間。パスワードまたは証明書の資格情報を割り当てる場合、その有効期間の開始日と終了日を定義する必要があります。資格情報の有効期間は、通常、証明書とパスワードをどれくらいの頻度でローテーション/更新するかによって異なります。
  • アクセスの範囲。Azureサービスプリンシパルがサブスクリプション、リソースグループ、または選択したリソースにアクセスするかどうかを定義する必要があります。
  • 役割。いくつかの役割が利用可能です。例えば、ContributorReaderOwnerなどです。どの役割がサービスプリンシパルにとって適切かを定義する必要があります。

自動割り当てされたシークレットキーを使用してAzureのサービスプリンシパルを作成する

新しいAzureのサービスプリンシパルを作成するための中心となるのは、New-AzAdServicePrincipalコマンドレットです。この例では、以下の値を持つ新しいサービスプリンシパルが作成されます:

表示名AzVM_Reader

スコープAzVM1 (仮想マシン)

ロールReader

パスワード<自動割り当て>

資格情報の有効期間:1年

ターゲットスコープ(仮想マシン)のIDを取得する

上記の例では、この新しいサービスプリンシパルのスコープはAzVM1という名前の仮想マシンに限定されています。ただし、-Scopeパラメータは単に名前を受け付けるのではなく、リソースの全体のIDを必要とします。したがって、この例では、最初にAzVM1仮想マシンのIDを取得する必要があります。以下のコードを使用してそれを行います。

Get-AzVM | Format-Table Name, ID

上記のコードをPowerShellで実行すると、以下のスクリーンショットと似たようなVMの名前とIDのリストが表示されるはずです。

Get the list of VM names and IDs

シークレットキーを持つAzureのサービスプリンシパルを作成する

これで、ターゲットスコープであるAzVM1仮想マシンのIDを取得したので、以下のコマンドを使用して、readerロールを持つ新しいサービスプリンシパルを作成できます。新しいサービスプリンシパルのプロパティは$sp変数に保存されます。

$sp = New-AzAdServicePrincipal `
	-DisplayName AzVM_Reader `
	-Scope '/subscriptions/5e252811-b376-4136-b8ae-d3b8abe2c9c3/resourceGroups/ATA/providers/Microsoft.Compute/virtualMachines/AzVM1'
	-Role 'Reader'

上記のコマンドの結果、以下の値を持つサービスプリンシパルが作成されました。

The properties of the new service principal

シークレットキーの復号化

今、ApplicationIDSecret、つまりサービスプリンシパルのユーザー名とパスワードを持っています。ただし、Secretの値はSystem.Security.SecureStringと表示されています。この秘密が何であるか知りたい場合は、次のコマンドを使用して秘密を平文に変換します。

# 暗号化されたパスワードを平文に変換する
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto(
    [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR(
        $sp.Secret
    )
)

上記のコマンドは、$sp.Secretのセキュア文字列の値を平文に変換します。参考までに、以下のイメージをご覧ください。

Secure string password value converted to plain text

Azureサービスプリンシパルのロール割り当ての確認

これが機能したかどうかをどのように確認しますか?Azureポータルを使用してリソースのアクセス制御リストを確認できます。たとえば、下の画像では、AzVM_ReaderサービスプリンシパルがReaderアクセス権をAzVM1仮想マシンに持っていることがわかります。

Azure resource access control

また、Get-AzRoleAssignment -ObjectID $sp.idコマンドを使用して、Azureサービスプリンシパルのロール割り当てを取得することもできます。以下はスクリーンショットの例です。

Get the role assignment(s) of the service principal

パスワードを使用したAzureサービスプリンシパルの作成

Azureサービスプリンシパルに割り当てられるパスワードまたはシークレットキーをより細かく制御したい場合は、サービスプリンシパルの作成時に-PasswordCredentialパラメータを使用します。これは、パスワードが複雑な要件を満たす必要がある場合に特に便利です。

この例では、新しいAzureサービスプリンシパルが次の値で作成されます:

表示名: ATA_RG_Contributor

スコープ: ATA (リソースグループ)

役割: 貢献者

パスワード: 20文字で6つの非英数字の文字を含む

資格の有効期限: 5年

対象スコープ(リソースグループ)のIDを取得

この新しいサービスプリンシパルのスコープは、ATAという名前のリソースグループ全体をカバーします。最初に取得するのは、ATAリソースグループのIDです。以下のコードを使用して、-Nameパラメータの値をリソースグループの名前に変更してください。

# リソースグループのResourceId値を取得
$Scope = (Get-AzResourceGroup -Name ATA).ResourceId
$Scope

次に、リソースグループのResourceID$Scope変数に格納されていることが表示されます。

Getting the Resource Group ID

パスワード文字列の生成

次のステップは、20文字で6つの非英数字の文字を含む複雑さに従うパスワードを生成することです。そのために、.NETの静的メソッドGeneratePassword()を利用することができます。

# GeneratePassword()静的メソッドを使用してランダムなパスワードを生成
Add-Type -AssemblyName 'System.Web'
$password = [System.Web.Security.Membership]::GeneratePassword(20, 6)
$password

上記のコードGeneratePassword(20, 6)では、最初の値はパスワードの長さを意味し、2番目の値は含まれる非英数字の文字数を意味します。結果は以下のスクリーンショットに表示されます。

Randomly generated password using the .NET GeneratePassword() static method

パスワード資格情報オブジェクトの作成

パスワード文字列を取得したら、次のステップはMicrosoft.Azure.Commands.ActiveDirectory.PSADPasswordCredentialオブジェクトを作成することです。このオブジェクトには、$password変数に格納されたパスワード文字列と有効期間が5年の情報が含まれます。以下のコードをコピーしてAzure PowerShellセッションで実行してください。

# パスワードクレデンシャルオブジェクトの作成
[Microsoft.Azure.Commands.ActiveDirectory.PSADPasswordCredential]`
    $PasswordCredential = @{
    StartDate = Get-Date;
    EndDate   = (Get-Date).AddYears(5);
    Password  = $password
}
$PasswordCredential

上記のコードをPowerShellで実行すると、クレデンシャルオブジェクトが$PasswordCredential変数に格納されます。期待される結果は以下の例と似ています。

Creating the new password credential object in Azure PowerShell

パスワードを使用してサービスプリンシパルを作成する

必要なパラメータの値を用意したので、Azureのサービスプリンシパルを作成しましょう。以下のコードは、表示名をATA_RG_Contributorとし、パスワードを$PasswordCredential変数に格納します。

# パスワードクレデンシャルを使用してサービスプリンシパルを作成
$sp = New-AzAdServicePrincipal `
    -DisplayName 'ATA_RG_Contributor' `
    -PasswordCredential $PasswordCredential
$sp

コードを実行すると、新しいサービスプリンシパルが作成され、プロパティが$sp変数に格納されます。以下は例の結果です。

The new Azure service principal is created

ロールとスコープの割り当て

前のセクションでAzureのサービスプリンシパルを作成しましたが、RoleScopeはありませんでした。これは-Role-Scopeパラメータを-PasswordCredentialパラメータと同時に使用できないためです。つまり、サービスプリンシパルにロールとスコープを割り当てるために追加の手順が必要です。

以下のコードでは、New-AzRoleAssignmentコマンドレットを使用して、Azureサービスプリンシパルのスコープと役割を割り当てます。

# ターゲットリソースに役割を割り当てる
New-AzRoleAssignment -$azSubscription = Get-AzSubscription -SubscriptionName VSE3
$Scope = "/subscriptions/$($azSubscription.ID)"
$TenantID = $azSubscription.TenantID$sp.ApplicationId `
    -Scope $Scope `
    -RoleDefinitionName 'Contributor'

以下のスクリーンショットは、役割とスコープがAzureサービスプリンシパルに割り当てられた後の期待される結果を示しています。

Assigning role and scope using Azure Powershell

サービスプリンシパルのパスワードを保存しておくことは常に重要です。保存できなかったり、忘れてしまった場合には回復する方法はありません。

サービスプリンシパルパスワードを使用してAzureに接続する

さて、サービスプリンシパルを使用します。ユーザーアカウントを使用してAzure PowerShellにログインする代わりに、以下のコードではサービスプリンシパルの資格情報を使用します。

# ATA_RG_Contributorという表示名のサービスプリンシパルを取得する
$sp = Get-AzADServicePrincipal -DisplayName ATA_RG_Contributor

# テナントIDを取得する
$TenantID = (Get-AzContext).Tenant.ID

# 最初のサービスプリンシパル名を取得する
$user = $sp.ServicePrincipalNames[0]

# パスワードをセキュアな文字列に変換する
$secPassword = $password | ConvertTo-SecureString -AsPlainText -Force

# PSCredentialオブジェクトを作成する
$credential = [PSCredential]::New($user,$secPassword)

# Azureに接続する
Connect-AzAccount -ServicePrincipal -Credential $credential -Tenant $TenantID
# ATA_RG_Contributorという表示名のサービスプリンシパルを取得する
$sp = Get-AzADServicePrincipal -DisplayName ATA_RG_Contributor

# テナントIDを取得する
$TenantID = (Get-AzContext).Tenant.ID

# 最初のサービスプリンシパル名を取得する
$user = $sp.ServicePrincipalNames[0]

# パスワードをセキュアな文字列に変換する
$secPassword = $password | ConvertTo-SecureString -AsPlainText -Force

# PSCredentialオブジェクトを作成する
$credential = [PSCredential]::New($user,$secPassword)

# Azureに接続する
Connect-AzAccount -ServicePrincipal -Credential $credential -Tenant $TenantID# ATA_RG_Contributorという表示名のサービスプリンシパルを取得する
$sp = Get-AzADServicePrincipal -DisplayName ATA_RG_Contributor

# テナントIDを取得する
$TenantID = (Get-AzContext).Tenant.ID

# 最初のサービスプリンシパル名を取得する
$user = $sp.ServicePrincipalNames[0]

# パスワードをセキュアな文字列に変換する
$secPassword = $password | ConvertTo-SecureString -AsPlainText -Force

# PSCredentialオブジェクトを作成する
$credential = [PSCredential]::New($user,$secPassword)

# Azureに接続する
Connect-AzAccount -ServicePrincipal -Credential $credential -Tenant $TenantID

上記のコードを実行した後、ATA_RG_Contributorサービスプリンシパルとパスワード認証情報を使用してAzure PowerShellにログインする必要があります。

Connect to Azure using a Service Principal with Password Credential

証明書を使用したAzureサービスプリンシパルの作成

パスワード認証情報以外にも、Azureサービスプリンシパルには証明書ベースの認証情報を持つこともあります。関連する証明書は、証明書機関によって発行されたものまたは自己署名のものである場合があります。

この例では、新しいAzureサービスプリンシパルは以下の値で作成されます:

表示名: VSE3_SUB_OWNER

スコープ: VSE3 (サブスクリプション)

ロール: 所有者

証明書の有効期間: 2年

ターゲットスコープ(サブスクリプション)のIDを取得する

この新しいサービスプリンシパルのスコープはVSE3という名前のAzureサブスクリプションをカバーします。最初に取得するのはVSE3サブスクリプションのIDです。以下のコードを使用して取得しますが、-SubscriptionNameパラメータの値をリソースグループ名に変更してください。

# サブスクリプションスコープとテナントIDの取得
$azSubscription = Get-AzSubscription -SubscriptionName VSE3
$Scope = "/subscriptions/$($azSubscription.ID)"
$TenantID = $azSubscription.TenantID

次に、作成する新しいAzureサービスプリンシパルと自己署名証明書の名前を指定します。

# 新しいAzureサービスプリンシパルと自己署名証明書の名前
$DisplayName = 'VSE3_SUB_OWNER'

自己署名証明書の作成

以下のコードは、名前がCN=VSE3_SUB_OWNERで個人証明書ストアにセルフサインされたパスワードを作成します。証明書の有効期間は2年に設定されています。証明書のプロパティは$cert変数に保存されます。

# セルフサイン証明書の生成
$cert = New-SelfSignedCertificate -CertStoreLocation "cert:\CurrentUser\My" `
    -Subject "CN=$($DisplayName)" `
    -KeySpec KeyExchange `
    -NotBefore ((Get-Date).AddDays(-1)) `
    -NotAfter ((Get-Date).AddYears(2))
$cert

以下のスクリーンショットは、証明書が作成されたことを示しています。

The self-signed certificate is created in the personal certificate store

もし新しい証明書をより馴染みのあるビュー(GUI)で見たい場合は、証明書コンソール(certmgr.mmc)で見つけることができます。以下の画像は、証明書を示しています。

Viewing the self-signed certificate

次は、セルフサイン証明書のBase64エンコードされた値を取得し、$keyValue変数に保存することです。

# セルフサイン証明書のBase64値を取得
$keyValue = [System.Convert]::ToBase64String($cert.GetRawCertData())

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

証明書が作成されたので、次のステップは、セルフサイン証明書を資格情報として使用するAzureサービスプリンシパルを作成することです。資格情報の有効期間は証明書の有効期間と一致します。

$sp = New-AzADServicePrincipal -DisplayName $DisplayName `
    -CertValue $keyValue `
    -EndDate $cert.NotAfter `
    -StartDate $cert.NotBefore
$sp

以下のコードを実行すると、以下の画像と同様の出力が得られます。

The new Azure service principal with a certificate is created

ロールとスコープの割り当て

Azureサービスプリンシパルは作成されましたが、まだロールスコープが割り当てられていません。サービスプリンシパルにロールとスコープを割り当てるためには、さらなる手順が必要です。

以下のコードは、New-AzRoleAssignmentコマンドレットを使用して、サービスプリンシパルのVSE3サブスクリプションに所有者ロールを割り当てます。

# ロールとスコープを割り当てる
New-AzRoleAssignment -ApplicationId $sp.ApplicationId `
    -Scope $Scope `
    -RoleDefinitionName 'Owner'

コードを実行すると、以下のスクリーンショットによって、ロールの割り当てが完了したことが確認されます。

The service principal’s owner role is added to the subscription

サービスプリンシパル証明書を使用してAzureに接続する

これで、証明書ベースの資格情報を使用してサービスプリンシパルが作成されました。これにより、パスワードを使用せずにAzureに接続することができます。代わりに、コンピュータに利用可能な証明書を認証方法として使用します。

この例では、サービスプリンシパルの表示名はVSE3_SUB_OWNERであり、証明書名はCN=VSE3_SUB_OWNERです。以下のコードでは、パーソナル証明書ストアから証明書のサムプリントを取得し、それをログイン資格情報として使用します。

# subjectがCN=VSE3_SUB_OWNERの証明書を取得する
$cert = Get-ChildItem Cert:\CurrentUser\My\ | Where-Object { $_.Subject -eq 'CN=VSE3_SUB_OWNER' }

# Azureに接続する
Connect-AzAccount -ServicePrincipal -CertificateThumbprint $cert.ThumbPrint -ApplicationID $sp.ApplicationID -Tenant $TenantID

以下のスクリーンショットは、上記のコードを使用して、Azure PowerShellへのログインが成功したことを示しています。ログインにはApplicationIDTenant、およびCertificate ThumbPrintのみが使用されました。

Connecting to Azure using a Service Principal and Certificate

結論

Azureサービスプリンシパルは、Azureリソースにアクセスする自動化タスクとツールの資格情報を作成する際に考慮する必要があるセキュリティプリンシパルです。適用するスコープとロールは、「ちょうど十分な」アクセス許可を与えるために選択できます。

この記事では、PowerShellを使用してAzure Service Principalsを作成する方法を学びました。Azure Service Principalsにはパスワード、シークレットキー、または証明書ベースの資格情報が付与されます。それぞれの資格情報の種類には利点と適用可能な使用シナリオがあります。

パスワードまたはシークレットキーの資格情報を持つサービスプリンシパルはより携帯性がありますが、資格情報は平文として共有されるため、セキュリティが低いと考えられています。一方、証明書ベースの資格情報はより安全なオプションですが、少し手間がかかります。

この記事で学んだ技術は、自動化にAzureサービスプリンシパルを使用するための基本的な内容に限定されています。資格情報の追加、削除、リセットなど、Azureサービスプリンシパルの設定方法は他にもたくさんあります。これらは進んで探索していくことができます。

お読みいただきありがとうございました!

追加の学習リソース

以下は、この記事と一緒に役立つと思われるリソースです。

Source:
https://adamtheautomator.com/azure-service-principal/