Azure Application Security Group(ASG)がPublic Previewになったので使ってみた

#はじめに
2017年9月末に開催されたIgnite 2017で発表がありました、Application Security Group(ASG)がPublic Previewで出ましたので早速使ってみました。

#ASGって？
誤解を恐れずに一言で表すなら「仮想マシンのIPアドレスをNSGでいちいち設定しなくても適当な名前(ラベル名)で解決できるよ」ってことです。

英語ドキュメントでの説明は [https://docs.microsoft.com/en-us/azure/virtual-network/security-overview#application-security-groups](https://docs.microsoft.com/en-us/azure/virtual-network/security-overview#application-security-groups?WT.mc_id=AZ-MVP-5002499) です。

#NSGのおさらい
##仮想マシンの用途別にサブネットを分ける場合
たとえば複数台のWebサーバとDBサーバが、種類毎に別のサブネットに配置されている場合↓↓

![image.png](https://qiita-image-store.s3.amazonaws.com/0/137436/9bd1de7c-2914-8d4c-5803-30d9c4965e23.png)


NSG-1にはWebサーバに関する受信ルールとして以下の設定をすると思います。

|Name|優先順位|発信元 IP|発信元ポート|宛先 IP|宛先ポート|プロトコル|Access (アクセス)|
|:---|---:|:---|---:|:---|---:|:---|:---|
|AllowHTTP|300|Internet|*|VirtualNetwork|80|TCP|Allow|
|AllowSSH|500|(自社のWAN側IP)|*|VirtualNetwork|22|TCP|Allow|

NSG-2も同様にDBサーバに関する受信ルールとして以下の設定をするかと。

|Name|優先順位|発信元 IP|発信元ポート|宛先 IP|宛先ポート|プロトコル|Access (アクセス)|
|:---|---:|:---|---:|:---|---:|:---|:---|
|AllowDB|300|(サブネット1のCIDR)|*|VirtualNetwork|1433|TCP|Allow|
|AllowSSH|500|(自社のWAN側IP)|*|VirtualNetwork|22|TCP|Allow|

「Webサーバ」「DBサーバ」と用途ごとに仮想ネットワークのサブネットを分ける設計であれば従来どおりの書き方で、サブネットに紐付けたNSGは受信ルールの宛先IPとして「VirtualNetwork」を指定すればサブネット内の全ての仮想マシンが対象となります。

##ひとつのサブネット内に用途が異なる仮想マシンが混在している場合
仮想マシンの用途毎に専用のNSGを準備して、個々の仮想マシンのNICに対してNSGを紐付ける方法がひとつ考えられますね。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/137436/a676c67f-6da1-b2cc-69a3-bfd49c1df549.png)

Web用、DB用それぞれのNSGを準備する必要があって、今後別の用途の仮想マシンが増えてくる事も考慮すると先々のメンテも大変そうです。

二番目の方法として、NSGをサブネットに対して紐付けて、一つのNSGの受信ルールに全ての用途別のルールを書く方法です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/137436/586d1480-3bd6-a56a-41a3-726b31b89edb.png)

仮想マシンの内部IPアドレスは必ず固定にする必要があります。
NSGは受信ルールとして以下の感じに設定します。

|Name|優先順位|発信元 IP|発信元ポート|宛先 IP|宛先ポート|プロトコル|Access (アクセス)|
|:---|---:|:---|---:|:---|---:|:---|:---|
|AllowDB1|300|192.168.0.10|*|192.168.0.20|1433|TCP|Allow|
|AllowDB2|301|192.168.0.11|*|192.168.0.20|1433|TCP|Allow|
|AllowDB3|302|192.168.0.10|*|192.168.0.21|1433|TCP|Allow|
|AllowDB4|303|192.168.0.11|*|192.168.0.21|1433|TCP|Allow|
|AllowWeb1|400|Internet|*|192.168.0.10|80|TCP|Allow|
|AllowWeb2|401|Internet|*|192.168.0.11|80|TCP|Allow|
|AllowSSH|500|(自社のWAN側IP)|*|VirtualNetwork|22|TCP|Allow|

