#002: Virtual NetworkのBicep定義

※本記事は、個人の意見および個人的活動で得た経験を記したものであり、会社を代表するものではありません

# 1. VNetの定義

今回は以下の定義で構築する。

- name = “RagSystem-MainVNet-dev”
- region = “east us 2”
- IP Address Prefix = 10.0.0.0/16 (Default)
- 仮想ネットワーク暗号化 = true
- DDoS ネットワーク保護 = false
- Bastionの有効化 = false (Subnetだけ作成しBasion自体は後で追加)
- Firewallの有効化 = false

VNetって結構簡単に構築できちゃうのだが、考慮すべき事が結構あるので少し丁寧に説明しながら詳細を定義する。

# 2. VNetを構成する時の考慮ポイント

## 2-1. VNetの暗号化

VNetを構成する時のオプションとして、VNetの暗号化がある。VNet内の仮想マシン間のトラフィック、及びピアリングした複数VNetに散在するVM間のトラフィックを暗号化する。

https://learn.microsoft.com/ja-jp/azure/virtual-network/virtual-network-encryption-overview

https://www.aps-web.jp/academy/security/83374/

理解不足のためUDPベースの暗号化ってイメージできていないが、ポイントは「仮想マシン間の通信をセキュアにする」ということ。「仮想マシン」の定義として、AzureのPaaSサービス内で利用されているVMも含まれている。

追加料金は不要だし、プライベートネットワークであってもEnd to Endで暗号化されるのでデータセキュリティの観点からONで良いと思う。

https://teskalabs.com/blog/seacat-encryption

ただし、仮想ネットワーク暗号化に対応したVMインスタンスサイズを選択していないと暗号化が有効にならないそうなので（後で言及するが、暗号化されないだけで通信はできる）、VMだけではなくPaaSサービス内で利用されるVMサイズも確認が必要。

https://learn.microsoft.com/ja-jp/azure/virtual-network/virtual-network-encryption-overview#requirements

今回はONにし、後で対応VMを構築する。

## 2-2. DDosネットワーク保護

今回の構成ではDDoS Basicで十分。

一応、DDoS BasicとDDoS Standardの主な違いについて以下にまとめておく。

### 2-2-1. DDoS Basic (IP level) の主な特徴

一般的なWEBアプリやAPIの保護、企業ホームページなどはDDoS Basicで十分。

- 追加料金なし
- 詳細な構成不要（リソース作成直後から保護開始）
- L3,4レベルの保護
- SLAなし
- 攻撃の診断結果やテレメトリログが提供されない

### 2-2-2. DDoS Standard (Network level)の主な特徴

必要となるケースとしては、E-Commerceサイト、金融サービス、メディアストリームサービスなど、サービスが停止する事で大きな損害が生じる可能性のあるサービスにはこちらを利用する。

- Azureの脅威インテリジェンスと機械学習を利用したDDoS攻撃のリアルタイムな検出
- 新しい攻撃や進化する攻撃への継続的な対応
- VNet外部に公開されている全てのリソースの保護 (PIPのあるVM, LB, Application Gatewayなど)
- L3,4に加えてL7レベルの保護
- Azureモニターやセキュリティセンターで詳細ログやメトリックの確認が可能
- DDoS保護ポリシーのカスタマイズ
- トラフィック量や保護対象リソースの数に応じた追加コストあり
- SLAあり

## 2-3. Subnetの検討

Subnetの構成やIPレンジは事前に検討しておく。利用するリソースによって専用Subnetと一定数以上のIPレンジが必要になる。また、１つのSubnetにつきAzureによって予約されているIP含めて合計5つ消費されるという事は常に意識しておく必要がある。設計漏れによって後から追加・変更が必要になると、IPレンジが足りなくて構成できないといった状況に陥る可能性がある。

以前のプロジェクトで、Firewall、Bastion、VM、AMPLS、PaaSとのPrivate end point、Express Routeとの接続を１つのVNetで構成したが、オンプレ側の制約でVNetに付与できるネットワークアドレスに制限があったため、これ以上Subnetを追加できないといった状態までひっ迫したことがある。VMを構成するSubnetのレンジを最小にすることで乗り切ったがかなり焦った。

### 2-1-1. 管理VM用のSubnetの定義

VMを配置するSubnetは以下の内容で構築する。

