備忘録、のようなもの

頭を使うために書き始めることにしました。わりと何でも書くつもりです。

AzureのVMでスクリプトを定期実行させてみる

会社の人から毎月初めにログをアーカイブしておくのが大変、なんて話を聞いたのでちょっと遊んでみた話です。
なんかWindowsのセキュリティログをアーカイブしてディスクに丁寧に保存してるんだとか。
保持期限も設定されてないのでとりあえず内部のディスクに溜まり続ける宿命らしい。

最初はLog Analyticsで収集しておくかーって思ったけど、保管してあればいいだけで検索できる必要もないし、
そもそもセキュリティログは収集出来ないらしかった。
f:id:idx_ccd3:20190203173455j:plain

というわけで、zipにしてストレージアカウント放り込んでおこう、という安易な考えに至りました。
以下がその過程です。

まずはVM内でスクリプトを実行するにはいくつか方法があるらしい。
docs.microsoft.com

  • カスタム スクリプト拡張機能
    これはだいたいVM作成時に使うものので除外
  • 実行コマンド
    昨年あたりに使えるようになった、ポータルからも実行できるやつ。
    とりあえず手っ取り早そう
  • Hybrid Runbook Worker
    なんか使えそう。
  • シリアル コンソール
    ポータルからしか使えん

というわけでHybrid Runbook Workerが最適っぽいけど何故か実行コマンドを選びました。我ながら愚か。
そして実行コマンドをAutomationで定期実行しよう、と貧弱な発想に思い至ったのです。

AutomationからInvoke-AzVMRunCommandを叩くだけなので、まずはVM内で実行するスクリプトを書いてみた

param (
    [parameter(mandatory=$true)]
    [string]$workDir, # ログのあるディレクトリ
    [parameter(mandatory=$true)]
    [string]$msiId, #マネージドID
    [parameter(mandatory=$true)]
    [string]$storageAccount, #アップロード先のストレージアカウント
    [parameter(mandatory=$true)]
    [string]$container #アップロード先のコンテナ
)

$ErrorActionPreference = "Stop"

# Compressing Log
Set-Location $workDir
$beginDay =  (Get-Date -Day 1 -Hour 0 -Minute 0 -Second 0).AddMonths(-1)
$endDay =  (Get-Date -Day 1 -Hour 23 -Minute 59 -Second 59).AddDays(-1) 
$fileName = "Archive-Security-$($endDay.ToString("MM")).zip"
$sourcePath = (Get-ChildItem | Where-Object{($_.Name -like "Archive-*") -and ($_.LastWriteTime -ge $beginDay) -and ($_.LastWriteTime -le $endDay)}).FullName
$destPath = "$($workDir)\$($fileName)"

&C:\Tools\7z1806-extra\x64\7za a -tzip $destPath $sourcePath

# Upload Log
&C:\tools\azcopy\azcopy login --identity $msiId
&C:\tools\azcopy\azcopy cp $destPath "https://$($storageAccount).blob.core.windows.net/$($container)"

Remove-Item $sourcePath
Remove-Item $destPath

マネージドIDについてはこちら
docs.microsoft.com ストレージアカウントの情報とか、AzureADの資格情報とか直接書きたくないなあ、と思ったらちょっと便利そうな機能だったので使ってみた。
VMからならAzureへのログインが簡単にできる。うちのVMはローカルアカウントの管理がザルなので、その気になれば悪用できるけどその部分は先輩に考えてもらうことにします。

上記のスクリプトをストレージアカウントに保存して、大切な情報も載せてないのでパブリック公開しました。(手抜き)
そしてそれをAutomationで実行しようとした結果がこちらのRunbook。

param(
    [parameter(Mandatory=$true)]
    [String] $rgname,
    [parameter(Mandatory=$true)]
    [String] $vmname,
    [parameter(Mandatory=$true)]
    [string]$workDir,
    [parameter(Mandatory=$true)]
    [string]$msiId,
    [parameter(Mandatory=$true)]
    [string]$storageAccount,
    [parameter(Mandatory=$true)]
    [string]$container"
)

$connection = Get-AutomationConnection -Name "AzureRunAsConnection"
Write-Output $connection
Login-AzAccount -ServicePrincipal -Tenant $connection.TenantID -ApplicationId $connection.ApplicationID -CertificateThumbprint $connection.CertificateThumbprint

$script= 'Archive-AuditLog.ps1'
Invoke-WebRequest -Uri "https://$($storageAccount).blob.core.windows.net/scripts/$script" -OutFile $script 
Invoke-AzureRmVMRunCommand  -ResourceGroupName $rgname `
                            -Name $vmname `
                            -CommandId 'RunPowerShellScript' `
                            -ScriptPath $script `
                            -Parameter @{"workDir" = "$($workDir)"; "msiId" = "$($msiId)"; "storageAccount" = "$($storageAccount)"; "container" = "$($container)"}

rgnameとvmnameは実行対象のVMの指定です。 他はVM内で実行するスクリプトに渡す情報です。
最後にAutomationのスケジュール登録して終わり。すごい手抜きでごめんなさい。

また時間を見つけてHybrid Runbook Workerで書き直してみようと思いますのでしばらくお待ちください。