Azure 仮想マシンをHTTPトリガーで起動/停止/サイズ変更などする

表題のような要件が生まれたのでやってみます。

前準備

Azure Powershellに自動ログインできないと始まりません。

以前、こんな記事を書いたのですが…

Azure上に作成した仮想マシンを作業時だけサイズ変更して快適に利用する(その他仮想マシン作成後のメモ) - 今日も元気にIT屋さん

セキュリティ上の理由でこの方法が使えなくなったので別の方法でやります。

Azure PowerShell スクリプトにて認証画面を出さずログインし、実行したい (2018/1/29 更新) ? Japan Azure Technical Support Engineers' Blog

1. Azure Active Directory に、空のアプリケーションを作成し、アプリケーションの ID とパスワードを作成する

手順の通りに実行します。アプリケーションを作成し…シークレットキーを生成。

f:id:teraco:20180424175225j:plain f:id:teraco:20180424175231j:plain

会社アカウントの場合、システム管理者が一般ユーザーがAzureポータルにログインできないよう、制御している可能性があります。その際はあきらめましょう。

2. 入手したアプリケーション ID とパスワードを認証情報にする

Azure にサービス プリンシパル名を登録します。という手順で躓きました。ブログの記載では

New-AzureRmRoleAssignment -ServicePrincipalName http://myTestApp -RoleDefinitionName Contributor

とありますが、"The provided information does not map to an AD object id."というエラーになる。いろいろ調べたところ、時間が解決するという書き込みもありましたが、以下のように直接アプリケーションIDを指定する事で登録が出来ました。

New-AzureRmRoleAssignment -ServicePrincipalName [アプリケーションID] -RoleDefinitionName Contributor

参考にした記事:Use PowerShell to create a Service Principal in your AAD

3. Azure PowerShell からログイン

後は元記事の手順通りにログインが出来ます。

$secpasswd = ConvertTo-SecureString "[シークレットキー]" -AsPlainText -Force
$AppID = "[アプリケーションID]"
$TenantID = "[テナントID]"
$mycreds = New-Object System.Management.Automation.PSCredential ("$AppID", $secpasswd)
Login-AzureRmAccount -ServicePrincipal -Tenant $TenantID -Credential $mycreds[f:id:teraco:20180424175225j:plain]

HTTPトリガーから起動/停止/サイズ変更など

1. Azure Functionへの登録

上記PowerShellをAzure Functionに登録し、HTTPトリガーで動くようにします。

f:id:teraco:20180424175634j:plain f:id:teraco:20180424175638j:plain

HTTPトリガーは以下のようなURLにアクセスすることで動作させることが可能です。

https://[アプリケーション名].azurewebsites.net/api/[関数名]?code=[functionキー]

HTTPトリガーの種類を"匿名"にすればcode=~の部分は不要です。が、セキュリティを高めるために、規定値で使用するのがいいでしょう。functionキーの表示兵法は、関数レベルの管理メニューからホスト キー(すべての関数) -> defaultを表示すればOK。

f:id:teraco:20180424180804j:plain

2. 引数受けの準備

指定したサーバーに対して、起動/停止のアクションを実施したいため、サーバー名とアクション内容を指定できるようにします。HTTPトリガーにGetで引数を投げた場合、以下の変数で受けることができます。

$req_query_[引数名]

今回は、サーバー名 = server、アクション内容 = modeで受けるため、以下のようなURLでGetリクエストを投げ…

https://[アプリケーション名].azurewebsites.net/api/[関数名]?code=[functionキー]&server=[サーバー名]&mode=[開始]

スクリプト中では以下のようなコードで受けます。

$mode = $req_query_mode
if($mode -eq $Null) {
    "Please set mode Param(stop/start)"
    exit
}
$Server = $req_query_server
if($Server -eq $Null) {
    "Please set Server Param"
    exit
}

3. PowerShellの登録

サーバーを起動/停止するpowershellコードを書きます。

$RGName = [リソースグループ名]
if($mode -eq "start") {
  Start-AzureRmVM -ResourceGroupName $RGName -Name $server

} elseif($mode -eq "stop") {
  Stop-AzureRmVM -ResourceGroupName $RGName -Name $server -Force
}

前準備を行う事でAzure PowerShell への自動ログインが可能となったので、自動ログイン後、仮想マシンに対してアクションを行うPowerShell スクリプトを作成します。ここでは仮想マシンの起動を行うようにします。

4. 資格情報の隠ぺい

これだとスクリプトの中に資格情報が記載されたままで怖いので、上記参照記事の通り、Functionの機能を用いて隠ぺいします。

Connect an Azure Function to Office 365 - GCITS

文字列を暗号化すると…

f:id:teraco:20180424180249j:plain

ファイルが生成される。

f:id:teraco:20180424180311j:plain

PassEnctyptKey.key をアップロードし。

f:id:teraco:20180424180404j:plain

EncryptedPassword.txt 中の文字列を環境変数に設定。

f:id:teraco:20180424180611j:plain

隠ぺい前はこちら。

$secpasswd = ConvertTo-SecureString "[シークレットキー]" -AsPlainText -Force
$AppID = "[アプリケーションID]"
$TenantID = "[テナントID]"

隠ぺい後はこちら。

$FunctionName = [関数名]
$keypath = "D:\home\site\wwwroot\$FunctionName\bin\keys\PassEncryptKey.key"
$secpasswd = $Env:SecretKey | ConvertTo-SecureString -Key (Get-Content $keypath)
$AppID = $Env:AppID
$TenantID = $Env:TenantID