LoginSignup
13
9

More than 5 years have passed since last update.

【20180519 改】AccessToken を使用して Login-AzureRMAccount / Add-AzureRMAccount を実行する

Last updated at Posted at 2017-09-12

Introduction


※ 20180519 以前書いた方法が仕様変更によってできなくなっているという報告がありましたので修正しました

PowerShell を使用して Azure サブスクリプションにログインする場合、通常はユーザーIDとパスワードを使用します。

Login-AzureRMAccount 

パラメタを何も指定しない場合、ログインダイアログボックスが表示され、手動でユーザーIDとパスワードを入力します。

-Credential パラメタを使用すればダイアログボックスの表示を省略することも可能です。

$UserID = "userid@company.com"
$UserPass = ConvertTo-SecureString "password" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PsCredential $UserID,$UserPass
Login-AzureRmAccount -Credential $cred

ただ、この方法では多要素認証(MFA, Multi Factor Authentication) に対応できません。ユーザーIDに多要素認証が設定されている場合、以下のようなエラーが出力されます。

Login-AzureRmAccount : AADSTS50079: The user is required to use multi-factor authentication.
Trace ID: 7c047e1d-4da8-4c7a-8e0e-b7bdcf1a2200
Correlation ID: 8732b1bc-4247-4e7f-876d-9a1ee75e18d5
Timestamp: 2017-08-31 15:55:25Z: リモート サーバーがエラーを返しました: (400) 要求が不適切です
発生場所 行:4 文字:1
+ Login-AzureRmAccount -Credential $cred
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : CloseError: (:) [Add-AzureRmAccount]、AadAuthenticationFailedException
    + FullyQualifiedErrorId : Microsoft.Azure.Commands.Profile.AddAzureRMAccountCommand

Get-AzureRmVM : Run Login-AzureRmAccount to login.
発生場所 行:5 文字:1
+ Get-AzureRmVM
+ ~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Get-AzureRmVM]、PSInvalidOperationException
    + FullyQualifiedErrorId : InvalidOperation,Microsoft.Azure.Commands.Compute.GetAzureVMC

この課題を解決する方法はいくつかありますが、ここでは -AccessToken を使用する方法を紹介します。

-AccessToken パラメタには”アクセストークン”と呼ばれるチケット的なものを指定します。このチケットは誰が発行してくれるのかといえば Azure AD です。Azure AD にチケットを発行してもらうには、発行先(つまりチケットを使う人)を明確にしておかなければなりません。発行されたチケットを他人が使用することはできないのです。

発行先を明確にするためには、”サービスプリンシパル”を登録する必要があります。

サービスプリンシパルとはなんぞや

サービスプリンシパルとは”サービスの識別子”です。と書いてもちょっとわかりずらいんですよね。なので、ここはぶっちゃけましょう。”サービス(プログラム)”を”ユーザーの一人”だと考えましょう。今回は PowerShell がサービスに相当するので、PowerShell を一人のユーザーだと考えます。こんなこと書くとその筋の識者に怒られますがww

そう、”PowerShellちゃん” です。みんな大好き、擬人化です。せっかくなので萌え絵でも描いておきますか。

”PowerShellちゃん”は、Azureサブスクリプションにログインして、Azure のリソースに触りたいんです。VM を作ったりとか、WEBアプリを再起動したりとか。

でも、”PowerShellちゃん”自身にはそんな権限はありません。そもそも Azure にログインすることができません。

なので、普段は管理者の人にログインしてもらって、その権限を借りて操作していました。

管理者が不在のときは、パスワードを事前に教えてもらっておき、-Credential パラメタを使用して好き勝手出来ました。

そこに「ちょっとまった!」をかけたのがAzure AD の"多要素認証"です。

Azure AD は Azure の番人です。いままでは、管理者の認証によって発行された”権限”を、PowerShell が流用することを許可していました。が、管理者に多要素認証が必要になると、権限の流用が不可能になってしまったのです。

”PowerShellちゃん” は困りました。毎回毎回、真夜中のタスクを実行するために管理者のスマートフォンに電話をして PIN を入力してもらうなんてことは不可能だからです。

