今回は Azure Automation を使って Azure Bastion の自動作成および削除を行えるようにしてみます。Azure Bastion は Azure AD と連携してセキュアに仮想マシンへのリモート接続 (SSH, RDP) ができるソリューションです。
はじめに
Azure Bastion って何がいいの
従来だと踏み台サーバーとして接続用の VM を用意しておくのがセオリーでしたが、昨今はクラウドにシステムを構築する関係上インターネットからの接続のためにポートを開いておく必要がある状態ではリスクが付きまといます。かといって細かく接続元の IP アドレスを指定するのも管理の負荷が増えてしまいます。
そのため Azure であれば、Azure AD と連携して認証を行い、ブラウザベースでリモート接続できる Azure Bastion を利用するのが望ましいです。他のクラウドサービスでも似たような接続機能が用意されています。

具体的には Azure Bastion がプロキシーのような役割をして、仮想ネットワーク内の VM への接続を中継してくれます。接続したい VM にパブリック IP アドレスを付ける必要はありません。
Azure Bastion | Microsoft Docs
でもお高いんでしょう?
そう、Azure Bastion は中々いいお値段をしています。通常の SKU で \21.28/h なので、大体月額だと 15534.4 円になります。Standard は現段階だと \32.48 なので月額 23710.4 円くらいでしょうか。プレビュー価格だった場合は半額になっているのでもしかしたら倍の 47420.8 円くらいかもしれません。
価格 – Azure Bastion | Microsoft Azure
セキュリティには役立ちますが、常時起動させておく必要がない環境では節約のために電源を落とせる VM でいいや〜となってしまうかもしれません。
なので、今回は Azure Automation を使って簡単に Azure Bastion をデプロイできるようにして、使いたい時だけ Azure Bastion を利用できるようにしてみたいと思います。こうすると例えば平日日中9時から18時の間だけ稼働させれば月額3800円くらいになります。(9 hours * 5 days * 4 weeks = 180 hours として試算)
構築手順
事前準備
- Azure Automation アカウントを作成しておく
- 仮想ネットワークを作成しておく
- 仮想ネットワークに Azure Bastion 用のサブネットを作成しておく
Azure Bastion 用のサブネットは名称と必要なアドレス範囲の大きさが決まっているのでご注意ください。
項目 | 設定値 |
サブネット名 | AzureBastionSubnet |
サブネット範囲の大きさ | /27 以上 |

1. Automation モジュールのインポート
Automation アカウントで PowerShell コマンドを実行できるよう、必要なモジュールをインポートします。Az モジュールを一発インストールしたいところですが、依存関係を細かく解かないといけないため必要最低限で進めます。
Automation アカウントのメニューから [モジュール ギャラリー] をクリックします。検索バーに「Az.Accounts」と入力し、検索結果の一覧に表示された [Az.Accounts]をクリックします。

[Az.Accounts] にて、[インポート] をクリックします。

少し時間がかかるので待機し、モジュールがインポートされたことを確認します。

同様の手順で「Az.Network」モジュールもインポートします。

2. Automation 変数の準備
PowerShell スクリプト内で利用するための変数を準備しておきます。
Automation アカウントのメニューから [変数]をクリックし、上部の [変数の追加] をクリックします。

[新しい変数]にて、次のように変数を作成します。値は実際の環境に合わせて設定してください。

名前 | 説明 | タイプ |
AZBAS_Bastion_Name | Bastion のリソース名 | 文字列 |
AZBAS_PIP_NAME | Bastion のパブリック IP アドレス名 | 文字列 |
AZBAS_ResourceGroup_Name | Bastion を配置する仮想ネットワークのリソースグループ名 | 文字列 |
AZBAS_Vnet_Name | Bastion を展開する仮想ネットワーク名 | 文字列 |
次のように設定できていれば OK です。

3. 作成ランブックの作成
Azure Bastion を作成するランブックを作成していきます。
Automation アカウントのメニューから [Runbook] をクリックし、上部の [Runbook の作成] をクリックします。

[Runbook の作成] にて、次のように入力して [作成] をクリックします。
- [名前]: Create-AzBastion
- [Runbook の種類]: [PowerShell]
- [説明]: Bastion を作成する Runbook

