Azure ネットワークセキュリティグループの作成

スポンサーリンク

Azureのネットワークの基本概念である「仮想ネットワーク」と「サブネット」の考え方についてまとめます。Azureでは「仮想ネットワーク」の中に複数の「サブネット」を設ける事ができます。同一の「仮想ネットワーク」に属する「サブネット」同士は互いにルーティングできる状態になっています。

前提

公式ドキュメント

参考になる公式ドキュメントを以下に示します。

事前設定

以下、リソースグループを作成します。

az group create --name MyResourceGroup --location japaneast

仮想ネットワーク内にサブネットを2つ作成します。

az network vnet create \
  --resource-group MyResourceGroup \
  --name Vnet01 \
  --address-prefix 172.16.0.0/16

az network vnet subnet create \
  --resource-group MyResourceGroup \
  --name SubnetWeb \
  --vnet-name Vnet01 \
  --address-prefixes 172.16.1.0/24

az network vnet subnet create \
  --resource-group MyResourceGroup \
  --name SubnetDb \
  --vnet-name Vnet01 \
  --address-prefixes 172.16.2.0/24

セキュリティグループ

Webサーバのセキュリティグループ実装例

セキュリティグループの作成

以下のコマンドでセキュリティグループを作成します。

az network nsg create \
  --resource-group MyResourceGroup \
  --name NsgWeb

ssh(tcp22)とhttp(tcp80)を許可します。ssh(tcp22)は特定の拠点からの接続のみを許可するように送信元IPアドレスで絞り込みます。送信元IPアドレスは環境に応じて適宜の変更をお願いします。

引数priorityは評価順です。数値の小さいものが優先されます。他のファイアウォール製品ではsequence numberと呼称される事の方が多いでしょう。

az network nsg rule create \
  --resource-group MyResourceGroup \
  --nsg-name NsgWeb \
  --name tcp22 \
  --priority 100 \
  --destination-port-ranges 22 \
  --source-address-prefixes 103.5.140.135/32 \
  --access Allow \
  --protocol Tcp 

az network nsg rule create \
  --resource-group MyResourceGroup \
  --nsg-name NsgWeb \
  --name tcp80 \
  --priority 110 \
  --destination-port-ranges 80 \
  --access Allow \
  --protocol Tcp 

セキュリティグループの設定確認

showコマンドによる確認例は以下の通りです。queryで整形していますが、必要とされる情報は運用要件依存かと思いますので、queryの整形は適宜の変更が必要です。

$ az network nsg rule list \
  --resource-group MyResourceGroup \
  --nsg-name NsgWeb \
  --query "[].{seq:priority, source:sourceAddressPrefix, port:destinationPortRange, action:access}" \
  --output table
Seq    Source            Port    Action
-----  ----------------  ------  --------
100    103.5.140.135/32  22      Allow
110    *                 80      Allow  

azコマンドだけなく、ポータル(GUI)でも設定を確認してみましょう。「すべてのサービス」から辿る場合は、「ネットワーキング」「ネットワーク セキュリティ グループ」「ネットワーク セキュリティ グループ名(NsgWeb)」「受信セキュリティ規則」の順に押下します。すると、「AllowVnetInBound」「AllowAzureLoadBalancerInBound」という暗黙の許可設定がある事が分かります。Azure内の仮想マシンやロードバランサからは明示的な許可なしに接続可能な事が分かります。

暗黙的なルール含めて確認するには「az network nic list-effective-nsg」というコマンドを使用します。

暗黙的なセキュリティルールの確認

疎通確認用の仮想マシン作成

疎通確認用の仮想マシンを作成します。

az vm create \
  --resource-group MyResourceGroup \
  --name LinuxWeb010 \
  --image UbuntuLTS \
  --size Standard_B1s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/authorized_keys \
  --vnet-name Vnet01 \
  --subnet SubnetWeb \
  --nsg NsgWeb \
  --private-ip-address 172.16.1.10

Webサーバを模擬するために、nginxをインストールします。

az vm run-command invoke \
  --resource-group MyResourceGroup \
  --name LinuxWeb010 \
  --command-id RunShellScript \
  --scripts 'apt install -y nginx'

疎通確認

仮想マシン作成時のログから、仮想マシンに割り当てられたグローバルIPアドレスを判断します。

$ az vm create \
  --resource-group MyResourceGroup \
  --name LinuxWeb010 \
  --image UbuntuLTS \
  --size Standard_B1s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/authorized_keys \
  --vnet-name Vnet01 \
  --tags uinitTest=nsg \
  --subnet SubnetWeb \
  --nsg NsgWeb \
  --private-ip-address 172.16.1.10
It is recommended to use parameter "--public-ip-sku Standard" to create new VM with Standard public IP. Please note that the default public IP used for VM creation will be changed from Basic to Standard in the future.
{
  "fqdns": "",
  "id": "/subscriptions/2e2f81a9-b030-410f-9784-c582580c932e/resourceGroups/MyResourceGroup/providers/Microsoft.Compute/virtualMachines/LinuxWeb010",
  "location": "japaneast",
  "macAddress": "00-22-48-68-D1-37",
  "powerState": "VM running",
  "privateIpAddress": "172.16.1.10",
  "publicIpAddress": "20.222.51.151",
  "resourceGroup": "MyResourceGroup",
  "zones": ""
}

仮想マシンへのsshとhttpが成功する事を確認します。

admin@mac19 ~ % curl -I http://20.222.51.151/
HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Date: Sun, 27 Mar 2022 05:26:44 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Sun, 27 Mar 2022 05:23:10 GMT
Connection: keep-alive
ETag: "623ff4be-264"
Accept-Ranges: bytes

admin@mac19 ~ % 
admin@mac19 ~ % 
admin@mac19 ~ % 
admin@mac19 ~ % ssh azureuser@20.222.51.151

  <omitted>

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.



azureuser@LinuxWeb010:~$ 

DBサーバのセキュリティグループ実装例

セキュリティグループの作成

以下のコマンドでセキュリティグループを作成します。

az network nsg create \
  --resource-group MyResourceGroup \
  --name NsgDB

mysql(tcp3306)を許可し、さらに他のサーバからの一切のログインを拒否します。まずはmysql(tcp3306)を許可する設定例を示します。

az network nsg rule create \
  --resource-group MyResourceGroup \
  --nsg-name NsgDB \
  --name tcp3306 \
  --priority 100 \
  --destination-port-ranges 3306 \
  --access Allow \
  --protocol Tcp 

ネットワークセキュリティグループは、デフォルトでAzure内の仮想マシンなどからの接続を許可する暗黙的な設定が入っています。この挙動を打ち消すには、明示的な拒否の設定が必要です。他のサーバからの一切のログインを拒否しますには、以下のような設定をします。

引数destination-port-rangesを省略するとデフォルト値80が設定される珍しい仕様になっていますので、全てのポート番号を指定する場合は以下のように明示的に「*」を指定してください。

az network nsg rule create \
  --resource-group MyResourceGroup \
  --nsg-name NsgDB \
  --name denyAny \
  --priority 4000 \
  --destination-port-ranges '*' \
  --access Deny \
  --protocol '*'

セキュリティグループの設定確認

showコマンドによる確認例は以下の通りです。

$ az network nsg rule list \
  --resource-group MyResourceGroup \
  --nsg-name NsgDB \
  --query "[].{seq:priority, source:sourceAddressPrefix, port:destinationPortRange, action:access}" \
  --output table
Seq    Source    Port    Action
-----  --------  ------  --------
100    *         3306    Allow
4000   *         *       Deny

疎通確認用の仮想マシン作成

疎通確認用の仮想マシンを作成します。

az vm create \
  --resource-group MyResourceGroup \
  --name LinuxDb010 \
  --image UbuntuLTS \
  --size Standard_B1s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/authorized_keys \
  --vnet-name Vnet01 \
  --subnet SubnetDb \
  --nsg NsgDB \
  --private-ip-address 172.16.2.10

MySQLを疑似するために、tcp3306をlisten状態にするスクリプトを仕込みます。

RDBMS固有の製品知識がなくても動作確認ができるよう、敢えて、ncコマンドを使用する手法を採用しています。

az vm run-command invoke \
  --resource-group MyResourceGroup \
  --name LinuxDb010 \
  --command-id RunShellScript \
  --scripts @/dev/stdin << EOF
#!/bin/bash
function loop_nc {
  while true ; do
    nc -l 3306
  done
}
export -f loop_nc
nohup /bin/bash -c loop_nc > /root/loop_nc.log 2>&1 &
EOF

疎通確認

azureuser@LinuxWeb010:~$ nc 172.16.2.10 3306
A test message was sent to your server
^C
azureuser@LinuxWeb010:~$ 

