1
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

Organization

Azure NSGの疎通確認を一括で実行する

はじめに

AzureでNetwork Security Group(NSG)を作成したものの疎通確認を1個1個実施していくと膨大な時間と手間が掛かってしまいます。
なんとか一括で出来ないものかと悩んでいたところ、
Network WatcherのIPフローの確認でNSGのチェックが出来るということを思い出しました。
そしてポータルにあるのであればAzure PowerShellで実行出来るだろう。と思い、調べてスクリプト作ってみました。

参考:Network Watcher IPフローの確認画面

疎通確認用インプットデータ準備

編集が簡単に出来るようにインプットデータはエクセルを選択。
エクセルに必要なデータを入力出来る表を作成。

パラメータファイル

読込むエクセルのシート名や列などをパラメータ化し、jsonに記述するようにしました。
その他にサブスクリプションID等も一緒にパラメータ化。
シートは複数選択出来るようにしています。

パラメータ
{
    "Excel": {
        "InitialDirectory": "C:\\",
        "Sheet": [
            {
                "Name": "Main",
                "Column": {
                    "VMName": 2,
                    "ResourceGroup": 3,
                    "Direction": 4,
                    "Protocol": 5,
                    "LocalPort": 6,
                    "RemoteIPAddress": 7,
                    "RemotePort": 8,
                    "Max": 8
                },
                "Row": {
                    "Start": 4
                }
            }
        ]
    },
    "Azure": {
        "SubscriptionID": "",
        "NetworkWatcher": {
            "ResourceGroup": "NetworkWatcherRG",
            "Name": "NetworkWatcher_japaneast"
        }
    },
    "Output": {
        "Directory": "C:\\out"
    }
}

スクリプトの作成

PowerShell 7で作成しました。
エクセルを1行ずつ読み込んでIPフローの確認を実行します。
VMが停止していると実行できないため、停止している場合はスキップするようにしています。
他にはブランクの項目がある場合もスキップします。