- name = “AdminSubnet”
- IP address prefix = 10.0.0.0/29
- Private subnet = true
- NAT Gateway = none (NAT Gateway作成後に関連付けする)
- NSG = none (現時点では不要、利用するかどうかは必要に応じて後で検討)
- Route table = none (不要：送信トラフィック制御は行わない)
- Service Endpoint = none (不要：KeyVaultは外部公開せず、Private Endpointを利用してアクセスする)
- Subnet delegation = none (不要：イマイチ理解不足。PaaSのVNet統合と関係ありそうだが、今回はVNet統合は利用しないので、それに伴うdelegationは不要と判断)
- private endpoint network policy = NSG（イマイチ理解不足。KeyVault用Private EndpointへのアクセスはAzureBastionSubnetからのインバウンドのみ許可するようにしたいのでNSGを指定、NSGのリソース自体はあとで追加）

VMの用途は、閉域網内の管理運用の用途。

ちなみに1台のVMを構築するだけでもSubnetのIPレンジは最低/29必要。

:::note warn
冒頭で説明した通り、Azureのサブネットはデフォルトで先頭4つと最後の1つの合計5つのIPがAzureによって予約されているため、1台のVMを構成する場合であってもSubnetは最低/29のレンジが必要。むやみやたらにSubnetを作成するのは無駄にIPを消費するので効率的なSubnetを設計するというのは重要。
:::

/29のレンジで作成したSubnetに含めることが出来るVMやPrivate Endpointは合計3台。

プライベートIPに関する参考情報。

https://learn.microsoft.com/ja-jp/azure/virtual-network/ip-services/private-ip-addresses#allocation-method

subnet delegationに関する参考情報。（アーキテクチャサンプルの説明で少しイメージできた）

https://learn.microsoft.com/en-us/azure/architecture/web-apps/guides/networking/access-multitenant-web-app-from-on-premises

Private EndpointのNetwork policyに関する参考情報。（この記事わかりやすい）

https://msandbu.org/network-policies-for-private-endpoints-with-udr-and-nsg/

### 2-1-2. Bastion用Subnetの定義

- name = “AzureBastionSubnet”
- IP address prefix = 10.0.0.64/26
- Private subnet = true
- NAT Gateway = none (後で追加して関連付け)
- NSG = none (後で追加して関連付け)
- Route table = none
- Service Endpoint = none
- Subnet delegation = none
- private endpoint network policy = Disabled

仮想マシンを構成する場合はBastionを使用する可能性を考慮。RDPやSSHにダイレクトにアクセスするのはセキュリティの観点から好ましくなく、かつVMに接続するためだけにVPNを構成したりFirewallルールを追加するのは手間なので、セキュリティと構成容易性の観点から私はBasionを好んで利用し、必要に応じてBastionへの接続元IP制限を設定する。

Basic以上のSkuを利用する場合、”AzureBastionSubnet”という固有名詞で、かつ/26以上のIPレンジを持つSubnetが必須。

1つのVNetで構成されたシステムで、かつVMがシステム運用上優先度が低い場合はBasicで良いかも。

複数VNetをピアリングする場合、Standardにすることで、1つのBastionでピアリングされた複数VNetにあるVMへのアクセスが提供できる。

Developerは無料ではあるものの、提供されるリージョンは現時点で東西日本リージョンは提供されていない。また単純なパスワード認証のみに対応しており、KeyVaultでSSHキーやパスワードを管理するといったことはできない。

https://azure.microsoft.com/en-us/blog/introducing-azure-bastion-developer-secure-and-cost-effective-access-to-your-azure-virtual-machines/

今回はSSH KeyをKeyVaultに保存し、それを使ってLinux VMへアクセスしたいので、Basicを利用する。（上述の通り、この機能はDeveloperでは提供されない）

### 2-1-3. Azure Monitor Private Link Scope (AMPLS)用Subnetの定義

別途検証するので今回は含めない。

このSubnetが必要になるのは、Azure Monitor Private Link Scope（AMPLS）の利用を検討する場合。VNet内のリソースやExpressRoute経由でオンプレサーバーのメトリックやログなどの監視データをプライベートネットワーク経由でAzure Monitorへ転送する事ができる。

AMPLSもサブネットが必要で最低/27のレンジが必要。専用Subnetは必須ではないが、ネットワーク管理の観点でAMPLS用のSubnetを構成したほうが分かりやすいと思う。

https://learn.microsoft.com/ja-jp/azure/azure-monitor/logs/private-link-design#network-subnet-size

### 2-1-4. Azure Firewall用Subnetの定義

別途検証するので今回は含めない。

Azure Firewallも”AzureFirewallSubnet”という固有名詞で、かつ/26以上のレンジを持つSubnetが必須。