NSGの設定の中に、仮想マシンのプライベートIPアドレスを全ての組み合わせで記載する必要があり、非効率です。

従来は上記の何れかの方法で細かいアクセス制御を実現する必要がありました。
今後はAzure Application Security Group(ASG)を使うと、NSG内で発信元IP、宛先IPの場所に任意のASGを指定してグルーピングできるようになります。

#ASGの簡単な説明
まず、新しいリソースとしてASGリソースをWeb用とDB用の2つ作成します。
NSGでは発信元IP、宛先IPに直接IPアドレスを書かずに、このASGを指定します。

|Name|優先順位|発信元 IP|発信元ポート|宛先 IP|宛先ポート|プロトコル|Access (アクセス)|
|:---|---:|:---|---:|:---|---:|:---|:---|
|AllowDB|300|**Web用ASG**|*|**DB用ASG**|1433|TCP|Allow|
|AllowWeb|400|Internet|*|**Web用ASG**|80|TCP|Allow|
|AllowSSH|500|(自社のWAN側IP)|*|VirtualNetwork|22|TCP|Allow|

![image.png](https://qiita-image-store.s3.amazonaws.com/0/137436/b067da9c-5fb7-e0fd-fe1a-7e20dc43ba36.png)

NSGはサブネットと、個々の仮想マシン(NIC)両方に指定する必要があります。
更に仮想マシン(NIC)側には自分が所属するASGを指定します。

このような設定を行うと、一つのNSGリソースだけで種別の異なるサーバを細かく制御することができ、更にNSGのルール内にプライベートIPアドレスを記載しなくても良いので、本来すべきネットワーク設計に集中する事ができるのではないかと。

#実際試用してみる
本記事執筆時点ではまだPublic Previewで米国中西部のリージョンのみ可能です。
具体的な利用開始手順は英語ですが、以下のサイトを参照下さい。

[https://docs.microsoft.com/en-us/azure/virtual-network/create-network-security-group-preview](https://docs.microsoft.com/en-us/azure/virtual-network/create-network-security-group-preview?WT.mc_id=AZ-MVP-5002499)

Azure PowershellはVersion 4.4.0以降が必要で、Public PreviewのASGを使うには先に利用申請が必要です。

PowerShellから以下のコマンドを実行して、暫く待ちます。

```ps1
Register-AzureRmProviderFeature -FeatureName AllowApplicationSecurityGroups -ProviderNamespace Microsoft.Network
Register-AzureRmResourceProvider -ProviderNamespace Microsoft.Network
```

私の場合は10分くらいで利用申請の許可が降りました。
以下のコマンドで状況を確認します。

```ps1
Get-AzureRmProviderFeature -FeatureName AllowApplicationSecurityGroups -ProviderNamespace Microsoft.Network
```

RegistrationStateに「Registered」が返ってくればOKです。

```
FeatureName                    ProviderName      RegistrationState
-----------                    ------------      -----------------
AllowApplicationSecurityGroups Microsoft.Network Registered     
```

後は先に示したURLから(英語ですが)チュートリアルを実施すれば一通りの流れがわかると思います。
Azureポータル側の対応が未だなので、NSGの内容とかみると、ASGに対応していないため宛先部分が空白になっていたりするのですが、ちゃんと動きましたｗ

![image.png](https://qiita-image-store.s3.amazonaws.com/0/137436/b4de4b1d-f313-e9d1-1982-e89622c71d69.png)

参考として私が試用で使ったスクリプトを以下に示します。
Linux(Centos 7.3)とWindows Server 2016の2台の仮想マシンを作成します。
tcp/80(HTTP)は両方の仮想マシンが受信できますが(ASGを設定していない)、Linuxにはtcp/22(ssh)を、Windowsにはtcp/3389(RDP)の受信ルールがそれぞれ有効になる感じの作りです。

```ps1#asgsample.ps1
$rgname = 'ASG-test-rg'
$loc = 'westcentralus'
$cred = Get-Credential -Message "Enter a username and password for the virtual machine."

New-AzureRmResourceGroup -Name $rgname -Location $loc

$linuxasg= New-AzureRmApplicationSecurityGroup -ResourceGroupName $rgname -Location $loc -name LinuxASG
$windowsasg= New-AzureRmApplicationSecurityGroup -ResourceGroupName $rgname -Location $loc -name WindowsASG

$linuxrule = New-AzureRmNetworkSecurityRuleConfig -Name "alllowssh" -Access Allow -Protocol Tcp -Direction Inbound -Priority 200 -SourceAddressPrefix "Internet" -SourcePortRange "*" -DestinationApplicationSecurityGroup $linuxasg -DestinationPortRange 22
$windowsrule = New-AzureRmNetworkSecurityRuleConfig -Name "alllowrdp" -Access Allow -Protocol Tcp -Direction Inbound -Priority 300 -SourceAddressPrefix "Internet" -SourcePortRange "*" -DestinationApplicationSecurityGroup $windowsasg -DestinationPortRange 3389
$commonrule = New-AzureRmNetworkSecurityRuleConfig -Name "alllowhttp" -Access Allow -Protocol Tcp -Direction Inbound -Priority 400 -SourceAddressPrefix "Internet" -SourcePortRange "*" -DestinationPortRange 80 -DestinationAddressPrefix *

$nsg = New-AzureRmNetworkSecurityGroup -ResourceGroupName $rgname -Location $loc -name defaultNSG -SecurityRules $windowsrule,$linuxrule,$commonrule

$subnet = New-AzureRmVirtualNetworkSubnetConfig -AddressPrefix 192.168.0.0/24 -Name default -NetworkSecurityGroup $nsg
$vnet = New-AzureRmVirtualNetwork -Name testVNET -AddressPrefix 192.168.0.0/16 -Subnet $subnet -ResourceGroupName $rgname -Location $loc

###linux
$pip1 = New-AzureRmPublicIpAddress -Name pip1 -ResourceGroupName $rgname -Location $loc -Sku Basic -AllocationMethod Dynamic -IpAddressVersion IPv4
$nic1 = New-AzureRmNetworkInterface -Name nic1 -ResourceGroupName $rgname -Location $loc -Subnet $vnet.Subnets[0] -PublicIpAddress $pip1 -NetworkSecurityGroup $nsg -ApplicationSecurityGroup $linuxasg
$vmconfig1 = New-AzureRmVMConfig -VMName LINVM01 -VMSize Standard_DS1_V2 | Set-AzureRmVMOperatingSystem -Linux -ComputerName LINVM01 -Credential $cred | Set-AzureRmVMSourceImage -PublisherName OpenLogic -Skus 7.3 -Offer CentOS -Version "latest" | Add-AzureRmVMNetworkInterface -Id $nic1.Id
New-AzureRmVM -ResourceGroupName $rgname -Location $loc -VM $vmconfig1

###Win
$pip2 = New-AzureRmPublicIpAddress -Name pip2 -ResourceGroupName $rgname -Location $loc -Sku Basic -AllocationMethod Dynamic -IpAddressVersion IPv4
$nic2 = New-AzureRmNetworkInterface -Name nic2 -ResourceGroupName $rgname -Location $loc -Subnet $vnet.Subnets[0] -PublicIpAddress $pip2 -NetworkSecurityGroup $nsg -ApplicationSecurityGroup $windowsasg
$vmconfig2 = New-AzureRmVMConfig -VMName WINVM01 -VMSize Standard_DS2_V2 | Set-AzureRmVMOperatingSystem -Windows -ComputerName WINVM01 -Credential $cred | Set-AzureRmVMSourceImage -PublisherName MicrosoftWindowsServer -Skus 2016-Datacenter -Offer WindowsServer -Version latest | Add-AzureRmVMNetworkInterface -Id $nic2.Id
New-AzureRmVM -ResourceGroupName $rgname -Location $loc -VM $vmconfig2
```

#おわりに
今後、GAまでにきっとAzureポータル側の対応や、MS公式の親切な日本語ドキュメントなど充実してくると思いますが、先ずは今回の試用記事が少しでも参考になれば幸いです。