そこで、”PowerShell ちゃん”を Azure の利用者として登録し、きちんとAzureのリソースにアクセスできる権限を与えてあげることにしましょう。

PowerShell を Azure AD に登録する(サービスプリンシパルを作成する)

まずは、Azure AD に PowerShell を登録します。

といっても、Azure AD は登録されたサービスが WEBアプリなのか PowerShell なのかについては意識していません。Azure AD にサービスを登録して”サービスプリンシパル(ユーザー ID みたいなもの)”が作成されると、Application ID と Key が発行されます。これらが、UserID と Password に相当します。PowerShell スクリプトの中で Application ID と Key を使用することで Azure にログインできるようになるのです。

多要素認証はサービスプリンシパルには適用されないので、UserID と Password のようにエラーが返されることはありません。

サービスプリンシパルを作成するための手順を以下に示します。

  1. Azure ポータルを開く
  2. "Azure Active Directory"を開く
  3. "App Registration" を開く
  4. "New Application Registration" をクリック
  5. サービスプリンシパルに必要な情報を入力

    サービスの名前は好きなものを指定してください。このサービスプリンシパルを使用するアプリケーションの名前を指定するのがよいでしょう。
    アプリケーションのタイプは”Native”を指定してください。PowerShellもネイティブアプリの一種です。
    リダイレクトURI ですが、ここを説明しはじめると OAuth 2.0 について説明しなけれならなず時間がかかるので、ここでは ”ネイティブアプリの識別子” だと考えてください。ひとまず、以下の形式で指定しておいてください。 このURIも後で使用するので控えておきましょう。
    https://< Name >


    詳しく知りたい方は、以下を起点として理解を深めましょう。

    Redirect URLs for Native Apps
    https://www.oauth.com/oauth2-servers/redirect-uris/redirect-uris-native-apps/
    OAuth 2.0の代表的な利用パターンを仕様から理解しよう
    www.buildinsider.net/enterprise/openid/oauth20
    「OAuth 2.0」の基本動作を知る
    http://www.atmarkit.co.jp/ait/articles/1708/31/news124.html

  6. "Create" をクリック

  7. 今登録したサービスプリンシパルが存在するか、念のために検索してみましょう。

  8. 検索結果に表示されたサービスをクリックして開き "Application ID" を控えておいてください。これが UserID の代わりになります。



    9. 次に、"Keys" をクリック
    ※Native ClientではKeyが取得できなくなりました。よって、この手順は不要です。なぜこのようなことになったのかと言えば、そもそも Native Client で Client ID と Secret の組み合わせでログインできてしまうのがおかしかったのですね。じゃ、代わりに何を使うかと言えば、ここでは Redirect URI を使用しています。正直これが完全にセキュアかと言えば、当然、全然そんなことは無いです。いずれにしてもスクリプトに特定の文字列をうめこまなければならないという方法そのものが脆弱であると言えます。誰でもスクリプトをコピペできてしまうわけですからね。本当に安全な方法をとるのであれば、Azure Automationや Azure Function という Azure 上のスクリプト実行環境を使用してください。これは完全に Azure AD の管理下にあり、スクリプトの作成から実行まで、全てのプロセスがAzure ADの認可のもとにあります。

  9. "Description" にキーの名前を適当に指定し、"EXPIRES"からキーの有効期限を選択します。キーは言うまでもなくパスワードに相当します。この時点ではキーそのものは表示されません。

  10. "Save" をクリックすると "VALUE" にキーが表示されるので、これをコピーしてどこかに控えておいてください。

※以下の手順を追加しました 20180519
11. 「Required Permission」をクリックし、このアプリケーションからアクセスするAPIとして「Windows Azure Management API」を追加します。

以上でサービスプリンシパルの作成が完了しました。そして、サービスプリンシパルを特定するための情報として、Application ID と Key が発行されました。

これで終わりかといえばそうではありません。サービスプリンシパルは、発行されただけでは Azure に対して何の権限も持っていません。これを有効活用するためには、PowerShell が使うであろう権限を割り当てなければならないのです。

