はじめに
AzureのIaaS環境を構成するにあたり、NSG(ネットワークセキュリティグループ)はまず間違いなく使用します。 何かしらのシステム基盤であればもちろんのこと、比較的自由に利用できる検証環境の場合でもNSGでのアクセス制御をしているでしょう。
自由に使わせる場合、よくわからずVMをデプロイしたらNSGを適用していたのに発信元IPアドレスがAnyで許可してた、ということもあると思います。(おまけ参照)
ただ、毎度チェックするわけにもいかないので、発信元IPアドレスがAnyのNSGルールをまとめて、表形式でメール通知するAutomationジョブを作成してみました。
2019年11月24日、AzureポリシーでNSGのルールを制限する方法を紹介しました。
目次
準備/設定
使用するスクリプト
今回作成したスクリプトの全体の流れは次のような構成です。
- 4列のテーブルオブジェクトを作成(NSG名、リソースグループ名、ルール名、宛先ポート)
- Automation実行アカウントにログイン
- サブスクリプション内のすべてのNSGおよびNSGルールを順に取得し、条件に合致するルールの情報をテーブルに追加
- テーブルオブジェクトを、メール送信するためのHTML形式に整形
- SendGridの認証情報を作成し、結果をメール送信(検出ルールが0の場合はメール送信しない)
スクリプト中のルール検出条件は、「ソースアドレスプレフィックスがAny」かつ「許可ルール」かつ「受信ルール」です。 中にはApplication Gatewayなど使用にポート許可が必要な場合もあるので特定のポートに限定することも考えましたが、 まずはシンプルに"疑わしいルール"を検出することにしました。
xxxの部分は環境に合わせて変更が必要です。
$MailToには、メール送信先のアドレスを配列形式で指定します。 $MailFromは差出人のアドレスですが、好きに指定してOKです。
Automation実行アカウントへのログインは、実行アカウントを作成する前提の記述のため、 実行アカウントを使わず別途資格情報を登録する場合には、記述の変更が必要です。
また、Azコマンドを使用しているため、後述のモジュールの追加が必要です。
# Create a Table
$Table = New-Object system.Data.DataTable "TestTable"
$Col1 = New-Object system.Data.DataColumn NSGName,([string])
$Col2 = New-Object system.Data.DataColumn ResourceGroupName,([string])
$Col3 = New-Object system.Data.DataColumn RuleName,([string])
$Col4 = New-Object system.Data.DataColumn DestPort,([string])
$Table.columns.add($col1)
$Table.columns.add($col2)
$Table.columns.add($col3)
$Table.columns.add($col4)
#Login Azure Automation
$connection = Get-AutomationConnection -Name "AzureRunAsConnection"
Connect-AzAccount -ServicePrincipal -Tenant $connection.TenantID -ApplicationId $connection.ApplicationID -CertificateThumbprint $connection.CertificateThumbprint | Out-Null
# Detect NSG Rules
Get-AzNetworkSecurityGroup | ForEach-Object{
$NSGName = $_.Name
$RGName = $_.ResourceGroupName
$AllSecrityRules = $_.SecurityRules
$AllSecrityRules | ForEach-Object{
$RuleName = $_.Name
$SourceAddressPrefix = $_.SourceAddressPrefix
$Access = $_.Access
$Direction = $_.Direction
$DestinationPort = $_.DestinationPortRange -join ","
if(($SourceAddressPrefix -eq "*") -and
($Access -eq "Allow") -and
($Direction -eq "Inbound"))
{
$row = $table.NewRow()
$Row.NSGName = $NSGName
$Row.ResourceGroupName = $RGName
$Row.RuleName = $RuleName
$Row.DestPort = $DestinationPort
$Table.Rows.Add($row)
}else{
#Nothing to do
}
}
}
if($Table.Rows.Count){
# Create HTML Table of Detected Rules
$Result = "<table border=`"1`"><tr><td>NSG Name</td><td>ResourceGroup Name</td><td>Rule Name</td><td>Destination Port</td></tr>"
foreach($Row in $Table.Rows){
$Result += "<tr><td>" + $Row[0] + "</td><td>" + $Row[1] + "</td><td>" + $Row[2] + "</td><td>" + $Row[3] + "</td></tr>"
}
$Result += "</table>"
# Create An Alert Mail
$SmtpServer = "smtp.sendgrid.net"
$Port = 587
$UserName = "azure_xxxxx@azure.com"
$Password = "xxxxx"
$MailFrom = "xxx@example.com"
$MailTo = @("xxx@xxx.com","xxx@xxx.com")
$Subject = "NSG Rule Alert"
$Body = "Here is List of NSG Rules using * as a SourceIPAddressRange.<br /><br />" + $Result
$pwd = ConvertTo-SecureString -String $Password -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential $UserName,$pwd
Send-MailMessage -UseSsl -From $MailFrom -To $MailTo -Subject $Subject -Body $Body -SmtpServer $SmtpServer -Port $Port -Credential $cred -BodyAsHtml
}
参考
スクリプトを作成するうえで、以下の記事/ページを参考にしています。
https://codeday.me/jp/qa/20190321/445515.htmlcodeday.me
SendGrid Accounts
SendGridとは、SendGrid社の提供するメール配信サービスです。 サーバ不要であり、無料枠で月25000通のメールを配信できるので、Azure 環境からメールを送信する場合はこれを使うと楽です。
プランと料金はこちら。
https://azuremarketplace.microsoft.com/ja-jp/marketplace/apps/SendGrid.SendGrid?tab=PlansAndPriceazuremarketplace.microsoft.com
今回はAutomationのジョブからSendGridへメールを投げるため使います。Freeプランで作成します。
作成時には認証用パスワードやプラン指定、サポートからの連絡先指定が必要です。パスワードは後で変更できます。

作成したSendGrid AccountsのConfigurationsに表示されている、以下の2つの情報をスクリプト中の変数に指定します。
- Usernameを$UserNameに格納
- Passwordを$Passwordに格納

Automationアカウント
Automationアカウントとは、Azureで提供されているプロセスの自動化サービスです。 PowerShell/Pythonに対応しており、登録したジョブのスケジュール実行や、Webhookを作成してHTTP Postを受けての実行が可能です。
ジョブの実行時間に応じて課金されますが、無料枠が月500分あり、ちょっとしたことであれば十分足りてしまいます。 ジョブ実行以外にも、更新プログラムの管理や構成管理機能があります。 2019年9月現在、西日本リージョンには作成できません。
料金はこちら azure.microsoft.com
今回はこれを用いてジョブ実行するので、Automationアカウントをデプロイします。
実行アカウントの作成を行うと新しいサービスプリンシパルが作成され、サブスクリプションの共同作成者ロールが割り当てられます。 作成しない場合は別途資格情報の登録が必要になるので、ここでは実行アカウントを作成します。

モジュールの追加
現在のAzure PowerShellではAzモジュールがメインですが、記事作成時点では、AutomationはデフォルトではAzureRmモジュールのみ対応しています。
そのため、Azコマンドを使用する際はモジュールの追加が必要になります。 本記事のスクリプトを動作させるためには、[Az.Accounts]と[Az.Network]の2つのモジュールが必要です。
モジュール追加を行うには、[モジュールギャラリー]を選択します。

Az.AccountsとAz.Networkの2つのモジュールを検索し、両方インポートします。
※パッケージの依存関係があるため順番に注意してください。今回の例ではAz.Accountsが先です。



モジュール画面に移動し、先ほど追加したモジュールが使用可能になればOKです。

Runbookの作成
アカウントを作成しモジュールを追加したら、続いてRunbookを作成します。
Runbookの種類をPowerShellにします。

[編集]をクリックします。

ここにコードを貼り付け、[公開]を行います。
※公開を実行しないと、変更が反映されません。

スケジュール登録
Runbookを作成したら、最後にジョブのスケジュール登録を行います。
Runbookのスケジュール画面を開きます。

新しいスケジュールの作成を行い、好きな日時、タイミングで実行するように設定します。画像のように指定すれば、平日の朝10時だけ実行することが可能です。

これで設定は完了です。
メール通知
実際にメールが届くと、以下のようになります。

これで、条件に合致した特定のNSGルールを検出し、表形式でメール通知することができました。
おまけ:VMデプロイ時の注意
今回こんなスクリプトを作成してみようと思ったきっかけにも関連するのですが、 ポータルで仮想マシンを作成する場合、以下の設定画面があります。

ここで受信ポートを選択すると、新規作成され、ネットワークインターフェースに紐づけられたNSGに自動で受信ルールを追加してくれるのですが、発信元IPアドレスがAnyで許可されます。
知らないと22/3389を公開してしまう可能性があるので、これは使用せず自分で許可ルールを追加することをお勧めします。
おわりに
今回は、特定のNSGルールを検出しメール通知する、というジョブをAutomationでスケジュール設定しました。 意外とあっさりでき、AutomationとSendGridだけでもいろいろなことができそうだとわかりました。 単なるスクリプトなので条件を変えれば何でも検出できますし、検出したあと自分のグローバルIPに置き換える、ということも可能です。
本当はFunctionとか使えればよかったのですが、知識が足らず。。。 NSGの作成/変更を検出してうんぬん、というのができればやってみたいなと思います。
クラウドで構築が簡単になり、ネットワークなどよくわからなくてもいろいろ作れてしまいますが、 その結果として実は無防備でした、となると重大な問題になるので、使うにあたりある程度の理解は必要です。 また、間違えても検出できる仕組み、そもそも間違えない仕組みは大事ですね。