作成したら上部の [編集] をクリックし、エディターに次のコードをペーストします。
## Initiate connection $conn = Get-AutomationConnection -Name 'AzureRunAsConnection' Write-Output 'Connecting to Azure...' Connect-AzAccount ` -ServicePrincipal ` -Tenant $conn.TenantID ` -ApplicationId $conn.ApplicationID ` -CertificateThumbprint $conn.CertificateThumbprint Write-Output 'Connect succeeded!' ## Define variables $rgName = Get-AutomationVariable -Name 'AZBAS_ResourceGroup_Name' $basName = Get-AutomationVariable -Name 'AZBAS_Bastion_Name' $vnetName = Get-AutomationVariable -Name 'AZBAS_Vnet_Name' $pipName = Get-AutomationVariable -Name 'AZBAS_PIP_Name' ## Create Azure Bastion $existBas = Get-AzBastion -ResourceGroupName $rgName if($existBas.Length -eq 0){ Write-Output "Getting specified Azure Virtual Netwok..." $vnet = Get-AzVirtualNetwork -ResourceGroupName $rgName -Name $vnetName Write-Output "Creating Azure Public IP Address..." $pip = New-AzPublicIpAddress -Name $pipName -ResourceGroupName $rgName -AllocationMethod Static -Sku Standard -Location japaneast Write-Output "Created Azure Public IP Address." Write-Output "Creating Azure Bastion..." $bastion = New-AzBastion -ResourceGroupName $rgName -Name $basName -VirtualNetwork $vnet -PublicIPAddress $pip Write-Output "Created Azure Bastion." }else{ Write-Output "Azure Bastion is already exist." }
ペーストしたら上部の [公開] をクリックします。
4. 削除ランブックの作成
先程と同様に [Runbook の作成] にて、次のように入力して [作成] をクリックします。
- [名前]: Delete-AzBastion
- [Runbook の種類]: [PowerShell]
- [説明]: Bastion を削除する Runbook
エディターに次の内容をペーストして公開します。
## Initiate connection $conn = Get-AutomationConnection -Name 'AzureRunAsConnection' Write-Output 'Connecting to Azure...' Connect-AzAccount ` -ServicePrincipal ` -Tenant $conn.TenantID ` -ApplicationId $conn.ApplicationID ` -CertificateThumbprint $conn.CertificateThumbprint Write-Output 'Connect succeeded!' ## Define variables $rgName = Get-AutomationVariable -Name 'AZBAS_ResourceGroup_Name' $basName = Get-AutomationVariable -Name 'AZBAS_Bastion_Name' $vnetName = Get-AutomationVariable -Name 'AZBAS_Vnet_Name' $pipName = Get-AutomationVariable -Name 'AZBAS_PIP_Name' ## Create Azure Bastion $existBas = Get-AzBastion -ResourceGroupName $rgName if($existBas.Length -ne 0){ Write-Output "Deleting Azure Bastion..." Remove-AzBastion -ResourceGroupName $rgName -Name $basName -Force Write-Output "Deleted Azure Bastion." Write-Output "Deleting Azure Public IP Address..." Remove-AzPublicIpAddress -Name $pipName -ResourceGroupName $rgName -Force Write-Output "Deleted Azure Public IP Address." }else{ Write-Output "Azure Bastion is not exist." }
5. 動作確認
Runbook の作成が完了したら、Create-AzBastion → Delete-AzBastion の順で実行して動作に問題がないか確認します。実行は Runbook 画面上部の [開始] をクリックします。これで好きなタイミングで実行できます。細かいエラー処理は省いているので、失敗時は実行画面のエラータブなどから確認してください。
成功時は出力タブに次のような内容が表示されます。


おまけ: スケジューリング
作成した Runbook を定期実行できるようにスケジューリングできます。
Automation アカウントのメニューから [スケジュール] をクリックし、[スケジュールの追加] をクリックします。[間隔] で [週] を選ぶと実行する曜日などで指定できます。

設定したらスケジュールを作成します。
Runbook を表示し、上部の [スケジュールへのリンク]をクリックし、[スケジュール] で作成済みのスケジュールを選択して [OK] をクリックします。あとは指定した時間に Runbook が実行されます。
コメント