0. 背景
Azure VMを使う時に筆者はいつもめんどくさがってVM作成時にオプションを使いVnet・Subnet・NSGを作成していた。しかしそれがベストプラクティスに沿っていないこと最近知ったため備忘録として残しておこうと思ったため。
1. 結論
VNet・Subnet・NSGは、VM作成前に個別に作成してからアタッチするべき
- Azure PortalのVM作成画面ではVNet・Subnet・NSGをまとめて作成できる機能があるが、この方法には複数の問題がある
- ネットワークリソースはVMのライフサイクルとは独立して管理するのがベストプラクティスであり、事前に設計・作成しておくことで運用上の問題を回避できる
2. 今回立てたいVM構成
以下の構成を前提として検証を行う
Resource Group: rg-example
Region: Japan East
VNet: vnet-example (10.0.0.0/16)
└── Subnet: snet-example (10.0.0.0/24)
└── NSG: nsg-example
└── Inbound Rule: SSH(22) - 自分のIPのみ許可
VM: vm-example
OS: Ubuntu 24.04 LTS
NIC: 自動作成
Public IP: pip-example構成図
Internet
│
│ SSH(22) ← 自分のIPのみ
│
Public IP (pip-example)
│
NIC
│
VM (vm-example / Ubuntu 24.04 LTS)
│
Subnet (snet-example: 10.0.0.0/24)
│
NSG (nsg-example) ← Subnetレベルでアタッチ
│
VNet (vnet-example: 10.0.0.0/16)3. ベストプラクティスな立て方の手順
以下の順番でリソースを作成する。前提として作業は全てAzure Portalで行うこととしている。
① Resource Group
② VNet + Subnet
③ NSG → ルール設定 → Subnetにアタッチ
④ Public IP
⑤ VM(既存のSubnetを指定)① Resource Groupの作成
- Azure Portal上部の検索バーで「リソース グループ」を検索し選択
- 「作成」をクリック
- 以下を入力して「確認および作成」→「作成」
| 項目 | 値 |
|---|---|
| サブスクリプション | 任意 |
| リソース グループ名 | rg-example |
| リージョン | Japan East |
② VNet + Subnetの作成
- 検索バーで「仮想ネットワーク」を検索し選択
- 「作成」をクリック
- 「基本」タブで以下を入力
| 項目 | 値 |
|---|---|
| リソース グループ | rg-example |
| 名前 | vnet-example |
| リージョン | Japan East |
- 「IPアドレス」タブで以下を設定
| 項目 | 値 |
|---|---|
| IPv4 アドレス空間 | 10.0.0.0/16 |
| サブネット名 | snet-example |
| サブネット アドレス範囲 | 10.0.0.0/24 |
- 「確認および作成」→「作成」
③ NSGの作成・ルール設定・Subnetへのアタッチ
- 検索バーで「ネットワーク セキュリティ グループ」を検索し選択
- 「作成」をクリック
- 以下を入力して「確認および作成」→「作成」
| 項目 | 値 |
|---|---|
| リソース グループ | rg-example |
| 名前 | nsg-example |
| リージョン | Japan East |
- 作成した
nsg-exampleを開く - 左メニューの「受信セキュリティ規則」→「追加」をクリック
- 以下を入力して「追加」
| 項目 | 値 |
|---|---|
| ソース | IP アドレス |
| ソースIPアドレス | 自分のグローバルIPアドレス(例: 203.0.113.10/32) |
| 宛先ポート範囲 | 22 |
| プロトコル | TCP |
| アクション | 許可 |
| 優先度 | 100 |
| 名前 | Allow-SSH-MyIP |
補足: 自分のグローバルIPは https://whatismyip.com などで確認できる。末尾の /32 はそのIPアドレス1つだけを指定する意味。nsg-exampleの左メニューから「サブネット」→「関連付け」をクリック- 以下を選択して「OK」
| 項目 | 値 |
|---|---|
| 仮想ネットワーク | vnet-example |
| サブネット | snet-example |
④ Public IPの作成
- 検索バーで「パブリック IP アドレス」を検索し選択
- 「作成」をクリック
- 以下を入力して「確認および作成」→「作成」
| 項目 | 値 |
|---|---|
| リソース グループ | rg-example |
| 名前 | pip-example |
| リージョン | Japan East |
| SKU | Standard |
| 割り当て | 静的 |
⑤ VMの作成(既存リソースを指定)
- 検索バーで「仮想マシン」を検索し選択
- 「作成」→「Azure仮想マシン」をクリック
| 項目 | 値 |
|---|---|
| リソース グループ | rg-example |
| 仮想マシン名 | vm-example |
| リージョン | Japan East |
| イメージ | Ubuntu Server 24.04 LTS |
| 認証の種類 | SSH 公開キー(推奨) |
| 項目 | 値 |
|---|---|
| 仮想ネットワーク | vnet-example(既存を選択) |
| サブネット | snet-example(既存を選択) |
| パブリック IP | pip-example(既存を選択) |
| NIC ネットワーク セキュリティ グループ | なし |
ポイント: NSGはSubnetレベルで既にアタッチ済みのため、NICレベルのNSGは「なし」に設定する。NICとSubnetの両方にNSGをアタッチすると二重管理になり、ルールの把握が困難になる。
- 「確認および作成」→「作成」
4. VMでまとめて作成した場合の手順と出来上がる構成
手順
VM作成画面の「ネットワーク」タブで各項目を「新規作成」のままにするだけで、VNet・Subnet・NSGが自動で作成される。
| 項目 | 自動生成される値 |
|---|---|
| 仮想ネットワーク | vm-example-vnet |
| サブネット | default |
| パブリック IP | vm-example-ip |
| NSG | vm-example-nsg |
出来上がる構成
Resource Group: rg-example
│
├── vm-example (VM)
├── vm-example_disk1 (OS Disk)
├── vm-example928 (NIC)
├── vm-example-ip (Public IP)
├── vm-example-nsg (NSG) ← NICレベルにアタッチ
└── vm-example-vnet (VNet)
└── Subnet: default (10.0.0.0/24)
└── NSGアタッチ: なし構成図
Internet
│
│ SSH(22) ← Any(インターネット全開放)
│ RDP(3389) ← Any(インターネット全開放)
│
Public IP (vm-example-ip)
│
NIC ──── vm-example-nsg(NSGがNICレベルに紐付き)
│
VM (vm-example / Ubuntu 24.04 LTS)
│
Subnet (default: 10.0.0.0/24) ← NSGなし
│
VNet (vm-example-vnet: 10.0.0.0/16)5. 問題点
まとめて作成した場合に発生する問題を、ベストプラクティスの構成と対比して説明する。
問題① NSGがNICレベルにアタッチされている
| まとめて作成 | ベストプラクティス | |
|---|---|---|
| NSGのアタッチ先 | NIC(VMごと) | Subnet(共通) |
| 複数VM追加時 | VMごとにNSGが増殖 | SubnetのNSG1つで制御 |
NICレベルのNSGはそのVM専用の設定になる。同じSubnetに2台目のVMを追加したとき、同じルールを持つNSGをもう1つ作ることになり、管理箇所が分散する。
【例:まとめて作成した場合に2台目を追加したケース】
Subnet (default)
├── vm-example ──── vm-example-nsg (SSH: Any許可)
└── vm-example2 ──── vm-example2-nsg (SSH: Any許可) ← 同じ設定のNSGが増殖
【ベストプラクティスの場合】
Subnet (snet-example) ──── nsg-example (SSH: 自分のIPのみ)
├── vm-example
└── vm-example2 ← SubnetのNSGで一元管理問題② SSH・RDPがデフォルトで全開放されている
まとめて作成すると、NSGに以下のルールが自動生成される。
Inbound Rules(自動生成)
┌─────────────┬──────────┬────────┐
│ Source │ Port │ Action │
├─────────────┼──────────┼────────┤
│ Any │ 22 (SSH) │ Allow │ ← インターネット全開放
│ Any │ 3389(RDP)│ Allow │ ← インターネット全開放
└─────────────┴──────────┴────────┘インターネット上の不特定多数からSSHの接続試行が行われ、ブルートフォース攻撃の対象になる。
ベストプラクティスでは接続元IPを自分のIPのみに限定する。
Inbound Rules(ベストプラクティス)
┌──────────────────┬──────────┬────────┐
│ Source │ Port │ Action │
├──────────────────┼──────────┼────────┤
│ 203.0.113.10/32 │ 22 (SSH) │ Allow │ ← 自分のIPのみ
└──────────────────┴──────────┴────────┘問題③ VM名に依存した命名になる
自動生成されるリソース名はすべてVM名を冠する。
vm-example-vnet ← ネットワークリソースなのにVM名が入っている
vm-example-nsg
vm-example-ipネットワークリソースはVMと独立して存在するべきものだが、名前がVMに紐付いてしまうため、後から構成を拡張する際に命名規則が崩れる。
問題④ VM削除時にネットワーク設定を誤って削除するリスク
まとめて作成するとすべてのリソースが同一Resource Groupに混在し、それぞれの依存関係が不明確になる。VMを削除しようとした際に、VNetやNSGまで一緒に削除してしまうミスが起きやすい。
事前に個別作成しておけば、「ネットワークリソースはVMとは別管理」という意識が構造として表れ、誤削除を防ぎやすくなる。
| 観点 | まとめて作成 | 事前に個別作成(ベストプラクティス) |
|---|---|---|
| NSGのアタッチ先 | NICレベル(VM専用) | Subnetレベル(共通管理) |
| SSH接続元 | Any(全開放) | 自分のIPのみ |
| リソースの命名 | VM名に依存 | 役割ベースで独立 |
| 複数VM追加時 | NSGが増殖・管理分散 | SubnetのNSGで一元管理 |
| VM削除時のリスク | ネットワーク設定も消す恐れあり | 独立しているため安全 |
| PoC・検証用途 | 許容範囲 | 推奨だが過剰な場合もある |
6. まとめ
- ネットワークリソース(VNet・Subnet・NSG)は、VMのライフサイクルとは独立して管理する必要があることを知った。
- ベストプラクティスである理由までセットで理解するとより理解度が深まると感じたため、今後意識していきたい。