クラウドにサーバーを立てた直後にこういった不安を感じるのは、現場エンジニアなら誰しも経験することです。パブリッククラウドの検証サーバーは、オンプレと違ってインターネットから直接アクセスできる状態で起動します。ファイアウォール相当の設定を後回しにすると、SSH辞書攻撃のログが大量に積み上がります。
この記事では、AzureのLinux VMに対してSSH公開鍵認証を設定し、NSG(ネットワークセキュリティグループ)で接続元IPを絞り込む実践的な手順を解説します。Azure CLIとAzureポータル両面から操作し、設定後の動作確認まで一通り追えるよう構成しました。NSGのデフォルト規則の仕組みから、複数拠点対応のTips、AWSセキュリティグループとの設計の違いまでカバーします。
この記事のポイント
・Azure NSGの受信セキュリティ規則でSSHを特定IPに限定できる
・SSH公開鍵認証をAzure CLIで後から追加する手順を実機で確認
・パスワード認証を無効化してブルートフォース攻撃を根本から防ぐ
・NSG規則の優先度(Priority)で複数IP許可・全IP拒否を組み合わせる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
AzureのNSGとは何か|Linuxのfirewalldとどこがちがうのか
NSG(Network Security Group)はAzureが提供するL4レベルのフィルタリング機能で、送信元IP・プロトコル・ポートの組み合わせで通信の許可/拒否を制御します。オンプレミスでいうと「サーバーの外側に置かれたルーターのACL」に近いイメージです。Linuxの
firewalldやiptablesはサーバー内部で動くのに対し、NSGはAzureのネットワーク基盤側で動きます。つまりNSGで拒否されたパケットはVM自体には届かず、journalctlにも残りません。NSGには2つのアタッチポイントがあります。
・NIC(ネットワークインターフェイス)に紐付け:そのVMだけに適用される
・サブネットに紐付け:同じサブネット内の全VMに一括適用される
本記事では「NICに紐付けたNSGで特定VMを個別制御する方法」を扱います。
規則は優先度(Priority)の数値が小さいほど先に評価されます。100~4096の範囲で指定でき、同じ優先度は設定できません。「許可する規則を低い番号に、拒否する規則を高い番号に」と覚えてください。
NSGを作成したときに自動で存在するデフォルト規則
NSGを作成すると、削除できないデフォルト規則が自動で設定されます。カスタム規則はこのデフォルトより小さい優先度番号(高い優先度)で追加していきます。| 優先度 | 規則名 | 方向 | 送信元 | 宛先 | 処理 |
|---|---|---|---|---|---|
| 65000 | AllowVnetInBound | インバウンド | VirtualNetwork | VirtualNetwork | Allow |
| 65001 | AllowAzureLoadBalancerInBound | インバウンド | AzureLoadBalancer | * | Allow |
| 65500 | DenyAllInBound | インバウンド | * | * | Deny |
| 65000 | AllowVnetOutBound | アウトバウンド | VirtualNetwork | VirtualNetwork | Allow |
| 65001 | AllowInternetOutBound | アウトバウンド | * | Internet | Allow |
| 65500 | DenyAllOutBound | アウトバウンド | * | * | Deny |
SSH規則(優先度1000)を自動で追加するためです。なぜSSH公開鍵認証が必須なのか|パスワード認証の危険性を数字で見る
Azure上でパスワード認証を有効にしたまま22番ポートを全IPに開けておくと、数十分で辞書攻撃が始まります。実際の検証サーバーのSSH認証ログを見ると:# journalctl -u sshd --since "1 hour ago" | grep "Failed password" | wc -l 2347 # journalctl -u sshd --since "1 hour ago" | grep "Failed password" | awk '{print $11}' | sort | uniq -c | sort -rn | head -5 312 198.xx.xx.xx 287 45.yy.yy.yy 201 103.zz.zz.zz 89 185.aa.aa.aa 67 91.bb.bb.bb
公開鍵認証に切り替えると、鍵ファイルを持たない接続は一切認証に進めないため、辞書攻撃は根本的に無効化されます。NSGで接続元IPを絞ることで、鍵が漏洩した場合の被害も最小化できます。
SSH公開鍵認証の設定手順|Azure CLIを使う方法
1. ローカルマシンでSSH鍵ペアを生成する
まずローカルの作業PCでED25519鍵ペアを生成します。RSA 2048bitより短く、セキュリティ強度は高い現在の推奨方式です。# 実行環境: ローカルPC(Windows WSL2 / macOS / Linux) ssh-keygen -t ed25519 -C "azure-linuxvm-key" -f ~/.ssh/azure_vm_key # 出力例 Generating public/private ed25519 key pair. Enter passphrase (empty for no passphrase): (パスフレーズを入力。空はNG) Enter same passphrase again: Your identification has been saved in /home/user/.ssh/azure_vm_key Your public key has been saved in /home/user/.ssh/azure_vm_key.pub The key fingerprint is: SHA256:xXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxX azure-linuxvm-key
azure_vm_key(秘密鍵)はローカルから絶対に持ち出さないこと。 Azureに登録するのはazure_vm_key.pub(公開鍵)だけです。2. 既存VMに公開鍵を追加する(Azure CLI)
VMがすでに稼働している場合、az vm user updateコマンドで公開鍵を追加します。# 実行環境: Azure Cloud Shell または az CLI が使えるローカル環境 # RHEL 9.4 / Ubuntu 24.04 LTS の Azure VMで動作確認済み # 変数を設定 RG="myResourceGroup" VM_NAME="myLinuxVM" USERNAME="azureuser" PUBKEY_PATH="~/.ssh/azure_vm_key.pub" # 公開鍵を既存VMに追加 az vm user update --resource-group "$RG" --name "$VM_NAME" --username "$USERNAME" --ssh-key-value "$(cat $PUBKEY_PATH)" # 出力例(成功時) { "homeDirectory": "", "password": null, "sshAuthorizedKeys": [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB... azure-linuxvm-key" ], "username": "azureuser" }
3. VM側でパスワード認証を無効化する
公開鍵を追加した後、VM内でSSHデーモンの設定を変更してパスワード認証を無効にします。# 公開鍵認証でVMにログイン(変更前に必ず成功を確認すること) ssh -i ~/.ssh/azure_vm_key azureuser@xx.xx.xx.xx # 以下はVM内での作業 # PasswordAuthentication を no に変更 sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config # 設定確認 grep "PasswordAuthentication" /etc/ssh/sshd_config # 出力例 PasswordAuthentication no # SSHデーモンを再起動 sudo systemctl restart sshd # 再起動後もサービスが正常か確認 sudo systemctl status sshd | grep "Active:" # 出力例 Active: active (running) since Sat 2026-06-27 10:15:33 UTC; 3s ago
sshd再起動前に、公開鍵認証でのログインが成功することを別のターミナルで確認してください。ログインできないままパスワード認証を無効にするとVMにアクセスできなくなります。NSGで接続元IPを絞り込む手順|Azure CLI実践
1. 現在のNSGと規則を確認する
# VMに紐付いたNSG名を確認 az network nic show --resource-group "$RG" --name "${VM_NAME}VMNic" --query "networkSecurityGroup.id" --output tsv # 出力例 /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.Network/networkSecurityGroups/myLinuxVMNSG NSG_NAME="myLinuxVMNSG" # 現在の受信セキュリティ規則を一覧表示 az network nsg rule list --resource-group "$RG" --nsg-name "$NSG_NAME" --output table # 出力例(デフォルト状態) Name ResourceGroup Priority SourceAddressPrefixes SourcePortRanges DestinationAddressPrefixes DestinationPortRanges Protocol Access Direction ----------------------- --------------- ---------- ----------------------- ------------------ ---------------------------- ----------------------- ---------- -------- ----------- SSH myResourceGroup 1000 * * * 22 TCP Allow Inbound
*(全IP)からSSHを許可しています。これを自分のIPに限定します。2. 接続元IPを許可する規則を追加する
# 自分のグローバルIPアドレスを確認(ローカルPCから実行) curl -s https://ifconfig.me # 出力例 203.0.113.45 MY_IP="203.0.113.45" # 許可規則を追加(優先度100 = 最優先で評価) az network nsg rule create --resource-group "$RG" --nsg-name "$NSG_NAME" --name "Allow-SSH-MyIP" --priority 100 --protocol Tcp --direction Inbound --source-address-prefixes "$MY_IP" --source-port-ranges "*" --destination-address-prefixes "*" --destination-port-ranges 22 --access Allow # 出力例(成功時) { "access": "Allow", "destinationPortRange": "22", "name": "Allow-SSH-MyIP", "priority": 100, "protocol": "Tcp", "sourceAddressPrefix": "203.0.113.45", ... }
3. 全IPからのSSHを拒否する規則を追加する
# 全IPからのSSHを拒否(優先度200 = Allow-SSH-MyIPの後に評価) az network nsg rule create --resource-group "$RG" --nsg-name "$NSG_NAME" --name "Deny-SSH-All" --priority 200 --protocol Tcp --direction Inbound --source-address-prefixes "*" --source-port-ranges "*" --destination-address-prefixes "*" --destination-port-ranges 22 --access Deny # 設定後の規則を確認 az network nsg rule list --resource-group "$RG" --nsg-name "$NSG_NAME" --output table # 出力例(設定後) Name Priority SourceAddressPrefixes DestinationPortRanges Access ----------------------- ---------- ----------------------- ----------------------- -------- Allow-SSH-MyIP 100 203.0.113.45 22 Allow Deny-SSH-All 200 * 22 Deny SSH 1000 * 22 Allow
Allow-SSH-MyIPが先に評価されるため、203.0.113.45からのSSHは許可されます。それ以外のIPは優先度200のDeny-SSH-Allで拒否されます(優先度1000の既存SSH規則には到達しません)。4. 動作確認|許可・拒否の両方をテストする
# 許可されたIPからのSSH接続確認(成功するはず) ssh -i ~/.ssh/azure_vm_key -o ConnectTimeout=10 azureuser@xx.xx.xx.xx # 出力例 Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-1021-azure x86_64) Last login: Sat Jun 27 10:15:33 2026 from 203.0.113.45 # 別のIPからの接続を試みる場合(Azure Cloud Shellからテスト) # Cloud Shellは異なるIPのため拒否される ssh -o ConnectTimeout=10 azureuser@xx.xx.xx.xx # 出力例(NSGに拒否された場合) ssh: connect to host xx.xx.xx.xx port 22: Connection timed out
5. Network WatcherのIP Flow Verifyでルール有効性を事前確認する
実際に通信する前に「このNSG規則で通るか・拒否されるか」を検証できるのがIP Flow Verifyです。設定ミスによるロックアウトリスクを減らすために、規則追加後に必ず確認する習慣をつけてください。# 203.0.113.45 から vm の 22番ポートへのインバウンド通信可否を確認 az network watcher test-ip-flow --vm "$VM_NAME" --resource-group "$RG" --direction Inbound --protocol TCP --local xx.xx.xx.xx:22 --remote 203.0.113.45:* # 出力例(許可されている場合) { "access": "Allow", "ruleName": "Allow-SSH-MyIP" } # 出力例(拒否されている場合) { "access": "Deny", "ruleName": "Deny-SSH-All" }
ruleNameフィールドで「どの規則が適用されたか」が明示されるので、優先度の設定ミスをすぐに発見できます。想定外のルールが適用されていた場合はaz network nsg rule update --priorityで優先度の数値を調整してください。複数拠点から接続したい場合の応用Tips
オフィスと自宅の両方からアクセスしたい場合、--source-address-prefixesにCIDR形式で複数のIPまたは範囲を指定します。# 複数のIPアドレスを1つの規則で許可(スペース区切り) az network nsg rule update --resource-group "$RG" --nsg-name "$NSG_NAME" --name "Allow-SSH-MyIP" --source-address-prefixes "203.0.113.45" "198.51.100.20" # サブネット全体を許可する場合(例: 社内ネットワーク 10.0.0.0/24) az network nsg rule update --resource-group "$RG" --nsg-name "$NSG_NAME" --name "Allow-SSH-MyIP" --source-address-prefixes "203.0.113.45" "10.0.0.0/24"
・JITアクセスの利点:SSHポートを常時開放しなくて済む
・JITアクセスの欠点:Microsoft Defender for Cloud(旧 Azure Security Center)の有効化が必要でコストが増える
本番環境ではJITの導入を検討し、開発・検証サーバーはNSGによるIP制限で運用するのが現実的なバランスです。
サービスタグを使ったIP管理の省力化
NSGの規則では、個別のIPアドレスを列挙する代わりにサービスタグを使えます。サービスタグはAzureが管理するIPアドレスグループを表す識別子で、AzureがIPレンジを自動更新するためルールを変更する必要がありません。・VirtualNetwork:ピアリング済みVNetを含むVNet全体を表す
・Internet:VirtualNetworkに含まれない全IPアドレス(インターネット全体)
・AzureLoadBalancer:Azureロードバランサーのヘルスチェック送信元IP
・AzureCloud:AzureのパブリックIPアドレス全体
・Sql:Azure SQL Database / Azure Synapse のIPアドレス範囲
・Storage:Azure Blob Storage / Azure Files のIPアドレス範囲
例えばWebサーバー用にインターネット全体からHTTPS(443)を許可したい場合、
--source-address-prefix Internetとするだけで済みます。IPアドレスを手動で管理するよりメンテナンスコストを大幅に下げられます。AWSセキュリティグループとAzure NSGの比較
AWSにも同様の機能「Security Group(SG)」が存在します。どちらもステートフルなL4ファイアウォールですが、設計の考え方に重要な違いがあります。AWSから移行する場合や両環境を並行運用する場合は、この違いを押さえておくと混乱を防げます。| 比較項目 | AWS Security Group | Azure NSG |
|---|---|---|
| 適用場所 | ENI(NIC)のみ | NIC またはサブネット(両方も可) |
| 規則種別 | Allowのみ(暗黙のDeny) | Allow と Deny の両方が設定できる |
| 評価方式 | 全Allowルールを評価して1つでも合致すればAllow | 優先度順に評価し、最初にマッチした規則で確定 |
| グループ参照 | 別SGをソースに指定できる | Application Security Group(ASG)で対応 |
| ステートフル | はい | はい |
| インバウンドの既定 | 全拒否(暗黙のDeny) | 全拒否(DenyAllInBound、ただしVNet内はAllow) |
| アウトバウンドの既定 | 全許可 | 全許可(AllowInternetOutBound) |
| CLIコマンド | aws ec2 authorize-security-group-ingress | az network nsg rule create |
また、AWSのSGはENI(NIC)にのみ適用できますが、AzureのNSGはサブネットにも適用できるため、サブネット単位でのポリシー統一が容易です。VNet設計でサブネットを役割別(Web層・AP層・DB層)に分けている場合、NSGをサブネット単位で適用するのが実務上の標準構成になります。
NSG設定のよくあるトラブルと対処法
「Connection timed out」になって自分のIPからも繋がらない
考えられる原因は2つです。・グローバルIPが変わっている:プロバイダによっては動的IPのため、再度
curl -s https://ifconfig.meで確認してNSG規則を更新する・サブネットにも別のNSGが紐付いている:NIC単体のNSGは許可していても、サブネット側NSGが拒否しているケース。
az network vnet subnet showでサブネットのNSGも確認する# サブネットに紐付いたNSGを確認 az network vnet subnet show --resource-group "$RG" --vnet-name "myVNet" --name "mySubnet" --query "networkSecurityGroup.id" --output tsv # 出力例(NSGなし) None # 出力例(NSGあり) /subscriptions/xxx.../networkSecurityGroups/mySubnetNSG
NSGは更新したのに反映されない
NSG規則の変更は通常数秒以内に反映されますが、キャッシュの影響で最大1分ほどかかることがあります。az network nsg rule showで規則が正しく更新されていることを確認してから、再度SSH接続を試みてください。PasswordAuthentication no にしたらVMに入れなくなった
AzureにはVM拡張機能(VMAccess)を使ってSSH公開鍵をリセットする仕組みがあります。# VMAccessを使ってSSH公開鍵をリセット(ロックアウト時の復旧手順) az vm user reset-ssh --resource-group "$RG" --name "$VM_NAME" # または新しい公開鍵を強制上書き az vm user update --resource-group "$RG" --name "$VM_NAME" --username "$USERNAME" --ssh-key-value "$(cat ~/.ssh/new_key.pub)"
本記事のまとめ
Azure Linux VMのセキュリティ設定について、NSGとSSH公開鍵認証の2段構えで保護する手順を解説しました。| やること | コマンド・設定 |
|---|---|
| ED25519鍵ペアを生成する | ssh-keygen -t ed25519 -f ~/.ssh/azure_vm_key |
| 既存VMに公開鍵を追加する | az vm user update --ssh-key-value "$(cat key.pub)" |
| パスワード認証を無効化する | PasswordAuthentication no + systemctl restart sshd |
| 自分のIPからのSSHを許可する | az network nsg rule create --access Allow --priority 100 |
| 全IPからのSSHを拒否する | az network nsg rule create --access Deny --priority 200 |
| NSG規則の疎通をテストする | az network watcher test-ip-flow --direction Inbound --protocol TCP |
| サブネットのNSGを確認する | az network vnet subnet show --query "networkSecurityGroup.id" |
| ロックアウト時に公開鍵をリセットする | az vm user reset-ssh または az vm user update |
Azure上でLinuxを安全に扱う技術はクラウドエンジニアの必須スキルです。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、AzureでのLinux VM運用を体系的に学びたいなら、Azure実践ハンズオン講座をご覧ください。NSG・SSH鍵認証から始まるセキュリティ設計を、現役エンジニアの実務視点で一気に習得できます。
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます