Hyper-Vゲスト通信向け拡張ACL(Add-VMNetworkAdapterExtendedAcl)
仮想環境において、ゲストの通信を必要最低限の範囲に制限しておきたい場合があります。特に、ネットワーク側のファイアウォール設定だけでは都合が悪い場合、ホスト側で制限をかけられると便利です。
本記事は、Hyper-V環境でAdd-VMNetworkAdapterExtendedAcl
コマンドレット(拡張ACL)によりゲストの通信を制限する方法についてまとめたものです。Windows 10上のHyper-Vで確認したものですが、Windows Serverでも同様です。
この拡張ACLは便利ですが、Microsoftのページを含む公開情報では欲しい説明を探しづらく、仕様把握に手間取りました。事前に知っておきたかったと思うポイントを整理しておきます。
本記事の目的
- Hyper-V環境で拡張ACLの使用方法を把握する。
基本
拡張ACLの概要とユースケース
-
概要
- Hyper-Vホスト上のWindowsファイアウォールは、ゲストの通信に対しては適用されません。そのため、ゲストの通信をホスト側で制限したい場合には
Add-VMNetworkAdapterExtendedAcl
のような別の設定が必要です。 Add-VMNetworkAdapterExtendedAcl
は、Hyper-V上の各仮想ネットワークアダプタに対し、アクセス制御ルール(ACL)を作成するコマンドレットです。Add-VMNetworkAdapterAcl
のACLと対比する場合等、”拡張ACL”と呼ぶこともあります。- IPアドレスやポート番号によるACLを作成可能です。
- 簡易的な実装ではあるものの、各ゲストOS内の設定でなくホスト側で集中的にアクセス制御できる利点があります。
- 拡張ACLは、初期状態では未定義であり、ゲストの通信は全て許可されます。
- 仮想スイッチの種類に関わらず拡張ACLを使用可能です。補足事項は後述します。
- NAT(WinNAT)の有無に関わらず、拡張ACLを使用可能です。
- 仮想マシンごと(仮想ネットワークアダプタごと)に定義が必要です。便利な一括設定の方法については後述します。
- Hyper-Vホスト上のWindowsファイアウォールは、ゲストの通信に対しては適用されません。そのため、ゲストの通信をホスト側で制限したい場合には
-
ユースケース
以下のように、トラブル防止等の理由により、Add-VMNetworkAdapterExtendedAcl
を使用できます。- そのHyper-V環境をテストや検証のために使用する際、Hyper-Vの外にある本番環境に影響を与えないようにしたい
- ゲストから特定のネットワーク以外に対する通信を遮断したい
- あるいは、逆に特定のネットワークに対する通信を遮断したい
- ゲストOSのローカルファイアウォール設定だけでなく、追加の対策としてホスト側でも通信を制限しておきたい
- ネットワーク側のファイアウォール設定では都合がよくない
- セキュリティポリシー上、ゲストに許可する通信を必要最低限の範囲に制限しておきたい
- そのHyper-V環境をテストや検証のために使用する際、Hyper-Vの外にある本番環境に影響を与えないようにしたい
設定例
例として、以下の図に示すアクセス制御を実現するACLを設定してみます。
例1 (基本的な定義)
Add-VMNetworkAdapterExtendedAcl -Action Allow -Direction Outbound -VMName "VM1" -Weight 1 …(1) Add-VMNetworkAdapterExtendedAcl -Action Allow -Direction Inbound -VMName "VM1" -Weight 1 …(1') Add-VMNetworkAdapterExtendedAcl -Action Deny -Direction Outbound -VMName "VM1" -RemoteIPAddress 172.16.0.0/16 -Weight 10 …(2) Add-VMNetworkAdapterExtendedAcl -Action Deny -Direction Inbound -VMName "VM1" -RemoteIPAddress 172.16.0.0/16 -Weight 10 …(2') Add-VMNetworkAdapterExtendedAcl -Action Allow -Direction Outbound -VMName "VM1" -RemoteIPAddress 192.168.0.0/24 -Weight 11 …(3) Add-VMNetworkAdapterExtendedAcl -Action Allow -Direction Inbound -VMName "VM1" -RemoteIPAddress 192.168.0.0/24 -Weight 11 …(3') Add-VMNetworkAdapterExtendedAcl -Action Allow -Direction Outbound -VMName "VM1" -RemoteIPAddress 172.16.0.1/32 -RemotePort 53 -Protocol TCP -Weight 21 -Stateful $True …(4) Add-VMNetworkAdapterExtendedAcl -Action Allow -Direction Outbound -VMName "VM1" -RemoteIPAddress 172.16.0.1/32 -RemotePort 53 -Protocol UDP -Weight 22 -Stateful $True …(4') Add-VMNetworkAdapterExtendedAcl -Action Allow -Direction Outbound -VMName "VM1" -RemoteIPAddress 172.16.0.2/32 -RemotePort 443 -Protocol TCP -Weight 23 -Stateful $True …(5)
図中のVM1という仮想マシンに対してACLを設定します。
-
(1)、(1′) デフォルトアクション/社外ネットワーク(インターネット)との通信
- 他のどのACLにもマッチしない場合に適用するACLです。IPアドレスやポート番号の指定はありません。
-Weight 1
は最後に評価されるACLという意味です。- 今回の例ではインターネット向けの通信を許可するため、
-Action Allow
としています。拒否したい場合は-Action Deny
を指定します。 - 例なので明示的に定義していますが、この許可ACLは定義しなくても動作に変わりはありません(デフォルトでマッチするACLが無ければ許可されるため)。
- デフォルトで拒否したい場合には、
-Action Deny
のACL定義が必要です。
- デフォルトで拒否したい場合には、
- なお今回の例では、仮想マシンは社外に公開するサービスが無く、社外から仮想マシンに対する通信は社外向けファイアウォールにより遮断されることを前提にしています。
-
(2)、(2′) 社内ネットワーク(172.16.0.0/16)との通信
- 社内ネットワーク(172.16.0.0/16)に対する通信を拒否するACLです。
-Weight
は10なので、-Weight
が1~9のACLより優先されます。逆に-Weight
が11以上のACLはこのACLより優先されます。
-
(3)、(3′) Hyper-V内ネットワーク(192.168.0.0/24)との通信
- Hyper-V内ネットワーク(192.168.0.0/24)に対する通信を許可するACLです。
- 例なので明示的に定義していますが、この許可ACLは定義しなくても動作に変わりはありません(マッチするACLが無ければ許可されるため)。
- (1)のデフォルトアクションが拒否である場合、このような個別の許可ACLの定義が必要です。
-
(4)、(4′) DNSサーバ(172.16.0.1)との通信
- DNSサーバ(172.16.0.1)に対する通信を許可するACLです。
- (2)の拒否ACLよりこのACLが先に評価されるよう、
-Weight
の値を10より大きな値にしてあります。
- (2)の拒否ACLよりこのACLが先に評価されるよう、
- DNSの通信ポート(53)を指定してあります。
- DNS通信なのでTCPとUDPの両方を許可します。
- 同じポート番号ですが、
-Protocol TCP
と-Protocol UDP
、それぞれ定義が必要です。理由は後述します。
-Stateful $True
にて、ステートフルなアクセス制御となるよう指定します。- このACL 1つで、DNSサーバに対する行きパケットが許可されると、その戻りパケットも自動的に許可されます。
-Direction Inbound
の方向の拒否ACLが無い場合は、戻りパケットを許可する必要性が無いため、-Stateful $True
の指定は不要です。
- DNSサーバ(172.16.0.1)に対する通信を許可するACLです。
-
(5) Webサーバ(172.16.0.2)との通信
- Webサーバ(172.16.0.2)との通信を許可するACLです。
- (4)と同様ですが、HTTPSなのでTCPのみの定義です。
例2 (省略した定義)
次に、例1からできるだけACLを省略した場合の例を記載します。
以下のいずれかに該当する場合、Hyper-Vの外のネットワークとの通信に関する-Direction Inbound
の方向の拒否ACLは不要です。
- 仮想マシンがNAT(WinNAT)の有効な仮想ネットワーク配下にある場合
- NAT以外の仮想ネットワーク構成で、Hyper-Vの外から仮想マシンに対する通信を一律許可したい場合
省略しても動作に変わりのないACLを省略、さらに-Direction Inbound
の方向の拒否ACLを省略すると、以下のようになります。
Add-VMNetworkAdapterExtendedAcl -Action Deny -Direction Outbound -VMName "VM1" -RemoteIPAddress 172.16.0.0/16 -Weight 10 …(2) Add-VMNetworkAdapterExtendedAcl -Action Allow -Direction Outbound -VMName "VM1" -RemoteIPAddress 172.16.0.1/32 -RemotePort 53 -Protocol TCP -Weight 21 -Stateful $True …(4) Add-VMNetworkAdapterExtendedAcl -Action Allow -Direction Outbound -VMName "VM1" -RemoteIPAddress 172.16.0.1/32 -RemotePort 53 -Protocol UDP -Weight 22 -Stateful $True …(4') Add-VMNetworkAdapterExtendedAcl -Action Allow -Direction Outbound -VMName "VM1" -RemoteIPAddress 172.16.0.2/32 -RemotePort 443 -Protocol TCP -Weight 23 -Stateful $True …(5)
かなりシンプルになります。仮想スイッチの構成にもよりますが、図に記載のアクセス制御を実現するだけであれば、この定義で十分です。
(2′)のInbound方向のACLを定義していないので、(4)~(5)の-Stateful $True
は省略可です。
詳細
仮想スイッチの種類ごとの拡張ACLの適用
どの仮想スイッチを使用していても拡張ACLは適用できますが、考慮するポイントが少しずつ違うので整理しておきます。
-
Default Switch
- 拡張ACLにより、仮想マシンからHyper-Vの内外に対する通信を制限できます。
- ホストを再起動すると仮想マシンのIPアドレスが変わるので、仮想マシン側のIPアドレスを指定したACL定義は避けるべきです。
- NATが有効なので、
-Direction Inbound
の方向のACL定義は不要です。
-
外部ネットワーク(External)
- 拡張ACLにより、仮想マシンからHyper-Vの内外に対する通信を制限できます。また、Hyper-Vの外から仮想マシンに対する通信も制限できます。
- 基本的にHyper-Vの外から仮想マシンに対する通信が可能なので、
-Direction Inbound
のACL定義を行うか考慮が必要です。
-
内部ネットワーク(Internal)
- 拡張ACLにより、Hyper-V内部、つまり仮想マシンとホストWindowsの間の通信、および仮想マシン同士の通信を制限できます。
- 個別にNAT(WinNAT)を有効化した構成の場合は、拡張ACLにより、仮想マシンからHyper-Vの外に対する通信を制限できます。
-
プライベート(Private)
- 拡張ACLにより、ホストWindowsを除くHyper-V内部、つまり仮想マシン同士の通信を制限できます。
なお、New-VMSwitch
により個別に作成した仮想スイッチでも使用可能です。
コマンドレット説明
Add-VMNetworkAdapterExtendedAcl
以下のように実行できるコマンドです。
Add-VMNetworkAdapterExtendedAcl -Action Allow -Direction Outbound -VMName "仮想マシン名" -RemoteIPAddress x.x.x.x/x -RemotePort x -Protocol x -Weight x -Stateful $True
主要なオプションは以下です。
-
-Action
(必須)- パケットが条件にマッチした際のアクションです。
- 指定可能な値は、Allow(許可)、Deny(拒否)のいずれかです。
-
-Direction
(必須)- そのACLを適用するパケットの方向です。
- 指定可能な値は、Inbound、Outboundのいずれかです。
- 仮想マシンから見た方向なので、Inboundは仮想マシンが受信するパケット、Outboundは仮想マシンが送信するパケットを意味します。
- 省略時に両方向に適用されてくれたりすると定義をシンプルにできるのですが、残念ながら必須オプションです。
-
-Weight
(必須)- ACLエントリに対する優先度指定です。大きな値のACLが先に適用されます。
- いったんACLがパケットに適用されると、そのパケットには他のACLエントリは適用されません。
- 指定可能な値は、1以上の整数です(型はINT32のようです)。
- 大規模なACL設計でなければ、例えば1~100程度でも十分でしょう。
- 一般的なファイアウォールのルールと同様に考えると良いでしょう。
- ACLの数が多い場合には、狭いスコープの条件から広いスコープの条件の順に優先されるよう定義する等、設計上のポリシーを決めておくと良いです。
- ACLエントリに対する優先度指定です。大きな値のACLが先に適用されます。
-
-LocalIPAddress
、-RemoteIPAddress
(任意)- そのACLを適用するIPアドレスです。
-LocalIPAddress
が仮想マシン側のIPアドレス、-RemoteIPAddress
がその通信先のIPアドレスです。- 指定可能な値は、以下のいずれかです。
- IPアドレス(x.x.x.x)
- ネットワーク範囲(x.x.x.x/x、CIDR表記)
- ワイルドカード(0.0.0.0/0(IPv4)、::/0(IPv6)、ANY(IPv4、IPv6両方))
- 省略時は全てのIPアドレスが対象になります。
-
-LocalPort
、-RemotePort
(任意)- そのACLを適用するポート番号です。TCPとUDPに対して適用できます。
-LocalPort
が仮想マシン側のポート番号、-RemotePort
がその通信先のポート番号です。- 指定可能な値は、以下のいずれかです。
- “443”のように単一のポート番号
- “49152-49182″のようにポート番号の範囲
- 省略時は全てのポート番号が対象になります。
-
-Protocol
(任意)- そのACLを適用するプロトコルです。
- 指定可能な値は、以下のいずれかです。
- TCP
- UDP
- IPプロトコル番号 (例:ICMPの場合は”1″)
- 省略時は全てのIPベースのプロトコルが対象になるようです。例えば、TCP、UDPに加え、ICMP等のその他のプロトコルも対象になるということです。
-
-Stateful
(任意)- ステートフルなアクセス制御とするかどうかを指定します。
-Stateful $True
を指定した許可ACLは、そのACL 1つで行きパケットが許可されると、その戻りパケットも自動的に許可されます。
- 指定可能な値は、Bool値です(PowerShellの”$True”や”$False”を指定可能)。
-Stateful
を指定する際には、-Protocol
の指定が必須のようです。詳細は後述します。- 省略時はステートフルなアクセス制御を行いません。
- ステートフルなアクセス制御とするかどうかを指定します。
-
-IdleSessionTimeout
(任意)- 無通信タイムアウトを秒単位で指定します。
- 指定可能な値は、1以上の整数です(型はINT32のようです)。
- 省略時は255が設定されるようです(
Get-VMNetworkAdapterExtendedAcl
の結果より)。
Get-VMNetworkAdapterExtendedAcl
以下のように実行できるコマンドです。
`Get-VMNetworkAdapterExtendedAcl -VMName “仮想マシン名”
定義済みのACLの内容を出力します。
以下、出力例です(一部省略してあります)。
デフォルトで仮想マシン(仮想ネットワークアダプタ:ParentAdapter
)ごとにソートはされるようです。
Direction : Outbound Action : Allow LocalIPAddress : ANY RemoteIPAddress : 172.16.0.1/32 LocalPort : ANY RemotePort : 53 Protocol : TCP Weight : 21 Stateful : True IdleSessionTimeout : 255 IsolationID : 0 ParentAdapter : VMNetworkAdapter (Name = 'ネットワーク アダプター', VMName = 'VM1') [VMId = 'xxxxx-xxxxx-xxxxx-xxxxx-xxxxx'] IsTemplate : False CimSession : CimSession: . ComputerName : DESKTOP-XXXXXX IsDeleted : False … Direction : Outbound Action : Allow LocalIPAddress : ANY RemoteIPAddress : 192.168.0.0/24 LocalPort : ANY RemotePort : ANY Protocol : ANY Weight : 11 Stateful : False IdleSessionTimeout : 0 IsolationID : 0 ParentAdapter : VMNetworkAdapter (Name = 'ネットワーク アダプター', VMName = 'VM1') [VMId = 'xxxxx-xxxxx-xxxxx-xxxxx-xxxxx'] IsTemplate : False CimSession : CimSession: . ComputerName : DESKTOP-XXXXXX IsDeleted : False … Direction : Inbound Action : Allow LocalIPAddress : ANY RemoteIPAddress : 192.168.0.0/24 LocalPort : ANY RemotePort : ANY Protocol : ANY Weight : 11 Stateful : False IdleSessionTimeout : 0 IsolationID : 0 ParentAdapter : VMNetworkAdapter (Name = 'ネットワーク アダプター', VMName = 'VM1') [VMId = 'xxxxx-xxxxx-xxxxx-xxxxx-xxxxx'] IsTemplate : False CimSession : CimSession: . ComputerName : DESKTOP-XXXXXX IsDeleted : False
Remove-VMNetworkAdapterExtendedAcl
以下のように実行できるコマンドです。
特定のACLを1つ削除する場合は、-Direction
と-Weight
を指定して実行します。
Remove-VMNetworkAdapterExtendedAcl -VMName "VM1" -Direction InBound -Weight 23
その仮想マシンに紐づくACLを全て削除する場合は、ACLをオブジェクトで渡して実行します。
Get-VMNetworkAdapterExtendedAcl -VMName "VM1" | Remove-VMNetworkAdapterExtendedAcl
注意点として、ACLの削除が成功しても失敗しても何も出力されません。このコマンドを実行する前後でGet-VMNetworkAdapterExtendedAcl
の結果をテキストに保存しておき、差分チェックすると安心です。
-Stateful $True指定時に-Protocol指定が必須な理由と対処
Microsoftのページに記載は見当たりませんが、Add-VMNetworkAdapterExtendedAcl
では、-Stateful
を指定する際、-Protocol
の指定が必須のようです。
その理由として、-Protocol
の省略時は、全てのIPベースのプロトコルが対象となるようですが、このときTCP、UDP以外の-Stateful
に対応できないプロトコルも対象になってしまうためと思われます。例えば拡張ACLでは、ICMPに対して-Stateful
を指定できないので、行きと戻り両方のパケットにACLを適用する場合には、InboundとOutboundの両方の定義が必要です。
この動作により、DNS等、TCPとUDPで同じポート番号を使用するプロトコルにステートフルなACLを適用する場合に配慮が必要となります。
具体的には、-Protocol TCP
のACLと、-Protocol UDP
のACLをそれぞれ定義することになります。
これは、-Protocol
を省略すると-Stateful
指定はできないという点、また-Protocol
でTCPとUDPの2つを指定することができないという点から、結果的にACLを複数定義する必要性があるということです。
拡張ACLは、一般的なファイアウォールに比べると簡易的な実装ではあるので、このあたりは注意して使うしかないでしょう。
Add-VMNetworkAdapterAclとAdd-VMNetworkAdapterExtendedAclの違い
Add-VMNetworkAdapterAcl
(ACLの追加)とAdd-VMNetworkAdapterExtendedAcl
(拡張ACLの追加)は、異なるコマンドレットです。
異なるACLを扱います。併用すべきではないでしょう。混在させた場合の動作は不明です。
後者の拡張ACLが新しい機能です。Windows Server 2012 R2から使用できるようになったようです。
前者のACLは、ポート番号を指定したACLやステートフルなACLを作成できません。ACL自体に優先度指定は無く、最長マッチしたACLが優先的に適用されます。
後者の拡張ACLの方が多機能です。ポート番号を指定したACLやステートフルなACLを作成できます。ACLごとに優先度指定(-Weight
)が可能です。ただしMACアドレスベースのアクセス制御に関しては前者のACLにのみ備わっているようです。IPベースのACLと言えるでしょう。
また参考までに、構成によってはSCVMM経由で拡張ACLの管理ができるようです(portACL)。
拡張ACLの一括設定
全仮想マシンを対象に拡張ACLを一括設定
拡張ACLは全仮想マシンに適用されるグローバルな定義を設定できません。
代替手段として、全仮想マシンの仮想ネットワークアダプタを対象に、一括設定する方法があります。
Get-VMNetworkAdapter -vmname "*" | Get-VMNetworkAdapterExtendedAcl > "C:\any\path\before.txt" Get-VMNetworkAdapter -vmname "*" | Add-VMNetworkAdapterExtendedAcl … Get-VMNetworkAdapter -vmname "*" | Add-VMNetworkAdapterExtendedAcl … …(定義したい分、繰り返す)… Get-VMNetworkAdapter -vmname "*" | Get-VMNetworkAdapterExtendedAcl > "C:\any\path\after.txt"
-
全ての仮想マシン(“*”)を対象に
Get-VMNetworkAdapter
コマンドレットを実行して得られる仮想ネットワークアダプタのオブジェクトを、Add-VMNetworkAdapterExtendedAcl
等にパイプで渡すと、一括で処理してくれます。 -
例えば、仮想マシンを追加した際に実行するバッチとして準備しておくことで、全ての仮想マシンに対して一律同じ設定を維持できます。
-
なお、繰り返し全ての仮想マシンを対象に
Add-VMNetworkAdapterExtendedAcl
を実行すると、追加しようとするACLと同じACL(同じ-Direction
と-Weight
)が既に存在することになります。この場合、そのACLの追加に関してはAdd-VMNetworkAdapterExtendedAcl
がエラーとなりますので、重複した内容のACLが登録されることはありません。ACLが未設定の仮想ネットワークアダプタに対してのみ追加されます。
言い換えると、Add-VMNetworkAdapterExtendedAcl
はACLの上書きをしません。
全仮想マシンを対象に拡張ACLを一括削除
同様に、全仮想マシンの仮想ネットワークアダプタを対象に、既に定義されている拡張ACLを一括削除する方法です。
Get-VMNetworkAdapter -vmname "*" | Get-VMNetworkAdapterExtendedAcl | Remove-VMNetworkAdapterExtendedAcl もしくは Get-VMNetworkAdapterExtendedAcl -VMName "*" | Remove-VMNetworkAdapterExtendedAcl
(参考)ホストWindows側の仮想ネットワークアダプタに対するACL設定
あまりユースケースが無さそうですが、ホストWindows側の仮想ネットワークアダプタに対してACL設定することもできるようです。
-ManagementOS
オプションを使用します。このサイトに例が載っています。拡張ACLでなくVMNetworkAdapterACLの方ですが、拡張ACLでも-ManagementOS
オプションは使用可能です。
以下、Add-VMNetworkAdapterAcl
で試した際のメモです。
- ホストWindowsの仮想ネットワークアダプタに対するACLを設定すると、そのIPインタフェースを使用した通信を制限できます。
- そのACLは、ホストWindowsの仮想ネットワークアダプタをゲートウェイとして使用する仮想マシンが送受信するパケットに対しては適用されないようです。これはWinNAT環境で確認した結果ですが、WinNATの有無は関係無い気がします。
- また、その結果から、ACLはパケットの送信元IPアドレスと宛先IPアドレスに対してのみ適用されるのかと思ったら、一方でホストWindowsのゲートウェイのIPアドレスを指定した拒否ACLを定義してみると、それはゲストの通信(パケットの送信元IPアドレスと宛先IPアドレスはHyper-Vの外部)に適用されてゲートウェイを越えられない、といった動作でした。