AzureNSGCheck.ps1(疎通確認実行部分を抜粋)
    foreach ($eachRow in $($Row.Start)..($MaxRow)) {
        # ブランク項目存在チェック
        $blankCol = $ExcelRange[$eachRow, $Column.VMName]
        $blankCol = $blankCol -and $ExcelRange[$eachRow, $Column.ResourceGroup]
        $blankCol = $blankCol -and $ExcelRange[$eachRow, $Column.Direction]
        $blankCol = $blankCol -and $ExcelRange[$eachRow, $Column.Protocol]
        $blankCol = $blankCol -and $ExcelRange[$eachRow, $Column.LocalPort]
        $blankCol = $blankCol -and $ExcelRange[$eachRow, $Column.RemoteIPAddress]
        $blankCol = $blankCol -and $ExcelRange[$eachRow, $Column.RemotePort]

        if (!$blankCol) {
            $Log.Warn("空白の項目が存在するため、次の行にスキップします。")
            continue
        }

        # VM情報の取得
        if ($VirtualMachine.Name -ne $ExcelRange[$eachRow, $Column.VMName]) {
            $VirtualMachine = $null
            $VirtualMachine = Get-AzVM -ResourceGroupName $ExcelRange[$eachRow, $Column.ResourceGroup] -Name $ExcelRange[$eachRow, $Column.VMName]

            if (!$VirtualMachine) {
                $Log.warn("仮想マシン「$($ExcelRange[$eachRow, $Column.VMName])」の取得に失敗しました。")
                $resultCheck = $returnCode.Error
                continue
            }

            # VMステータス取得
            $VMStatus = ($VirtualMachine | Get-AzVM -Status).Statuses | where { $_.Code -match "PowerState" }
        }

        if ($VMStatus.Code -ne "PowerState/running") {
            $Log.Warn("仮想マシン「$($ExcelRange[$eachRow, $Column.VMName])」を起動してください。現在のステータスは「$($VMStatus.Code)」です。")
            $resultCheck = $returnCode.Error
            continue
        }

        # プライベートIPアドレス(NIC)情報の取得
        $NetworkInterface = $null
        $NetworkInterface = Get-AzNetworkInterface -ResourceGroupName $VirtualMachine.ResourceGroupName | where { $_.VirtualMachine.Id -eq $VirtualMachine.Id }
        $LocalIP = $NetworkInterface.IpConfigurations.PrivateIpAddress

        $Log.info("測定内容: 仮想マシン:$($VirtualMachine.Name) 方向:$($ExcelRange[$eachRow, $Column.Direction]) プロトコル:$($ExcelRange[$eachRow, $Column.Protocol]) ローカルIP:${LocalIP} ローカルポート:$($ExcelRange[$eachRow, $Column.LocalPort]) リモートIP:$($ExcelRange[$eachRow, $Column.RemoteIPAddress]) リモートポート:$($ExcelRange[$eachRow, $Column.RemotePort])")

        # ローカルIPとリモートIPの同一チェック
        if ($LocalIP -eq $ExcelRange[$eachRow, $Column.RemoteIPAddress]) {
            $Log.Warn("リモートIPがローカルIPと同一のため、次の行にスキップします。")
            $resultCheck = $returnCode.Error
            continue
        }

        # IPFlow実行
        $resultNWIPFlow = $null
        $resultNWIPFlow = Test-AzNetworkWatcherIPFlow -NetworkWatcher $NetworkWatcher -TargetVirtualMachineId $VirtualMachine.Id -Direction $ExcelRange[$eachRow, $Column.Direction] -Protocol $ExcelRange[$eachRow, $Column.Protocol] -LocalIPAddress $LocalIP -RemoteIPAddress $ExcelRange[$eachRow, $Column.RemoteIPAddress] -LocalPort $ExcelRange[$eachRow, $Column.LocalPort] -RemotePort $ExcelRange[$eachRow, $Column.RemotePort]

        if (!$resultNWIPFlow) {
            $Log.Error("NSGチェック処理に失敗しました。")
            $resultCheck = $returnCode.Error
            continue
        }

        $Log.Info("結果: アクセス:$($resultNWIPFlow.Access) ルール:$($resultNWIPFlow.RuleName)")
        $OutputNSGCheck += "$($resultNWIPFlow.Access),$($resultNWIPFlow.RuleName),$($VirtualMachine.Name),$($ExcelRange[$eachRow, $Column.Direction]),$($ExcelRange[$eachRow, $Column.Protocol]),$($LocalIP),$($ExcelRange[$eachRow, $Column.LocalPort]),$($ExcelRange[$eachRow, $Column.RemoteIPAddress]),$($ExcelRange[$eachRow, $Column.RemotePort])"

    }

スクリプトの実行

スクリプト実行前にAzureにPowerShellでログインします。

Login-AzAccount

ログイン後、スクリプトを実行します。

.\AzureNSGCheck.ps1 -ConfigFileName NSGCheckConfig.json

読込むエクセルファイルを選択するダイアログが表示されますのでファイルを選択します。

処理が実行され、結果がcsvファイルで出力されます。
内容は許可/拒否、対応したセキュリティルール名と実行した情報です。

実行結果
Access,Rule,VMName,Direction,Protocol,LocalIP,LocalPort,RemoteIP,RemotePort
Allow,defaultSecurityRules/AllowVnetInBound,sample-vm,Inbound,TCP,10.0.0.4,3389,10.0.1.4,3389
Deny,defaultSecurityRules/DenyAllInBound,sample-vm,Inbound,TCP,10.0.0.4,3389,10.10.0.5,3389
Allow,defaultSecurityRules/AllowVnetInBound,sample-vm,Inbound,TCP,10.0.0.4,22,10.0.1.4,22
Deny,defaultSecurityRules/DenyAllOutBound,sample-vm,Outbound,TCP,10.0.0.4,443,0.0.0.0,443

おわりに

これでAzureポータルからポチポチ実行しなくても良くなりました。
ただ、あくまでNSGのチェックになるのでスクリプトの実行結果がOKでもOS上で疎通確認すると結果が異なることがあります。
OS上のfirewall等で引っかかったり。
その辺りは不便ですが、NSG自体の設定に不備がないかの確認が出来るだけでも良しとします。
今回作成したスクリプトはGitHubに公開しています。(こちら

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
1
Help us understand the problem. What are the problem?