トランスポートレベルでトラフィックを細かく制御するとか、複数のリソースや、ピアリングされた複数VNetのアクセスポリシーを一か所で制御したい場合はAzure Firewallを検討する。要件によってNAT gatewayで十分な場合があるので、どちらを採用するかは要件に応じて決定する。

Azure Firewallを検討する例として、VMからインターネットアクセスに対するセキュリティ要件が厳しい場合がある。例えば、VMのOSアップデートやセキュリティパッチ、VMからAzure Portalにアクセスしたり、CLIで管理業務を行うときに必要なURLだけを許可するといった、かなり細かい制御を行う必要がある場合は、Azure Firewallで制御する事を検討する。

今回はNAT Gatewayを利用するが、Azure Firewallの構成例としてVMからのアクセスを制限する方法は別の機会に記載する。

### 2-1-5. Key VaultへアクセスするためのPrivate endpointを配置するSubnetの定義

今回はAdminSubnetに間借りするのでPrivate Endpoint用のSubnetは構成しない。

SSHキーの保存用途で利用するKeyVaultはPaaSであるため、VNet内のリソースからセキュアに接続するためにはPrivate Endpointを用いてPrivate Link経由でアクセスする必要がある。

Private Endpointは，VNetとPrivate Linkを接続するためのVNet側に配置するNICとして機能するものであり、Subnet内に配置するイメージ。

Private Endpointは、SubnetのIPレンジからPrivate IPが割り当てられる事で、VNet内のリソースがPrivate IP経由でPrivate Linkを通してPaaSと接続できるようになる。

Private Endpointには専用のsubnetは不要であるため、接続するPaaSの用途に応じてsubnetを決めればよいと思う。

今回はVMに接続するときのSSHキーを保存する用途しかないので、AdminSubnetに紐づける事にする。

::: note warn
設計パターンとしてPrivate EndpointだけをまとめたSubnetを構築するケースもある。これにより他のSubnetからPaaSへのルーティングルールを定義しやすくなるというメリットがある。
:::

## 2-2. Subnetを構成する時のオプション

### 2-2-1. Private Subnet（Preview）の検討

現時点では、VNetには明確なインターネットへの接続設定を利用しなくてもデフォルトで送信トラフィックだけは許可する仕組みがあるとのこと。だが、この機能は2025/09/30で終了するため、明示的に送信トラフィックを許可するための手段を入れておくのが良い。

Private Subnet は、送信トラフィックを許可するデフォルト機能を抑制するオプション。

https://techcommunity.microsoft.com/t5/azure-networking-blog/secure-your-subnet-via-private-subnet-and-explicit-outbound/ba-p/3984177

Public Previewだが、今回試しに使ってみる。

Private Subnetにはいくつか制限があるので後から有効にする場合は考慮しておく必要がある。

https://learn.microsoft.com/en-us/azure/virtual-network/ip-services/default-outbound-access#private-subnet-limitations

SNATを提供するリソースはいくつかあるが、特に送信トラフィックの制限に要件が無いのであれば、NAT Gatewayが一番お手軽な方法。MSも推奨している。

今回は全てのSubnetをPrivate Subnetとして構築する。

### 2-2-2. NAT Gateway

今回の構成では、以下の理由でVMからインターネットアクセスを必要とするが、Public IPを構成するのではなく、NAT Gatewayで構成する。

- VM自体のOSアップデートとセキュリティパッチのダウンロード
- VNetに閉じたKeyVaultをVMから管理するために、VMからAzureポータル（ブラウザ）にアクセス

::: note warn
KeyVaultをVNetに閉じると、Azure PortalからKeyVaultのキー、証明書、シークレットなどにアクセスできない。このため、KeyVaultをPrivate Endpointで接続したVNet内のVMからアクセスする必要があるが、Azure Portalはインターネット上で提供されているサービスであるため、一旦インターネットへのアクセスが必要。
:::
VMのブラウザで一度インターネット上のAzure Portalにアクセスし、そこからKeyVaultアクセスするのだが、KeyVaultにアクセスする際にPrivate DNSによりKeyVaultのサービス名がPrivate EndpointのプライベートIPで解決されるため、Private Endpointを経由してKeyVaultにアクセスすることが出来るようになる。結果、キー、シークレット、証明書の管理が可能になるということ。
ややこしやーw

</aside>

Azure Firewallの項目で言及したので繰り返しになるが、NAT GatewayはSNATを簡易的に提供するが、トラフィックの宛先の制限等はできない。企業のセキュリティ要件として、特定の目的以外の送信トラフィックを許可しないポリシーの場合もあり、その場合はNAT GatewayではなくAzure Firewallを構成しなければならない。

