本連載「ポイントを速習!『Azureの基礎(AZ900)』をみんなで学ぶ」では、FIXERの若手エンジニアたちがマイクロソフトの「Azureの基礎(AZ900)」公式ラーニングパスに沿いつつ、Azureを使ううえで覚えておくべき基礎的かつ重要なポイントだけ※をわかりやすくまとめます。実際に手を動かして学ぶハンズオンのコーナーもありますので、皆さんもぜひ一緒に学んでいきましょう。
(※ 本連載はAZ900試験の受験対策を目的としたものではなく、出題範囲すべてを網羅するものではありません)
はじめに
連載「ポイントを速習!『Azureの基礎(AZ900)』をみんなで学ぶ」の第13回目では、Microsoft Azure上のコンピュータシステムをセキュリティで保護するアプローチについて学んでいきます。
前編記事では、Azureのセキュリティ対策を行ううえで知っておく必要がある「複数のレベルの保護を行う多層防御の考え方」や「セキュリティ対策で提供される各サービス」、「Azureでセキュリティに取り組む上で理解すべき共有責任とその管理範囲」の概要を紹介しました。
今回の後編記事は実践編として、前編で学んだ内容に基づき、多層防御に含まれる「NSG(Network Security Group)」や「VNet Service Endpoint」をハンズオンで構築してみましょう。なお今回のハンズオンを行う前提として、Azureサブスクリプション(無料アカウントでも問題ありません)と、ネットワークやストレージ、仮想マシン(VM)に関する基本的な知識が必要になります。
今回の目次
●NSG(Network Security Group)とは
-セキュリティ規則の中身
●VNet Service Endpointとは
-類似サービス(Private Link)
●[実践]NSGを使って接続を制限する
●[実践]VNet Service Endpointを使ってリソース間接続を制御する
NSG(Network Security Group)とは
NSGを使うと、Azure VNet内のリソースが送受信するトラフィックをフィルター処理することができます。フィルター処理のルールである「セキュリティ規則」で定義された「送信元/送信先」「ポート」「プロトコル」などに基づき、I/Oトラフィックの通過を許可または拒否します。
ユーザーは、サブスクリプションで定められた任意の個数までセキュリティ規則を追加できます。また、あらかじめ何種類かのリソースとのI/Oトラフィックを許可/拒否するプリセットも準備されており、実現したい規則を手軽に適用できます。
セキュリティ規則の中身
セキュリティ規則の中身を見てみましょう。次のようなプロパティが定義されています。
一般には、通信元(Source)、通信元ポート、通信先(Destination)、通信先ポート、プロトコルという5組の情報を設定し、優先度(Priority)に基づいて通信の可否が判断されます。
注意点として、「同じ優先度」で「同じ送受信方向」のセキュリティ規則は作成できず、エラーが出ます。優先度が重複しないように設定してください。
VNet Service Endpointとは
VNet Service Endpoint(仮想ネットワークサービスエンドポイント。以下、VSE)は、Azureの内部インフラネットワーク上で最適化されたルートを介して、各種Azureリソースへ安全に直接接続ができるサービスです。
VSEを使用することで、重要なリソースへのアクセスをVNet内のみで完結させることができます。また、VNet内のプライベートIPは、VNet上のパブリックIPを必要とせずに、各種リソースのエンドポイントに接続できるようになっています。
VSEの主なメリットをまとめると、次のようになります。
●リソースのセキュリティが強化される
VSEでは、VNetのIDをAzureサービス単位に拡張することで、リソースのアクセス先をVNetのみに制限できます。VSEを適用したいVnetでアクセス規則を作成することで、パブリックインターネットからリソースにアクセスできないよう設定できます。
●VNet間の最適なルーティング
VSEを使うと、リソースのエンドポイントは常にVNetを通じてアクセスされます。そのトラフィックはすべてAzureの内部ネットワーク上を流れるため、強制トンネリングによりトラフィック自体に影響を与えることなく、監査や監視を行うことができるようになります。
●手軽な設定項目
IPアドレスベースのファイアウォールでリソースを保護するために、VNetで予約したパブリックIPを使う必要がなくなります。VSEの設定ではNATやゲートウェイを意識することなく、GUIを使ってサブネットを指定するだけで簡単に構築できるようになっています。
類似サービス(Private Link)
VSEに類似したサービスとして「Azure Private Link」というものもあります。これを使うと、VNetにあるプライベートエンドポイントやStandard LB(Load Balancer)の一部を使って、Azure内のリソースへ接続できるようになります。
Azure Private LinkでもVSEと同様に、VNetとリソース間のトラフィックはAzureの内部ネットワークを通るので、セキュリティやルーティング効率のうえでメリットがあります。また、Private Linkとモニタリングツールの「Azure Monitor」は連携できるので、データのログをアーカイブしたり、「Azure Event Hub」へのストリーム配信をしたりすることもできるようです。
「それならば、VNet Service EndpointとPrivate Linkは何が違うんだろう?」と思われる方も多いと思いますので、以下に比較表を置きます。Private Linkのほうが対応するリソースが多く、セキュリティや価格の面でも便利であるように見えますね。
[実践]NSGを使って接続を制限する
ここまで各機能の解説をしてきましたが、ここからはNSGを使って、実際に手を動かしながら通信の出入りをコントロールしてみましょう。
上記の図は、これから構築するリソース群の概要を示しています。アプリケーションサーバーからデータサーバーへアクセスするときにはHTTP通信を許可しますが、逆方向のデータサーバーからアプリケーションサーバーへのHTTP通信は拒否するというものです。
VNetとNSGを作成する
まず、Azure上にリソースグループ(以下、RG)とVNet、サブネットを作成し、その後にNSGを作ります。なお、以下ではCloud Shellターミナル(Bash)上でのコマンドライン操作となりますが、以下に掲載しているコマンドを適宜コピーして、ターミナルへ右クリックでペーストすると便利です。
1. Azure Portalの右上のボタン①からCloud Shellターミナル(Bash)を開き、リソースを作成したいサブスクリプションのあるディレクトリにログインします。ディレクトリ名は、右上のディレクトリ選択ボタン②から確認できる「~.onmicrosoft.com」で終わる文字列になるので、以下のコマンドラインの部分に入れて下さい。
az login --tenant 2. 今回のリソース群をデプロイするリージョン名を選びます。たとえば東日本リージョンならば「japaneast」です。その他のリージョン名は、以下のコマンドで表示されるリストの「Name」カラムから選択してください。
az account list-locations -o table 3. RG名を入れる変数(rg)を設定したうえで、RGを作成します。《rg name》部分にはお好みのRG名を、《location》部分には「japaneast」など先ほど選んだデプロイ先リージョン名を入れて、次のコマンドを実行します。
rg=《rg name》 az group create --name $rg --location 《location》 4. 「servers」という名前のVNetと「Apps」というサブネットを作成するために、次のコマンドを実行します。
az network vnet create \ --resource-group $rg \ --name servers \ --address-prefixes 10.0.0.0/16 \ --subnet-name Apps \ --subnet-prefixes 10.0.0.0/24 5. 4.で作成したservers VNet内に、もうひとつの「DBs」サブネットを作成するために、次のコマンドを実行します。
az network vnet subnet create \ --resource-group $rg \ --vnet-name servers \ --address-prefixes 10.0.1.0/24 \ --name DBs 6. 最後に「SERVERS-NSG」というNSGを作成するために、次のコマンドを実行します。
az network nsg create \ --resource-group $rg \ --name SERVERS-NSG
Linux VMを作成する
続いて、NSGのテストのためにUbuntuのVMを2つ作成します。VMの名前は「AppServer」 と「DataServer」にしましょう。
AppServer VMはAppsサブネットに、DataServer VMはDBs サブネットに、それぞれデプロイします。そのうえで、各VMのVIF(仮想ネットワークインターフェース)をSERVERS-NSGに追加することで、NSGの管理下とします。
1. AppServer VMをビルドするために、次のコマンドを実行して下さい。なお、VMの管理者アカウントのパスワードとして、《password》部分にお好みのパスワードを追加して下さい。
wget -N https://raw.githubusercontent.com/MicrosoftDocs/mslearn-secure-and-isolate-with-nsg-and-service-endpoints/master/cloud-init.yml && \ az vm create \ --resource-group $rg \ --name AppServer \ --vnet-name servers \ --subnet Apps \ --nsg SERVERS-NSG \ --image UbuntuLTS \ --size Standard_DS1_v2 \ --admin-username azureuser \ --custom-data cloud-init.yml \ --no-wait \ --admin-password "《password》" 2. DataServer VMも同様にビルドします。
az vm create \ --resource-group $rg \ --name DataServer \ --vnet-name servers \ --subnet DBs \ --nsg SERVERS-NSG \ --size Standard_DS1_v2 \ --image UbuntuLTS \ --admin-username azureuser \ --custom-data cloud-init.yml \ --admin-password "《password》" 3. VMが起動するまでには数分ほど時間がかかります。デプロイの進捗を確認するために、次のコマンドを実行してください。AppServer、DataServerのそれぞれがプロビジョニング成功(Succeeded)しており、パワーステートが「VM running」になっていれば大丈夫です。
az vm list \ --resource-group $rg \ --show-details \ --query "[*].{Name:name, Provisioned:provisioningState, Power:powerState}" \ --output table
既定の規則を使って接続を確認
VMが用意できたら、それぞれのVMに対してSSHセッションが確立できるか試してみましょう。
1. ここまで使ってきたCloud ShellターミナルからSSH接続を行います。そのために2つのVMのパプリックIPアドレスが必要になるため、まずは次のコマンドを実行してください。
az vm list \ --resource-group $rg \ --show-details \ --query "[*].{Name:name, PrivateIP:privateIps, PublicIP:publicIps}" \ --output table 2. このあと何度もパブリックIPを使うことになるので、それぞれ変数(APPSERVERIP、DATASERVERIP)に保存しておきます。次の2つのコマンドを実行して下さい。
APPSERVERIP="$(az vm list-ip-addresses \ --resource-group $rg \ --name AppServer \ --query "[].virtualMachine.network.publicIpAddresses[*].ipAddress" \ --output tsv)" DATASERVERIP="$(az vm list-ip-addresses \ --resource-group $rg \ --name DataServer \ --query "[].virtualMachine.network.publicIpAddresses[*].ipAddress" \ --output tsv)" 3. 各VMにSSH接続できるかどうか、sshコマンドで試してみましょう。 次の2つのコマンドを実行します。
ssh azureuser@$APPSERVERIP -o ConnectTimeout=5 ssh azureuser@$DATASERVERIP -o ConnectTimeout=5 するとどうでしょう。「Connection timed out」というエラーメッセージが表示されたと思います。ここで、先ほどSERVERS-NSGをデプロイした際(「VNetとNSGを作成する」の6.)には特段何も指定せず、規定の規則でデプロイしたことを思い出してみてください。
特に何も指定せずデプロイしたNSGでは、規定の規則群に含まれる「Deny All Inbound」という規則によって、VNetへの受信(インバウンド)方向のトラフィックはすべて拒否するように設定されています。これにより、SSH接続がブロックされたわけです。
SSHのセキュリティ規則を作成
VMへのSSH接続が拒否された理由がわかったので、次はSERVERS-NSGにセキュリティ規則を追加して、各VMにSSH接続できるように設定を変更してみましょう。
1. SSHでのアクセスを有効にするセキュリティ規則を作成するために、次のコマンドを実行して下さい。
az network nsg rule create \ --resource-group $rg \ --nsg-name SERVERS-NSG \ --name AllowSSHRule \ --direction Inbound \ --priority 100 \ --source-address-prefixes '*' \ --source-port-ranges '*' \ --destination-address-prefixes '*' \ --destination-port-ranges 22 \ --access Allow \ --protocol Tcp \ --description "Allow inbound SSH" 2. もう一度、AppServer VMにSSH接続を実行してみます。なお、NSGの規則は有効になるまでに数分かかる場合があるため、接続エラーが出た場合は少し時間を置いてから、もう一度やり直してみてください。
ssh azureuser@$APPSERVERIP -o ConnectTimeout=5 3. 接続できるようになったら、接続を続行するかどうかを尋ねられるので「yes」を入力して下さい。パスワード入力が求められたら、AppServer VMの作成時(「Linux VMを作成する」の1.)に設定したパスワードを入力します。
4. これでAppServer VMへのSSH接続は成功です。SSHセッションを閉じるために、「exit」コマンドを実行してください。
5. 以上の2.~4.をDataServer VMに対しても試してみてください。同様の結果が得られるはずです。
HTTPアクセスを禁止する規則を追加
続いて、SERVERS-NSGに「AppServerからはHTTP経由でDataServerと通信できるが、DataServerからはHTTP経由でAppServerと通信できない」という規則を追加します。なお、ここで確認しておきますが、AppServerの内部IPは「10.0.0.4」、DataServerの内部IPは「10.0.1.4」となっています。
1. 80番ポートでのHTTPアクセスを拒否する新しいセキュリティ規則を作成するために、次のコマンドを実行して下さい。
az network nsg rule create \ --resource-group $rg \ --nsg-name SERVERS-NSG \ --name httpRule \ --direction Inbound \ --priority 150 \ --source-address-prefixes 10.0.1.4 \ --source-port-ranges '*' \ --destination-address-prefixes 10.0.0.4 \ --destination-port-ranges 80 \ --access Deny \ --protocol Tcp \ --description "Deny from DataServer to AppServer on port 80"
VM間のHTTP接続を確認
SERVERS-NSGに新しい規則を追加したので、正しく動作しているかどうかを確認します。先ほどの設定どおりならば、AppServerはHTTPS経由でDataServerへ接続できるはずです。
1. まず、AppServer VMへSSH接続してwgetコマンドを実行し、HTTP経由でDataServerへ接続できるかどうかを確認します。次のコマンドを実行してください。
ssh -t azureuser@$APPSERVERIP 'wget http://10.0.1.4; exit; bash' 2. AppServer VMを作成した際のパスワードを入力すると、すぐに"200 OK"レスポンスが表示されるはずです。つまり、AppServerからDataServerへは、HTTP経由で接続できることが確認できました。
3. 続いて、同じようにDataServerへSSH接続し、先ほどとは逆方向のHTTP通信を試します。次のコマンドを実行してください。
ssh -t azureuser@$DATASERVERIP 'wget http://10.0.0.4; exit; bash' 4. DataServer VMを作成した際のパスワードを入力すると、今度は「Connecting to 10.0.0.4:80...」と表示されたまま何も起こらず、数分後に「Connection timed out」と表示されるはずです(このままリトライを繰り返すので、Ctrl+Cキーでコマンド実行を中止してください)。
これは、先ほど追加したSERVERS-NSGの規則でDataServerからAppServerへのHTTP(ポート80)アクセスがブロックされているため、接続がタイムアウトしたのです。
ASG(Application Security Group)をデプロイ
先ほど追加したSERVERS-NSGのセキュリティ規則では、DataServerの内部IP(10.0.1.4)を直接指定して、このIPアドレスからAppServerへのHTTP通信を拒否するよう設定されていました。しかし、もっと多くのDBサーバーをデプロイする場合、それぞれのIPアドレスに対応する規則を1つずつ作成していくのでは不便です。
そこで最後に、DBサーバー用のASG(Application Security Group)を作成し、そのグループ内に所属するすべてのサーバーに対して、同じセキュリティ規則を割り当てられるようにしてみましょう。これでいくつか手間が減ることになりますね。なおこの場合、ASGには管理するVMのVIFを割り当てる必要があります。
1. DB-SERVERS-ASGという新規のASGを作成するために、次のコマンドを実行します。
az network asg create \ --resource-group $rg \ --name DB-SERVERS-ASG 2. DataServerとDB-SERVERS-ASGを関連付けるために、次のコマンドを実行して下さい。
az network nic ip-config update \ --resource-group $rg \ --application-security-groups DB-SERVERS-ASG \ --name ipconfigDataServer \ --nic-name DataServerVMNic \ --vnet-name servers \ --subnet DBs 3. 先に作成したSERVERS-NSGの「httpRule」セキュリティ規則を、DB-SERVERS-ASGに属するサーバーからAppServerへのHTTP通信を拒否する規則に更新します。次のコマンドを実行してください。
az network nsg rule update \ --resource-group $rg \ --nsg-name SERVERS-NSG \ --name httpRule \ --direction Inbound \ --priority 150 \ --source-address-prefixes "" \ --source-port-ranges '*' \ --source-asgs DB-SERVERS-ASG \ --destination-address-prefixes 10.0.0.4 \ --destination-port-ranges 80 \ --access Deny \ --protocol Tcp \ --description "Deny from DataServer to AppServer on port 80 using application security group"
更新したセキュリティ規則を確認
更新したセキュリティ規則が正しく機能しているかどうかを確認しましょう。先ほど(「VM間のHTTP接続を確認」の項)と同じ、次の2つのコマンドを順に実行します。
ssh -t azureuser@$APPSERVERIP 'wget http://10.0.1.4; exit; bash' ssh -t azureuser@$DATASERVERIP 'wget http://10.0.0.4; exit; bash' すると、同じようにAppServerからはHTTP接続ができ、DataServerからはHTTP接続ができないことがわかります。これで、通信元IPアドレスの代わりにASGで指定したNSGのセキュリティ規則も、正しく機能することが確認できました。
2台目、3台目のDBサーバーをデプロイした場合は、この項の2.で示した方法で新しいサーバーをDB-SERVERS-ASGに追加するだけで、簡単に適切なセキュリティを追加できます。
以上でNSGのハンズオンは終わりです。ただし、これまで作成した環境(リソース群)は次のハンズオンでも使いますので、まだ消さずに残しておいてください。
[実践]VNet Service Endpointを使ってリソース間接続を制御する
続いて、VNet Service Endpoint(VSE)の構築ハンズオンをやっていきたいと思います。
上記の図は、VSEをVNet内に作成し、ネットワーク規則を用いてVNet外にあるAzure Storageへのアクセスをバイパスさせていることを示します。ただしここでは、DataServer VMのあるDBsサブネットからのみ、Azure Storageへアクセスできるよう制限する設定を行います。
NSGに規則を追加
まずはNSGに規則を追加して、VNetからAzure Storageへの通信が確実にVSEを通過するよう設定します。具体的には「このVNetからStorageサービスへの外向き(アウトバウンド)方向の通信は許可するが、その他すべてのインターネット通信は拒否する」という規則です。
1. Storageへのアクセスを許可するアウトバウンド規則を作るために、次のコマンドを実行します。
az network nsg rule create \ --resource-group $rg \ --nsg-name SERVERS-NSG \ --name Allow_Storage \ --priority 190 \ --direction Outbound \ --source-address-prefixes "VirtualNetwork" \ --source-port-ranges '*' \ --destination-address-prefixes "Storage" \ --destination-port-ranges '*' \ --access Allow \ --protocol '*' \ --description "Allow access to Azure Storage" 2. 「すべてのインターネット通信を拒否」するアウトバウンド規則を作るために、次のコマンドを実行してください。
az network nsg rule create \ --resource-group $rg \ --nsg-name SERVERS-NSG \ --name Deny_Internet \ --priority 200 \ --direction Outbound \ --source-address-prefixes "VirtualNetwork" \ --source-port-ranges '*' \ --destination-address-prefixes "Internet" \ --destination-port-ranges '*' \ --access Deny \ --protocol '*' \ --description "Deny access to Internet." 前のハンズオンと合わせて、ここまでにSERVERS-NSGには次の規則が設定されているはずです。これにより、現時点ではAppServerからでもDataServerからでも、Azure Storageにアクセスすることができます。
Storage AccountとFile Shareを構成
次に、アクセス確認テスト用のリソースを用意しましょう。新しいStorage Accountを作成したあとに「Azure File Share」を構成します。このFile Shareは、ファイルを保存して共有できる、ファイルサーバーのようなサービスです。
1. Storage Accountを作成するために、次のコマンドを実行します。実行すると、変数STORAGEACCTにはStorage Account名が格納されます。
STORAGEACCT=$(az storage account create \ --resource-group $rg \ --name handsondocs$RANDOM \ --sku Standard_LRS \ --query "name" | tr -d '"') 2.. 次に、Storageのprimary keyを変数STORAGEKEYへ格納するために、次のコマンドを実行して下さい。
STORAGEKEY=$(az storage account keys list \ --resource-group $rg \ --account-name $STORAGEACCT \ --query "[0].value" | tr -d '"') 3.. 「handson-data-share」という名称のFile Shareを構成するために、次のコマンドを実行します。
az storage share create \ --account-name $STORAGEACCT \ --account-key $STORAGEKEY \ --name "handson-data-share"
VSEを有効にする
続いて、Storage Accountを修正して、DataServerからのみアクセスできるようにします。具体的には、DBsサブネットにStorageのVSEを割り当て、その後にStorage Account側にネットワーク規則を設定します。
1. 「Microsoft.Storage」という名前のVSEをDBsサブネットに割り当てるために、次のコマンドを実行して下さい。
az network vnet subnet update \ --vnet-name servers \ --resource-group $rg \ --name DBs \ --service-endpoints Microsoft.Storage 2. いったんすべてのネットワークkからStorage Accountへのアクセスができなくなるように、規定のアクションを「拒否(Deny)」に設定します。
az storage account update \ --resource-group $rg \ --name $STORAGEACCT \ --default-action Deny 3. そのうえで、Storage Accountへのアクセス制限を設定するために、次のコマンドを実行します。これにより、DBsサブネットからの通信のみを受信するように制限されます。
az storage account network-rule add \ --resource-group $rg \ --account-name $STORAGEACCT \ --vnet servers \ --subnet DBs
File Shareへの通信を確認
それでは、Storage AccountでDataServerのみがFile Shareにアクセスできるか確認してみましょう。
1. AppServerとDataServerのパブリックIPを変数に格納するために、次の2つのコマンドを実行してください。
APPSERVERIP="$(az vm list-ip-addresses \ --resource-group $rg \ --name AppServer \ --query "[].virtualMachine.network.publicIpAddresses[*].ipAddress" \ --output tsv)" DATASERVERIP="$(az vm list-ip-addresses \ --resource-group $rg \ --name DataServer \ --query "[].virtualMachine.network.publicIpAddresses[*].ipAddress" \ --output tsv)" 2. AppServer VMにSSH接続し、File Shareのマウントを行うために、次のコマンドを実行します。
ssh -t azureuser@$APPSERVERIP \ "mkdir azureshare; \ sudo mount -t cifs //$STORAGEACCT.file.core.windows.net/handson-data-share azureshare \ -o vers=3.0,username=$STORAGEACCT,password=$STORAGEKEY,dir_mode=0777,file_mode=0777,sec=ntlmssp; findmnt \ -t cifs; exit; bash" 3. VM作成時のパスワードを入力すると「mount error」が表示されます。これは、AppsサブネットにはStorage AccountのVSEがないため、AppServerからFile Shareへのアクセスが拒否されているのです。
4. 同じことをDataServer VMで試してみると、どうなるでしょうか。
ssh -t azureuser@$DATASERVERIP \ "mkdir azureshare; \ sudo mount -t cifs //$STORAGEACCT.file.core.windows.net/handson-data-share azureshare \ -o vers=3.0,username=$STORAGEACCT,password=$STORAGEKEY,dir_mode=0777,file_mode=0777,sec=ntlmssp;findmnt \ -t cifs; exit; bash" 5. VM作成時のパスワードを入力すると、今度はmountに成功した旨の詳細が表示されるはずです。これは、DBsサブネットにStorage Account用のVSEが作成されているからです。
以上で、VSEを使ってリソース間の接続を制御できることが確認できました。
* * *
以上、今回はNSGやVNet Service Endpointの解説と構築を行いました。非常に長くなってしまいましたが、いかがだったでしょうか。多層防御の一部分をなすこれらのリソースの理解に少しでも役立てば幸いです。
さて、13回にわたって連載してきた「ポイントを速習!『Azureの基礎(AZ900)』をみんなで学ぶ」は、今回が最終回となります。次回からは新連載として、Azure Cognitiveサービス(AIサービス)の基礎を学ぶシリーズをお届けする予定です。引き続きよろしくお願いいたします!
■今回のポイントまとめ!
NSGでトラフィックを制御する規則を作ると、VNetやVMをインターネットからのアクセスから保護できる VNet Service Endpointを使うと、SQL DatabaseやAzure StorageなどのAzureリソースを保護できる FIXER Inc. 椎名 泰之
社会人1年目の出来立てほやほやエンジニア。環境構築が大好物で、嫌いなものはMerge Conflict。仕事を始めても結局ゲームはやめられないらしい……。
■参考資料・関連サイト
NSGとVSEを使うことでAzureリソースへのアクセスをセキュリティで保護し、分離する(MS Learn) ネットワーク セキュリティ グループ(Azure製品ドキュメント) 仮想ネットワーク サービス エンドポイント(Azure製品ドキュメント) Azure Private Link とは(Azure製品ドキュメント)