Azure CLI を使って Azure Firewall と Network Security Group の組み合わせを試してみた

## 背景と目的

Azure Firewall と Network Security Group ( NSG ) の組み合わせでどのような動きになるのか不明だったので、実際に試してみて確認します。

## 前提条件

コマンドの実施環境は、Mac + Azure CLI です。

```zsh:zsh
% sw_vers
ProductName:    macOS
ProductVersion: 11.4
BuildVersion:   20F71

% az version
{
  "azure-cli": "2.24.2",
  "azure-cli-core": "2.24.2",
  "azure-cli-telemetry": "1.0.6",
  "extensions": {}
}
```

## 実施内容

まずは、VNET と NSG を作成しインターネットへアクセス出来ない状態にしてから、動作確認用 VM を用意します。その後、Azure Firewall とルーティングテーブルを作成して、動作確認用 VM が Azure Firewall を通ってインターネットにアクセスしている事を確認します。

```zsh:zsh
# 環境変数を設定します
region=japaneast
prefix=mnrafwtest

# リソースグループを作成します
az group create \
  --name ${prefix}-rg \
  --location $region

# VNET を作成します
az network vnet create \
  --name ${prefix}-vnet \
  --resource-group ${prefix}-rg \
  --address-prefixes 10.0.0.0/23 \
  --subnet-name default-subnet \
  --subnet-prefixes 10.0.0.0/24

# Azure Firewall 用のサブネットを作成します
# サブネット名は、AzureFirewallSubnet である必要があります
az network vnet subnet create \
  --name AzureFirewallSubnet \
  --resource-group ${prefix}-rg \
  --vnet-name ${prefix}-vnet \
  --address-prefix 10.0.1.0/24

# NSG を作成します
az network nsg create \
  --resource-group ${prefix}-rg \
  --name ${prefix}-nsg

# Internet へのアウトバウンドを禁止します
az network nsg rule create \
  --resource-group ${prefix}-rg \
  --nsg-name ${prefix}-nsg \
  --name DenyInternetOutBound \
  --priority 4096 \
  --destination-port-ranges '*' \
  --destination-address-prefixes Internet \
  --access Deny \
  --direction Outbound

# NSG をサブネットに紐付けます
az network vnet subnet update \
  --resource-group ${prefix}-rg \
  --name default-subnet \
  --vnet-name ${prefix}-vnet \
  --network-security-group ${prefix}-nsg

# 動作検証用 VM のパスワードを生成します
vmpassword=$(openssl rand -base64 16)
echo $vmpassword

# 動作検証用 VM を作成ます
# NIC には NSG やパブリック IP は設定しません
az vm create \
  --resource-group ${prefix}-rg \
  --name ${prefix}-vm \
  --os-disk-name ${prefix}-vmOSDisk \
  --image UbuntuLTS \
  --size Standard_B1s \
  --vnet-name ${prefix}-vnet \
  --subnet default-subnet \
  --admin-username azureuser \
  --admin-password $vmpassword \
  --nsg "" \
  --public-ip-address "" \
  --storage-sku Standard_LRS

# 動作検証用 VM からインターネットにアクセス出来るか確認します
# NSG でインターネットアクセスをブロックしているので curl の結果は帰ってきません
az vm run-command invoke \
  --command-id RunShellScript \
  --resource-group ${prefix}-rg \
  --name ${prefix}-vm \
  --query "value[0].message" \
  --output tsv \
  --scripts "curl -s inet-ip.info"

# Azure Firewall 用のパブリック IP を作成します
az network public-ip create \
  --resource-group ${prefix}-rg \
  --name ${prefix}-afw-pip \
  --allocation-method Static \
  --sku Standard

# Azure CLI に Azure Firewall の拡張機能を追加します
az extension add \
  --name azure-firewall

# Azure Firewall を作成します
az network firewall create \
  --resource-group ${prefix}-rg \
  --name ${prefix}-afw

# Azure Firewall にパブリック IP と VNET を紐付けます
# VNET のサブネットは、AzureFirewallSubnet が使われます
az network firewall ip-config create \
  --resource-group ${prefix}-rg \
  --firewall-name ${prefix}-afw \
  --name fw-config \
  --public-ip-address ${prefix}-afw-pip \
  --vnet-name ${prefix}-vnet

# ルーティングテーブルを作成します
az network route-table create \
  --name ${prefix}-rt \
  --resource-group ${prefix}-rg \
  --disable-bgp-route-propagation true

# ルーティングテーブルにデフォルトルートを作成します
az network route-table route create \
  --route-table-name ${prefix}-rt \
  --resource-group ${prefix}-rg \
  --name fw-route \
  --address-prefix 0.0.0.0/0 \
  --next-hop-type VirtualAppliance \
  --next-hop-ip-address $(az network firewall ip-config list \
  --resource-group ${prefix}-rg \
  --firewall-name ${prefix}-afw \
  --query "[?name=='fw-config'].privateIpAddress" \
  --output tsv)

# ルーティングテーブルを動作検証用 VM があるサブネットに紐付けます
az network vnet subnet update \
  --resource-group ${prefix}-rg \
  --name default-subnet \
  --vnet-name ${prefix}-vnet \
  --route-table ${prefix}-rt

# Azure Firewall にアプリケーションルールを作成します
# 動作検証用 VM があるサブネットから特定のFQDNへのアクセスを許可します
az network firewall application-rule create \
   --collection-name App-Coll01 \
   --firewall-name ${prefix}-afw \
   --name Allow-InetIpInfo \
   --protocols Http=80 Https=443 \
   --resource-group ${prefix}-rg \
   --target-fqdns inet-ip.info \
   --source-addresses 10.0.0.0/24 \
   --priority 200 \
   --action Allow

# NSG でインターネットへのアクセスをブロックしているのでルールを削除します
az network nsg rule delete \
  --resource-group ${prefix}-rg \
  --nsg-name ${prefix}-nsg \
  --name DenyInternetOutBound

# Azure Firewall にアプリケーションルールで許可している FQDN は正常にアクセス出来ます
az vm run-command invoke \
  --command-id RunShellScript \
  --resource-group ${prefix}-rg \
  --name ${prefix}-vm \
  --query "value[0].message" \
  --output tsv \
  --scripts "curl -s inet-ip.info"

# 検証が終わったのでリソースグループごと削除します
az group delete \
  --name ${prefix}-rg
```

## 実施結果

NSG と Azure Firewall のルール、どちらでも通信を制御可能な事がわかりました。
組み合わせて利用している場合は、片方を許可してもう片方でブロックしていたりすると通信できないので注意が必要です。


## 参考

[Azure CLI を使用して Azure Firewall をデプロイして構成する](https://docs.microsoft.com/ja-jp/azure/firewall/deploy-cli)

[az network firewall create](https://docs.microsoft.com/ja-jp/cli/azure/network/firewall?view=azure-cli-latest#az_network_firewall_create)