### 2-2-3. NAT GatewayとNSG

NSGはSubnet単位の簡易的なFirewallとして機能するが、今回はNAT Gatewayを使うので、NSGを使用したインターネットからのインバウンドトラフィック制御は不要。

今回はNAT Gatewayで十分。

### 2-2-4. Private Endpointのネットワークポリシー

https://learn.microsoft.com/en-us/azure/private-link/disable-private-endpoint-network-policy?tabs=network-policy-portal

Private Endpointに向けたトラフィックを制御したい場合、Subnetのネットワークポリシーを有効にする事で（デフォルトは無効）、以下２つのどちらか、もしくは両方で制御することが出来る。

- NSG：Private Endpoint宛のトラフィックに対し、Private Endpointが含まれるSubnetに紐づけたNSGによって許可/拒否を制御する
- UDR：Private Endpoint宛のトラフィックに対し、どこを経由するのかを制御する（Private Endpointが含まれるSubnetではなく、送信元Subnet側でUDRを定義する）

NSGはSubnetへのインバウンドトラフィックを制御する。

UDRは送信元の方でルーティング制御するものであり、仕組みが少し込み入っているのだが、以下のドキュメントで紹介されている構成を参照するとイメージしやすい。例えば、Private Endpointに向けたトラフィックを一旦Firewallに向けることで、Firewallにてトラフィックを制御し、かつトラフィックログも取得出来る（NSGではこれができない）。

https://learn.microsoft.com/en-us/azure/private-link/inspect-traffic-with-azure-firewall

また、上記のドキュメントではUDRを使って制御をする場合、SNATを構成することが推奨されている。SNATを通すことで、Private Endpointからの戻りトラフィックが確実にSNATで指定したIPに戻ってくるらしい。SNATが無いと元のIPに戻らないというのが理解できないので誰かコメントで教えてほしい。。。

MSのドキュメントだけでは全くイメージできなかったのだが、以下のブログを読んでSNATの必要性以外は理解が進んだ。

https://qiita.com/Isato-Hiyama/items/6b90904887fcfe12b2a9

今回はトラフィックログは不要、BastionからKeyVaultへのアクセスだけNSGで許可するので、AdminSubnetのPrivate EndpointのネットワークポリシーをNSGに設定し、後でルールを追加定義することにした。

## 2-3. VNet作成オプションまとめ

ここまでの内容から今回作成するVNetは以下の通り。

- name = “RagSystem-MainVNet-dev”
- region = “Japan East”
- IP Address Prefix = 10.0.0.0/16 (Default)
- 仮想ネットワーク暗号化 = true
- DDoS ネットワーク保護 = false
- Bastionの有効化 = false (Subnetだけ作成しBasion自体は後で追加)
- Firewallの有効化 = false
- Subnet[1]=管理VM用Subnet
    - name = “AdminSubnet”
    - IP address prefix = 10.0.0.0/29
    - Private subnet = true
    - NAT Gateway = none (NAT Gatewayは後で作成して関連付けする)
    - NSG = none
    - Route table = none
    - Service Endpoint = none
    - Subnet delegation = none
    - private endpoint network policy = NSG
- Subnet[2]=Bastion用Subnet
    - name = “AzureBastionSubnet”
    - IP address prefix = 10.0.0.64/26
    - Private subnet = true
    - NAT Gateway = none (NAT Gatewayは後で作成して関連付けする)
    - NSG = none
    - Route table = none
    - Service Endpoint = none
    - Subnet delegation = none
    - private endpoint network policy = none

構築後の作業として、以下２つのリソースを追加作成。

- NAT Gateway
    - AdminSubnet：VMのOSアップデートやセキュリティパッチのダウンロード、およびVNetに接続したPaaSに対する閉域網からの管理のためのAzure Portalへのアクセス
    - BastionSubnet：Basionを構成する内部VMのOSアップデートやセキュリティパッチのダウンロード
- NSG
    - AdminSubnet：Bastionからのインバウンドトラフィックのみ許可

# 3. リソースの作成

## 3-1. Bicepテンプレートでデプロイする

テンプレート作成のための情報源。

- Bicepテンプレートを使ったVNetのデプロイ

https://learn.microsoft.com/ja-jp/azure/azure-resource-manager/bicep/scenarios-virtual-networks

- VNetのBicep仕様

https://learn.microsoft.com/en-us/azure/templates/microsoft.network/virtualnetworks?pivots=deployment-language-bicep