azureuser@LinuxWeb010:~$ ping 172.16.2.10 -c 3
PING 172.16.2.10 (172.16.2.10) 56(84) bytes of data.

— 172.16.2.10 ping statistics —
3 packets transmitted, 0 received, 100% packet loss, time 2055ms

azureuser@LinuxWeb010:~$
azureuser@LinuxWeb010:~$
azureuser@LinuxWeb010:~$ ssh 172.16.2.10
ssh: connect to host 172.16.2.10 port 22: Connection timed out
azureuser@LinuxWeb010:~$

補足

effective nsg

以下のようなコマンドで実際に適用されるネットワークセキュリティグループを確認できます。

az network nic list-effective-nsg \
  --resource-group <リソースグループ名> \
  --name <仮想NIC名>

操作例は以下の通りです。ポータル(GUI)で出力される以上の細かな情報が出力されます。GUIで表示されない何らかの暗黙的な設定が疑われる場合は、このコマンドの出力を確認してみるのも良いでしょう。

理由は不明ですが(想像するにセキュリティ上の理由や国防上の理由など)、実は一部のグローバルアドレスとの接続が許可されていない等のポータル(GUI)からは読み取れない様々な暗黙的な仕様を確認する事ができます。

NIC_ID=$(az vm nic list \
  --resource-group MyResourceGroup \
  --vm-name LinuxWeb010 \
  --query "[0].id" \
  --output tsv )

NIC_NAME=$(az vm nic show \
  --resource-group MyResourceGroup \
  --vm-name LinuxWeb010 \
  --nic ${NIC_ID} \
  --query "name" \
  --output tsv )

az network nic list-effective-nsg \
  --resource-group MyResourceGroup \
  --name ${NIC_NAME}
{
  "nextLink": null,
  "value": [
    {
      "association": {
        "networkInterface": {
          "id": "/subscriptions/2e2f81a9-b030-410f-9784-c582580c932e/resourceGroups/MyResourceGroup/providers/Microsoft.Network/networkInterfaces/LinuxWeb010VMNic",
          "resourceGroup": "MyResourceGroup"
        },
        "networkManager": null,
        "subnet": null
      },

 <commit>

          "expandedDestinationAddressPrefix": [
            "1.0.0.0/8",
            "2.0.0.0/7",
            "4.0.0.0/9",
            "4.144.0.0/12",
            "4.160.0.0/11",
            "4.192.0.0/10",
            "5.0.0.0/8",
            "6.0.0.0/7",
            "8.0.0.0/7",

  <omitted>

トラフィックフィルターの診断

Inbound方向

ネットワーク ウォッチャーにはネットワークセキュリティグループの設定が想定通りか否かを診断するツールが備わっています。公式ドキュメント「クイック スタート:仮想マシン ネットワーク トラフィック フィルターの問題を診断する – Azure CLI」にはネットワーク ウォッチャーの有効化方法が記されていますが、殆どの場合は仮想マシンや仮想マシンスケールセットの作成と同時にネットワーク ウォッチャーが有効化されるので、意識する必要はない操作です。

さて、以下のようなコマンドを使用すると、トラフィックが許可されるのか拒否されるのか、どのようなセキュリティルールにヒットするのかを確認できます。

az network watcher test-ip-flow \
  --resource-group <リソースグループ名> \
  --direction <通信方向> \
  --protocol <プロトコル> \
  --local <ローカルIPアドレス>:<ローカルポート番号> \
  --remote <リモートIPアドレス>:<リモートポート番号> \
  --vm <仮想マシン名> \
  --nic <仮想NIC名>

例えば、LinuxWeb010がssh(tcp22)を許可している事を確認するには、以下のように操作します。

$ az network watcher test-ip-flow \
  --resource-group MyResourceGroup \
  --direction Inbound \
  --protocol TCP \
  --local 172.16.1.10:22 \
  --remote 103.5.140.135:60000 \
  --vm LinuxWeb010
{
  "access": "Allow",
  "ruleId": "/subscriptions/2e2f81a9-b030-410f-9784-c582580c932e/resourceGroups/MyResourceGroup/providers/Microsoft.Network/networkSecurityGroups/NsgWeb/securityRules/tcp22",
  "ruleName": "securityRules/tcp22"
}

LinuxDb010がssh(tcp22)を拒否している事を確認するには、以下のように操作します。

$ az network watcher test-ip-flow \
  --resource-group MyResourceGroup \
  --direction Inbound \
  --protocol TCP \
  --local 172.16.2.10:22 \
  --remote 103.5.140.135:60000 \
  --vm LinuxDb010
{
  "access": "Deny",
  "ruleId": "/subscriptions/2e2f81a9-b030-410f-9784-c582580c932e/resourceGroups/MyResourceGroup/providers/Microsoft.Network/networkSecurityGroups/NsgDB/securityRules/denyAny",
  "ruleName": "securityRules/denyAny"
}

Outbound

このページでは説明を省略していますが、セキュリティグループはOutbound方向にも設定する事ができます。Outbound方向に設定したセキュリティグループが想定通りかも確認できます。例えば、LinuxWeb010からbing.com(13.107.21.200)へhttp(tcp80)の疎通が可能かどうかを確認するのは、以下のような操作になります。

$ az network watcher test-ip-flow \
  --resource-group MyResourceGroup \
  --direction Outbound \
  --protocol TCP \
  --local 172.16.1.10:60000 \
  --remote 13.107.21.200:80 \
  --vm LinuxWeb010
{
  "access": "Allow",
  "ruleId": "",
  "ruleName": "defaultSecurityRules/AllowInternetOutBound"
}

NSGフローログ

NSGフローログを使用するには、Microsoft.Insightsを登録する必要があります。登録しているかどうか不明な場合は、以下のコマンドを実行します。

az provider register --namespace Microsoft.Insights

フローログを格納するストレージアカウントを作成します。すでにストレージアカウントが存在するならば、既存の物を利用しても良いでしょう。

az storage account create \
  --name storagegokatei01 \
  --resource-group MyResourceGroup \
  --location japaneast \
  --sku Standard_LRS

以下のようなコマンドでNSGフローログを有効にします。フローログはversion 1とversion 2があります。version 1の操作例は「Azure CLI を使用したネットワーク セキュリティ グループ フローのログの構成」を参照ください。

az network watcher flow-log create \
  --resource-group MyResourceGroup \
  --name flowLogWeb \
  --enabled true \
  --nsg NsgWeb \
  --storage-account storagegokatei01 \
  --location japaneast \
  --format JSON \
  --log-version 2

動作確認用のログを生成するために、LinuxWeb010に対して何らかの通信を発生させます。

curl -I http://20.222.51.151/
curl -I http://20.222.51.151:8080/
ssh azureuser@20.222.51.151

ログはinsights-logs-networksecuritygroupfloweventという名前のBLOBコンテナーに格納されます。コンテナからのダウンロード方法はAzure Storage Explorer, ポータル(GUI), CLIなど任意の方法で差し支えございません。

もし、ポータル(GUI)でダウンロードする場合は、「すべてのメニュー」から「ストレージ」「ストレージアカウント」「ストレージアカウント名(storagegokatei01)」「コンテナー」「insights-logs-networksecuritygroupflowevent」の順に画面遷移します。

NSG フローログの確認 01

日付やMacAddress毎にディレクトリが定義されていますので、ダウンロード対象となるJSONファイルを探します。JSONファイルは右クリックメニューでダウンロードできます。

NSG フローログの確認 02

ダウンロードしたJSONファイルは改行処理がなされておらず読みづらい状態になっていますので、jqコマンドなどを用いて適宜整形しながら読みます。

admin@mac19 ~ % cat PT1H.json | jq
{
  "records": [
    {
      "time": "2022-03-27T06:03:26.5437199Z",
      "systemId": "65afb951-d8ca-433f-b414-5b373bf61239",
      "macAddress": "00224868D137",
      "category": "NetworkSecurityGroupFlowEvent",
      "resourceId": "/SUBSCRIPTIONS/2E2F81A9-B030-410F-9784-C582580C932E/RESOURCEGROUPS/MYRESOURCEGROUP/PROVIDERS/MICROSOFT.NETWORK/NETWORKSECURITYGROUPS/NSGWEB",
      "operationName": "NetworkSecurityGroupFlowEvents",
      "properties": {
        "Version": 2,
        "flows": [
          {
            "rule": "DefaultRule_DenyAllInBound",
            "flows": [
              {
                "mac": "00224868D137",
                "flowTuples": [
                  "1648360983,103.5.140.135,172.16.1.10,54656,8080,T,I,D,B,,,,"
                ]
              }
            ]
          }
        ]
      }
    },

  <omitted>

タイトルとURLをコピーしました