🌟
Azure Firewallの開始・停止を自動化する
Azure Firewallは利用料金が結構かかるので、検証環境などでは夜間・休日は停止しておきたい。
というわけで、Azure Automationを使って開始・停止を自動化する。
※祝日や非営業日(年末年始とか)は対応してないです。
手順
- 前提
Azure FirewallやAutomation Accountは作成済み
Automation AccountにはManaged Idを割り当てておく
- Azure Firewallを開始・停止するPowershell Scriptを作成する
- Automation AccountのRunbookをスケジュール実行するBicep templateを作成する
- Automation AccountのRunbookを作成と設定
3-1. Powershell ScriptをAutomation AccountのRunbookとしてアップロードする
3-2. Bicep templateでRunbookのscheduleを登録する - RBACを設定する
Azure Firewallを開始・停止するPowershell Script
実装例: StartStopAzureFirewall.ps1
param(
[parameter(Mandatory = $true)]
[string] $resourceName,
[parameter(Mandatory = $true)]
[string] $resourceGroupName,
[parameter(Mandatory = $false)]
[string] $vnetResourceName,
[parameter(Mandatory = $false)]
[string] $pipResourceName,
[parameter(Mandatory = $true)]
[string] $action
)
filter timestamp { "[$(Get-Date -Format G)]: $_" }
Write-Output "Script started." | timestamp
$ErrorActionPreference = "Stop"
Disable-AzContextAutosave -Scope Process
Connect-AzAccount -Identity
if ($action -eq 'stop') {
$afw = Get-AzFirewall `
-Name $resourceName `
-ResourceGroupName $resourceGroupName
$afw.Deallocate()
Set-AzFirewall -AzureFirewall $afw
}
else {
$afw = Get-AzFirewall `
-Name $resourceName `
-ResourceGroupName $resourceGroupName
$vnet = Get-AzVirtualNetwork `
-Name $vnetResourceName `
-ResourceGroupName $resourceGroupName
$pip = Get-AzPublicIpAddress `
-Name $pipResourceName `
-ResourceGroupName $resourceGroupName
$afw.Allocate($vnet, $pip)
# $afw.IpConfigurations[0].Name = "ipconfig"
Set-AzFirewall -AzureFirewall $afw
}
Write-Output "Script finished." | timestamp
-
action
パラメータでFirewallを開始/停止を使い分ける - リソースにはManaged Idを使ってアクセス
- Firewallは開始にすると構成情報の一部がデフォルトに戻るので、必要に応じて作り込みが必要
- 例えば、Public IP構成の名前など
# $afw.IpConfigurations[0].Name = "ipconfig"
- 例えば、Public IP構成の名前など
- VNETとPublicIPは、Firewallと同じリソースグループにあるものとする
Automation AccountのRunbookをスケジュール実行するBicep template
Runbookのスケジュール登録
実装例: aa-schedule.bicep
param today string = utcNow('yyyy-MM-dd')
param aa_name string
param start_schedule_name string
param start_schedule_time string
param start_description string = 'start schedule'
param stop_schedule_name string
param stop_schedule_time string
param stop_description string = 'stop schedule'
var _start_schedule_time = dateTimeAdd('${today}T${start_schedule_time}', 'P1D')
var _stop_schedule_time = dateTimeAdd('${today}T${stop_schedule_time}', 'P1D')
// correction: 'Asia/Tokyo'
var _start_local_time = dateTimeAdd(_start_schedule_time, '-PT9H')
var _stop_local_time = dateTimeAdd(_stop_schedule_time, '-PT9H')
resource start_schedule 'Microsoft.Automation/automationAccounts/schedules@2022-08-08' = {
name: start_schedule_name
parent: automation
properties: {
description: start_description
startTime: _start_local_time
expiryTime: '9999-12-31T23:59:59.9999999+00:00'
frequency: 'Week'
interval: 1
advancedSchedule: {
weekDays: [
'Monday'
'Tuesday'
'Wednesday'
'Thursday'
'Friday'
]
}
timeZone: 'Asia/Tokyo'
}
}
resource stop_schedule 'Microsoft.Automation/automationAccounts/schedules@2022-08-08' = {
name: stop_schedule_name
parent: automation
properties: {
description: stop_description
startTime: _stop_local_time
expiryTime: '9999-12-31T23:59:59.9999999+00:00'
frequency: 'Day'
interval: 1
advancedSchedule: null
timeZone: 'Asia/Tokyo'
}
}
resource automation 'Microsoft.Automation/automationAccounts@2022-08-08' existing = {
name: aa_name
}
- スケジュールの日時設定を日本時間に合わせるように
var
の定義でゴニョゴニョやってます(良い方法が思いつかなかった - 開始のスケジュールは、月~金曜日を指定
- 停止のスケジュールは、毎日(休日出勤した人の停止忘れ防止用
RunBookのジョブスケジュール登録
実装例: aa-job-schedule.bicep
param now string
param aa_name string
param job_schedules array
@batchSize(1)
resource job_schedule 'Microsoft.Automation/automationAccounts/jobSchedules@2022-08-08' = [for job in job_schedules: {
name: guid(subscription().subscriptionId, aa_name, job.runbook_name, job.schedule_name, now)
parent: automation
properties: {
parameters: {
ResourceGroupName: job.target_rg_name
ResourceName: job.target_resource_name
VnetResourceName: job.target_vnet_name
PipResourceName: job.target_pip_name
Action: job.target_action
}
runbook: {
name: job.runbook_name
}
schedule: {
name: job.schedule_name
}
}
}]
resource automation 'Microsoft.Automation/automationAccounts@2022-08-08' existing = {
name: aa_name
}
- 特にコメントはなし
- 開始と停止の2つを登録するのでjob_scheduleでfor文を使用しているぐらい
- 開始と停止の2つを登録するのでjob_scheduleでfor文を使用しているぐらい
開始・停止スケジュール登録用
実装例: aa-fw-start-stop.bicep
param now string = utcNow('yyyyMMdd-HHmmss')
param aa_name string
param run_book_name string
param schedules_name string = 'afw-weekday'
param rg_name string = 'Firewallのリソースグループ名'
param fw_name string = 'Firewallのリソース名'
param vnet_name string = 'Firewallを配置するVNETのリソース名'
param pip_name string = 'Firewallに割り当てるPublicIPのリソース名'
var _start_schedule_name = 'start-schedule-${schedules_name}'
var _stop_schedule_name = 'stop-schedule-${schedules_name}'
var _start_schedule_time = '08:30:00'
var _stop_schedule_time = '18:00:00'
var _job_schedules = [
{
runbook_name: run_book_name
schedule_name: _start_schedule_name
target_rg_name: rg_name
target_resource_name: fw_name
target_vnet_name: vnet_name
target_pip_name: pip_name
target_action: 'start'
}
{
runbook_name: run_book_name
schedule_name: _stop_schedule_name
target_rg_name: rg_name
target_resource_name: fw_name
target_vnet_name: null
target_pip_name: null
target_action: 'stop'
}
]
module aa_schedule './aa-schedule.bicep' = {
name: 'aa-schedule'
params: {
aa_name: aa_name
start_schedule_name: _start_schedule_name
start_schedule_time: _start_schedule_time
stop_schedule_name: _stop_schedule_name
stop_schedule_time: _stop_schedule_time
}
scope: resourceGroup()
}
module aa_job_schedule './aa-job-schedule.bicep' = {
name: 'aa-job-schedule'
dependsOn: [ aa_schedule ]
params: {
now: now
aa_name: aa_name
job_schedules: _job_schedules
}
scope: resourceGroup()
}
- Automation Accountのリソース名とRunbook名はparam指定とした
- 開始・停止のPowershellをアップロードを外出ししているため
- その他のparam指定は、環境に応じて書き換える
- Azure Firewallの開始時間の指定
var _start_schedule_time = '08:30:00'
- Azure Firewallの停止時間の指定
var _stop_schedule_time = '18:00:00'
Automation AccountのRunbookの作成と設定
実装例
$aaResourceName = "Automation Accountのリソース名"
$aaResourceGroup = "Automation Accountのリソースグループ名"
$runBookName = "StartStop-AzureFirewall" # Runbook名
Import-AzAutomationRunbook `
-AutomationAccountName $aaResourceName `
-ResourceGroupName $aaResourceGroup `
-Name $runBookName `
-Path "./StartStopAzureFirewall.ps1" `
-Type PowerShell `
-Published `
-Force
$deployName = "deploy-aa-schedule-" + (Get-Date).ToString("yyyy-MM-dd-HHmmss")
New-AzResourceGroupDeployment `
-Name $deployName `
-ResourceGroupName $aaResourceGroup `
-TemplateFile "aa-fw-start-stop.bicep" `
-aa_name $aaResourceName `
-run_book_name $runBookName
- Import-AzAutomationRunbookを使って、Powershellをアップロード
- Runbookがなければ作成される
- 既存のRunbookがあれば、Powershell Scriptを上書きするようである
- New-AzResourceGroupDeploymentを使って、Runbookのスケジュール登録を行う
- Runbookのスケジュール登録は翌日からになっているはず・・・
RBACの設定
関連リソースのIAM設定でAutomation AccountのManaged Idに対してNetwork Contributor
を割り当てる
Firewall Policy
を使っている場合は、Firewall Policy
にもロールを割り当てる必要
以上、ここまで
Discussion