- Private Subnetを設定（プロパティ名が異なるので迷子になった）

https://samcogan.com/secure-your-vnets-with-private-subnets/

### 3-1-1. Bicepテンプレート

作ったテンプレートはこちら。

https://github.com/masatoshisato/RagSystem/tree/v1.0.0/infra/virtual-network

### 3-1-2. az deploymentコマンド

```bash
sato@[11:17:49]:~/proj/RagSystem% az account show
...
ログイン中のテナント、サブスクリプション、ユーザーが表示される
...
```

```bash
sato@[11:26:57]:~/proj/RagSystem% az deployment group create -g RagSystem -f virtual-network/vnet.bicep -p virtual-network/vnet.bicepparam 
...
実行結果が表示される
...
```

# 4. 仮想ネットワークの設計に関するその他tips

## 4-1. 仮想ネットワーク暗号化に関する制約

Bicepで仮想ネットワーク暗号化をしているパラメータは以下の通り、On/Offと、暗号化未対応のVMがVNet内にある場合にそのVMとの通信を許可するかどうかの設定がある。

以下はBicepテンプレートの抜粋。

```bash
    // Enables to encrypt the traffic between VMs.
    encryption: {
      enabled: true
      enforcement: 'AllowUnencrypted' // This is Limitation to be set only 'AllowUnencrypted' by Microsoft.
      // https://learn.microsoft.com/en-us/azure/virtual-network/virtual-network-encryption-overview#limitations
    }
```

Bicepテンプレートにもコメントを残しているが、本当は’DropUnencrypted’を指定したかったのだが、公式ドキュメントで現在は’AllowUnencrypted’しか指定できないとのこと。

これを無視して’DropUnencrypted’を指定すると、以下のazコマンド実行時にエラーが発生する。

```bash
sato@[12:44:11]:~/proj/azuretemplates% az deployment group create --template-file virtual-network/vnet.bicep --resource-group BastionWithSSHFromKV
{"status":"Failed","error":{"code":"DeploymentFailed","target":"/subscriptions/871e8b6f-0727-42ce-840e-02bf7d76541a/resourceGroups/BastionWithSSHFromKV/providers/Microsoft.Resources/deployments/vnet","message":"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/arm-deployment-operations for usage details.","details":[{"code":"CannotUseDropUnencryptedForVnet","message":"This subscription does not support \"DropUnencrypted\" as enforcement policy on encrypted vnet. Please register \"Microsoft.Network/AllowDropUnecryptedVnet\" feature on this subscription.","details":[]}]}}
```

エラーの内容としては、このサブスクリプションでは無効化されているからMicrosoftネットワークのAllowDropUnencryptedVnet機能を登録しろと言われる。

意味不明だったのだが、以下で議論されていたのを発見。一旦公式ドキュメントに記載されたことでクローズされていた。

https://github.com/hashicorp/terraform-provider-azurerm/issues/25913

以下、そのMS公式ドキュメント。

https://learn.microsoft.com/en-us/azure/virtual-network/virtual-network-encryption-overview#limitations

## 4-2. VM暗号化に関するプロパティ[enableVmProtection]

以下のMSのドキュメントにはこのプロパティが掲載されており有効なプロパティであると認識できる。

https://learn.microsoft.com/en-us/azure/templates/microsoft.network/virtualnetworks?pivots=deployment-language-bicep

だが、以下のQ＆Aにて未使用であることが回答されている。このプロパティはレガシーAPIであり、もう使われていないので、VMを保護するためにはDDoS保護プランを設定すべしとの事。

https://learn.microsoft.com/en-us/answers/questions/375729/properties-enablevmprotection

## 4-3. VNetのBGP Communitiesによる複雑なハイブリッドネットワーク管理の効率化

例えば、複数リージョンにまたがるVNetが複数存在し、それらに接続されるExpressRouteが複数存在する場合、オンプレからどのルートでどのVNetにルーティングするかといったルートフィルターを設定・維持することが煩雑になる場合がある。特に、VNet側のネットワーク構成が変更された場合、オンプレ側のルートフィルターはその都度、それぞれに対して設定更新が必要となる。

BGP Communitiesは、このような複雑なハイブリットネットワーク環境において、IPプレフィックスではなく指定されたBGPコミュニティ値に基づいてオンプレ側のVNetへのルートフィルターが管理されるため、VNet側のネットワーク構成変更時にもルートフィルターの変更が不要になるなど、管理が簡略化できるとの事。

https://learn.microsoft.com/en-us/azure/expressroute/bgp-communities