サービスプリンシパルに権限を割り当てる

Azure AD にユーザーを作成する場合は、その過程で”ロール”を割り当てることができます。ロールとはその名の通り”役割”のことです。役割には事前に”権限”が割り当てられています。

ユーザーに直接権限を割り当てるのではなく、[ユーザー]-[ロール]-[権限] のように、ロールを介して権限を割り当てる手法を RBAC(Role-Based Access Control)と言います。

ロールを介することで、ユーザーと権限を直結させる必要がなくなります。この方式の何が素敵かと言えば、「ユーザーが認証されてロールが決定される」というプロセスと、「リソースにアクセスする際にロールを見て権限を判定する」というプロセスを完全に分離することができるのです。

つまり、認証基盤側でロールさえ変えてしまえば、リソース側の権限が自動的に変わる。。。ということです。これを「認証と認可の分離」などと言ったりしますが、これを説明しはじめると休憩込みで3日ほどかかるので、ここは割愛。

以下の手順で、サービスプリンシパルにロールを割り当てましょう。

  1. Azure Portal を開く
  2. "サブスクリプション(Subscription)" を開く

  3. サブスクリプションを選択

  4. "Access Control(IAM)" を選択

  5. "追加(Add)"

  6. PowerShell が必要とするロール(Role)を選択

  7. そのロールを使用するサービスプリンシパルを選択

  8. "Save"

ここは考慮のしどころです。ロールの選択によっては必要以上の権限を与えてしまうことになるので、本当にPowerShellが欲している権限を与えるようにしましょう。

Azure ロールベースのアクセス制御の組み込みロール
https://docs.microsoft.com/ja-jp/azure/active-directory/role-based-access-built-in-roles
Azure のロールベースのアクセス制御のためのカスタム ロールを作成する
https://docs.microsoft.com/ja-jp/azure/active-directory/role-based-access-control-custom-roles

以上でAzure上のリソースに対してロールを割り当てることができました。

Tenant ID と Subscription ID を控える

サービスプリンシパルを作成したAzure ADと、割り当てたサブスクリプションを正確に識別するために、スクリプトの中では Tenant ID と Subscription ID を明示する必要があります。そのため、以下からそれぞれの情報を控えておきましょう。

  1. Tenant ID(Directory ID)

  2. Subscription ID

スクリプトを作成する

ここまでに取得した情報を使用して、以下のようなスクリプトを作成しましょう。
これで、パスワードを使用することなく、MFAに邪魔されることなく、スクリプトを実行することができます。

※現在は以下のスクリプトは動作しません 20180519

$ClientId = "09f50028-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$ClientSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx="
$SubscriptionId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$TenantId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

$ClientCredential = new-object "Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential" $ClientId,$ClientSecret

$authority = "https://login.windows.net/" + $TenantId
$Resource = "https://management.azure.com/"
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" $authority,$false
$authResult = $authContext.AcquireToken($Resource, $ClientCredential)

Login-AzureRmAccount -AccessToken $authResult.AccessToken -AccountId $AuthClientId -SubscriptionId $SubscriptionId

※以下のスクリプトに修正しました 20180519

$ClientId = "xxxxxxxx-xxxx-xxxx-xxxx-fe7037d73d68"
$redirectUri = "https://Login-AzureRMAccount"
$SubscriptionId = "xxxxxxxx-xxxx-xxxx-xxxx-bd98aef0acbe"
$TenantId = "xxxxxxxx-xxxx-xxxx-xxxx-c2df404a71ee"

$authority = "https://login.windows.net/" + $TenantId
$resourceId = "https://management.azure.com/"

$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" $authority,$false
$authResult = $authContext.AcquireToken($resourceId, $ClientId, $redirectUri) 

Login-AzureRmAccount -AccessToken $authResult.AccessToken  -AccountId $ClientId -SubscriptionId $SubscriptionId

ここで疑問がでますよねこの方法って安全なの???

それについては、別の投稿で解説することにします。

13
9
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
9