Azure 仮想ネットワーク上で NAT を実現する際のポイント

azure
Published: 2024-02-11

はじめに

本エントリは 仮想ネットワーク上での NAT を推奨するものではありません。私の中では、仮想ネットワーク上の NAT は「やらないに越したことはない」手法です。NAT 用仮想マシンの分だけ障害ポイントが増えますし、パフォーマンス上のボトルネックになる可能性もあるからです。また、運用中、特に障害時に「このアドレスは実際はこれだから・・・」という読み替えのコストが発生する点も地味に辛いです。

とはいえ、何かしらの要件で NAT しなけらばならないこともあるでしょう。というわけで実際に構成を組んで、設定時に必要なポイントを確認しました。

構成

今回の検証環境は以下の通りです。左から、オンプレ相当の仮想ネットワーク、ハブ仮想ネットワーク、NAT 装置が存在する仮想ネットワークに、NAT されている仮想ネットワークです。本エントリでは左から「オンプレの仮想ネットワーク」「左の仮想ネットワーク」「NAT 用仮想ネットワーク」「右の仮想ネットワーク」という名称で呼びます。

今回の構成図

大事なポイント

NAT を実現するための大事なポイントは次の3つです。事例を通じて解説します。

  1. 仮想ネットワークに、NAT 用仮想マシンが NAT で利用するアドレス帯のルーティングを追加する
  2. 仮想ネットワークに、自動的にルーティングを学習しないアドレス帯のルーティングを追加する
  3. 宛先 NAT で利用するアドレス帯をオンプレミスにも広報する

NAT 用仮想マシンの構成

今回の NAT 用仮想マシンは、将来の冗長化に備えて内部ロードバランサを前段に構える構成とします。内部ロードバランサは HA ポートを有効化してあるので、ロードバランサのフロントエンド IP アドレス(172.16.2.7)に届いたすべての TCP/UDP 通信を NAT 用仮想マシンに転送するルータのように振る舞います。

HA ポートの設定画面

また、NAT 用仮想マシンでは IP 転送を有効化します。通常の Azure のネットワークインターフェースは、NIC に設定された IP アドレスのみを受け入れます。ですが、NAT の場合、自分の NIC に設定されていない IP アドレス宛てのパケットを受け取る必要があります。IP 転送を有効化しておけば、NIC に設定された IP アドレス以外の宛先のパケットも受信してくれるようになります。

IP 転送の設定画面

ケースその1:Azure 内での宛先 NAT

まずは Azure 内での宛先 NAT からです。左の仮想ネットワーク上の仮想マシンから、NAT 用仮想マシンが提供する宛先 NAT 用 IP アドレスを通じて、右の仮想ネットワーク上の仮想マシンにアクセスします。

通信のイメージ

宛先 NAT で利用するアドレス帯は次の2つです。サブネットとして存在しているかによって挙動が変わるかを確認する意味合いで2つ用意しました。

  1. 172.16.2.64/26:NAT用仮想ネットワークのサブネットとして設定済み
  2. 172.16.20.0/24:仮想ネットワークのアドレス空間に追加済みだが、サブネットは未設定

まずは 172.16.1.5 の仮想マシンが送信する 172.16.2.65 宛のパケットを、NAT 装置用仮想マシンである 172.16.2.7 に届ける必要があります。ここでポイントになるのが1つ目の「仮想ネットワークに、NAT 用仮想マシンが NAT で利用するアドレス帯のルーティングを追加する」です。

172.16.2.5 の NAT 用仮想マシン内の OS 上で「宛先が 172.16.2.65 だったら 172.16.3.5 に変換する」という宛先 NAT の設定を入れたとしても、仮想ネットワークは NAT 用仮想マシンが 172.16.2.65 宛の通信を欲していることを理解できません。特に何もしない場合、仮想ネットワークが 172.16.2.5 の NAT 用仮想マシンに転送するパケットは、宛先が 172.16.2.5 のものだけです。宛先が 172.16.2.65 のパケットを 172.16.2.5 には転送しません。

ここで利用するのがユーザ定義ルートです。ユーザ定義ルートを利用して「宛先 NAT で利用するアドレス帯(172.16.2.64/26と172.16.20.0/24)のネクストホップは 172.16.2.7(NAT 用仮想マシンの内部ロードバランサ)」というルーティングを仮想ネットワークに設定します。このユーザ定義ルートによって、仮想ネットワークは、NAT 用 IP アドレスである 172.16.2.64/26 のパケットも 172.16.2.7 に転送するようになります。

> $res = Get-AzRouteTable -ResourceGroupName vnetnat -Name rtVnetLeft
> $res.Routes | ft AddressPrefix,  NextHopType, NextHopIpAddress

AddressPrefix  NextHopType      NextHopIpAddress
-------------  -----------      ----------------
172.16.2.64/26 VirtualAppliance 172.16.2.7
172.16.20.0/24 VirtualAppliance 172.16.2.7

また、戻りのルーティングも整える必要があります。ここでポイントになるのが2つ目の「仮想ネットワークに、自動的にルーティングを学習しないアドレス帯のルーティングを追加する」です。右の仮想ネットワークが自動的にルーティングを学習する範囲は隣の NAT 用仮想ネットワークまでです。したがって、右の仮想ネットワーク上には、左の仮想ネットワークのアドレス帯である 172.16.1.0/24 宛のルーティングが存在しません。その結果として今回の構成の場合、戻りのルーティングが「172.16.0.0/12 のネクストホップは Null」という既定のルーティングにマッチして破棄されてしまいます。

これを回避するためにもユーザ定義ルートを利用します。ユーザ定義ルートを利用して「172.16.1.0/24 のネクストホップは 172.16.2.7」というルーティングを右の仮想ネットワークに設定します。このユーザ定義ルートによって、右の仮想ネットワークは、宛先が 172.16.1.0/24 のパケットを破棄するのではなく、NAT 用仮想マシンに転送します。

> $res = Get-AzRouteTable -ResourceGroupName vnetnat -Name rtVnetRIght
> $res.Routes | ft AddressPrefix,  NextHopType, NextHopIpAddress

AddressPrefix  NextHopType      NextHopIpAddress
-------------  -----------      ----------------
172.16.1.0/24  VirtualAppliance 172.16.2.7

行きと戻りのルーティングが整ったので、NAT 用仮想マシンの iptables で以下の NAT を追加して動作確認します。

:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING -d 172.16.2.65/32 -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.16.3.5:80
-A PREROUTING -d 172.16.20.5/32 -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.16.3.5:80

通信の送信元 IP アドレスと宛先 IP アドレスを把握しやすいように、右の仮想ネットワーク上の仮想マシンでは、受信した HTTP リクエストの情報を表示する kongou-ae/light-ip-echo を動作させてあります。

もろもろ整っているので、以下のように通信できます。

# 172.16.1.5 から 172.16.2.65 への通信が成功
root@vnetLeftVm:~# curl 172.16.2.65
{"RemoteAddr":"172.16.1.5:35496","RequestURI":"/","Xforwardedfor":"","Host":"172.16.2.65","XAzureFDID":"","XAzureFDHP":""}

# 172.16.1.5 から 172.16.20.5 への通信も成功
root@vnetLeftVm:~# curl 172.16.20.5
{"RemoteAddr":"172.16.1.5:47452","RequestURI":"/","Xforwardedfor":"","Host":"172.16.20.5","XAzureFDID":"","XAzureFDHP":""}

なお、今回の構成の場合は、別に NAT しなくても、左の仮想ネットワークに「172.16.3.0/24 のネクストホップは NAT 用仮想マシン」というユーザ定義ルートを、右の仮想ネットワークに「172.16.1.0/24 のネクストホップは NAT 用仮想マシン」というユーザ定義ルートを追加すれば、実 IP アドレス同士でも通信できます。

> $res = Get-AzRouteTable -ResourceGroupName vnetnat -Name rtVnetLeft
> $res.Routes | ft AddressPrefix,  NextHopType, NextHopIpAddress

AddressPrefix  NextHopType      NextHopIpAddress
-------------  -----------      ----------------
172.16.3.0/24  VirtualAppliance 172.16.2.7
172.16.2.64/26 VirtualAppliance 172.16.2.7
172.16.20.0/24 VirtualAppliance 172.16.2.7
# 172.16.1.5 から 172.16.3.5 への通信が成功
root@vnetLeftVm:~# curl 172.16.3.5
{"RemoteAddr":"172.16.1.5:50128","RequestURI":"/","Xforwardedfor":"","Host":"172.16.3.5","XAzureFDID":"","XAzureFDHP":""}

ケースその2:オンプレミスからの宛先 NAT

次はオンプレミスを含めた宛先 NAT です。想定する通信は次の通りです。

通信のイメージ

オンプレミスの仮想ネットワークから右の仮想ネットワークの 172.16.3.0/24 にはアクセスできません。なぜならルーティングが存在しないからです。

# オンプレの仮想ネットワーク上の仮想マシンの有効なルート
Get-AzEffectiveRouteTable -NetworkInterfaceName vnetOnpreVmNic -ResourceGroupName vnetnat | Select-Object State,Source, AddressPrefix, NextHopType,NextHopIpAddress | ft *

State  Source                AddressPrefix     NextHopType           NextHopIpAddress
-----  ------                -------------     -----------           ----------------
Active Default               {192.168.1.0/24}  VnetLocal             {}
Active VirtualNetworkGateway {172.16.1.126/32} VirtualNetworkGateway {13.64.109.168}
Active VirtualNetworkGateway {172.16.1.0/24}   VirtualNetworkGateway {13.64.109.168}
Active VirtualNetworkGateway {172.16.20.0/24}  VirtualNetworkGateway {13.64.109.168}
Active VirtualNetworkGateway {172.16.2.0/24}   VirtualNetworkGateway {13.64.109.168}

原則として、仮想ネットワークゲートウェイが BGP で広報できるアドレス帯は次の2つのみです。

  • 仮想ネットワークゲートウェイが存在している仮想ネットワークのアドレス帯
  • 仮想ネットワークゲートウェイが存在している仮想ネットワークと VNet Peering で接続している仮想ネットワーク(ただし、VNet Peering 上でゲートウェイ転送の設定が必要)

そのため、仮想ネットワークゲートウェイが存在する左の仮想ネットワークの 172.16.1.0/24 や、その隣の NAT 用仮想ネットワークの 172.16.2.0/24 と 172.16.20.0/24 は広報されます。ですが、仮想ネットワークゲートウェイの存在する左の仮想ネットワークの隣の隣であり直接 VNet Peering していない右の仮想ネットワークで利用されている 172.16.3.0/24 は、オンプレミスに広報されません。

そのため、オンプレミスの仮想ネットワーク上の仮想マシンは、NAT 用仮想マシンが実現する宛先 NAT 経由であれば 172.16.3.0/24 上の仮想マシンにアクセスできます。NAT 用仮想マシンが利用している 172.16.2.65 や 172.16.20.5 は、仮想ネットワークゲートウェイがオンプレミスに広報しているからです。

ただし、今のままでは通信ができません。通信経路上の左の仮想ネットワーク上の仮想ネットワークゲートウェイが、宛先 NAT 用アドレス(172.16.2.64/26 と 172.16.20.0/24)宛ての通信を NAT 用仮想マシンに転送しないからです。そこで、仮想ネットワークゲートウェイが存在する GatewaySubnet にも「宛先 NAT で利用するアドレス帯(172.16.2.64/26と172.16.20.0/24)のネクストホップは 172.16.2.7」というユーザ定義ルートを設定します。

さらに、戻りのルーティングを考慮する必要があります。右の仮想ネットワーク上に「192.168.1.0/24 のネクストホップは 172.16.2.7」というユーザ定義ルートを追加します。

> $res = Get-AzRouteTable -ResourceGroupName vnetnat -Name rtVnetRIght
> $res.Routes | ft AddressPrefix,  NextHopType, NextHopIpAddress

AddressPrefix  NextHopType      NextHopIpAddress
-------------  -----------      ----------------
172.16.1.0/24  VirtualAppliance 172.16.2.7
192.168.1.0/24 VirtualAppliance 172.16.2.7

これらの設定によって、ルーティングがもろもろ整うので、一番左の VNET 上の仮想マシンからも宛先 NAT 用の IP アドレスに対して通信できるようになります。

# 192.168.1.5 から 172.16.2.65 への通信が成功
vnetOnpreVm:~$ curl 172.16.2.65
{"RemoteAddr":"192.168.1.5:50184","RequestURI":"/","Xforwardedfor":"","Host":"172.16.2.65","XAzureFDID":"","XAzureFDHP":""}

# 192.168.1.5 から 172.16.20.5 への通信が成功
vnetOnpreVm:~$ curl 172.16.20.5
{"RemoteAddr":"192.168.1.5:48202","RequestURI":"/","Xforwardedfor":"","Host":"172.16.20.5","XAzureFDID":"","XAzureFDHP":""}

ケースその3:送信元 NAT

次は送信元 NAT です。一番右の仮想ネットワークで「192.168.1.0/24 のネクストホップは NAT 用仮想マシン」をいうルーティングを設定できないときに利用する手法です。

一番右のネットワークから「192.168.1.0/24 のネクストホップは NAT 用仮想マシン」というルーティングを消すと、オンプレの仮想ネットワークから宛先 NAT 用 IP アドレス経由の通信は失敗します。行きのパケットは右の仮想ネットワーク上の仮想マシンに到達しますが、戻りのパケットが返ってこないためです。

# 右の仮想ネットワークには「192.168.1.0/24 のネクストホップは NAT 用仮想マシン」のルーティングが存在しない
> Get-AzEffectiveRouteTable -NetworkInterfaceName vnetRightVmNic -ResourceGroupName vnetnat | Select-Object State,Source, AddressPrefix, NextHopType,NextHopIpAddress | ft *

State  Source  AddressPrefix    NextHopType      NextHopIpAddress
-----  ------  -------------    -----------      ----------------
Active Default {172.16.3.0/24}  VnetLocal        {}
Active Default {172.16.2.0/24}  VNetPeering      {}
Active Default {172.16.20.0/24} VNetPeering      {}
Active Default {0.0.0.0/0}      Internet         {}
Active User    {172.16.1.0/24}  VirtualAppliance {172.16.2.7}
# 宛先 NAT 用の IP アドレスへの通信の応答が返ってこないので、ctrl+c で停止
vnetOnpreVm:~$ curl 172.16.2.65
^C
vnetOnpreVm:~$ curl 172.16.20.5
^C

この状況下で通信できるようにするため、NAT 用仮想マシンが 192.168.1.0/24 から届いたパケットを右の仮想ネットワーク上の仮想マシンに転送する際に、パケットの送信元 IP アドレスを NAT 用仮想マシンのアドレスに変換します。

:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING -d 172.16.2.65/32 -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.16.3.5:80
-A PREROUTING -d 172.16.20.5/32 -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.16.3.5:80

# 送信元 NAT の設定を追加
-A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE

こうすることで、右の仮想ネットワーク上の仮想マシンに到達するパケットの送信元 IP アドレスが 172.16.2.5 に変わります。一番右の仮想ネットワークは VNET Peering 経由で 172.16.2.0/24 のルーティングを学習しているので、戻りのパケットが無事に NAT 用仮想マシンに戻って通信が成立します。

# 192.168.1.5 から 172.16.2.65 への通信が成功
# ただし、SNAT によって、一番右の仮想マシンが受け取った HTTP リクエストの送信元 IP アドレス(RemoteAddr)が NAT 用仮想マシンの IP アドレスになっている
vnetOnpreVm:~$ curl 172.16.2.65
{"RemoteAddr":"172.16.2.5:43146","RequestURI":"/","Xforwardedfor":"","Host":"172.16.2.65","XAzureFDID":"","XAzureFDHP":""}

# 192.168.1.5 から 172.16.20.5 への通信が成功
# ただし、SNAT によって、一番右の仮想マシンが受け取った HTTP リクエストの送信元 IP アドレス(RemoteAddr)が NAT 用仮想マシンの IP アドレスになっている
vnetOnpreVm:~$ curl 172.16.20.5
{"RemoteAddr":"172.16.2.5:43410","RequestURI":"/","Xforwardedfor":"","Host":"172.16.20.5","XAzureFDID":"","XAzureFDHP":""}

なお、逆の通信、つまり一番右の仮想マシンからオンプレミスの仮想マシンへの通信も、同じ要領でもろもろを整えれば通信できます。

*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING -d 172.16.2.65/32 -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.16.3.5:80
-A PREROUTING -d 172.16.20.5/32 -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.16.3.5:80

# NAT 用仮想ネットワークの一部のアドレスをオンプレの仮想ネットワーク上の仮想マシンの IP アドレスに宛先 NAT
-A PREROUTING -d 172.16.20.6/32 -i eth0 -p tcp -m tcp --dport 22 -j DNAT --to-destination 192.168.1.5:22
-A PREROUTING -d 172.16.2.66/32 -i eth0 -p tcp -m tcp --dport 22 -j DNAT --to-destination 192.168.1.5:22

-A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE
# NAT 用仮想マシンを通るときに、右の仮想ネットワーク上の仮想マシンの送信元 IP アドレスを NAT 用仮想マシンの IP アドレスに SNAT
-A POSTROUTING -s 172.16.3.0/24 -o eth0 -j MASQUERADE
COMMIT
# 右の仮想ネットワーク上の仮想マシンから、宛先 NAT 用 IP を通じてオンプレの仮想ネットワーク上のの仮想マシンに SSH できている
# 送信元 NAT しているので、ログに記録されている IP アドレスが 172.16.3.5 ではなく 172.16.2.5 になっている。
root@vnetRightVm:~# ssh username@172.16.20.6
vnetOnpreVm:~# cat /var/log/auth.log

Feb  9 10:25:16 vnetOnpreVm sshd[23799]: PAM 1 more authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=172.16.2.5  user=root
Feb  9 10:25:25 vnetOnpreVm sshd[23851]: Accepted password for username from 172.16.2.5 port 35138 ssh2

番外編:仮想ネットワーク上に存在しないアドレス帯での宛先 NAT

これまでは、Azure 仮想ネットワーク上に存在するアドレス帯を利用して宛先 NAT を実現しました。やるかどうかは別として、Azure 仮想ネットワーク上に存在しないアドレス帯でも宛先 NAT は実現できます。やることは同じです。ユーザ定義ルートを利用して行きと戻りのルーティングを整えるだけです。

-A PREROUTING -d 172.16.2.65/32 -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.16.3.5:80
-A PREROUTING -d 172.16.20.5/32 -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.16.3.5:80
-A PREROUTING -d 172.16.20.6/32 -i eth0 -p tcp -m tcp --dport 22 -j DNAT --to-destination 192.168.1.5:22
-A PREROUTING -d 172.16.2.66/32 -i eth0 -p tcp -m tcp --dport 22 -j DNAT --to-destination 192.168.1.5:22

# Azure 仮想ネットワークのアドレス空間に存在しない 172.16.30.5 を宛先 NAT に 追加
-A PREROUTING -d 172.16.30.5/32 -i eth0 -p tcp -m tcp --dport 22 -j DNAT --to-destination 172.16.3.5:80

## 左の仮想ネットワーク上の仮想マシンから右の仮想ネットワーク上の仮想マシンに通信成功
vnetLeftVm:~$ curl 172.16.30.5
{"RemoteAddr":"172.16.1.5:44414","RequestURI":"/","Xforwardedfor":"","Host":"172.16.30.5","XAzureFDID":"","XAzureFDHP":""}

ただし、オンプレミスのネットワークから宛先 NAT 経由で右のネットワーク上の仮想マシンにはアクセスできません。なぜなら Azure 仮想ネットワーク上に存在しない 172.16.30.0/24 のアドレスを仮想ネットワークゲートウェイが BGP で広報しないからです。

# オンプレの仮想ネットワーク上の仮想マシンの有効なルート
# 172.16.30.0/24 が存在しない
> Get-AzEffectiveRouteTable -NetworkInterfaceName vnetOnpreVmNic -ResourceGroupName vnetnat | Select-Object State,Source, AddressPrefix, NextHopIpAddress

State  Source                AddressPrefix    NextHopIpAddress
-----  ------                -------------    ----------------
Active Default               {192.168.1.0/24} {}
Active VirtualNetworkGateway {172.16.1.69/32} {13.64.109.168}
Active VirtualNetworkGateway {172.16.2.0/24}  {13.64.109.168}
Active VirtualNetworkGateway {172.16.20.0/24} {13.64.109.168}
Active VirtualNetworkGateway {172.16.1.68/32} {13.64.109.168}
Active VirtualNetworkGateway {172.16.1.0/24}  {13.64.109.168}

ここで最後のポイントである「宛先 NAT で利用するアドレス帯をオンプレミスにも広報する」が登場します。以前はどうしようもなかったのですが、現在は Azure Route Server を利用することでこの困りごとを解決できます。

Route Server 設置後の構成図

Azure Route Server に対して BGP で経路を広報すると、Route Server がその経路を仮想ネットワークに注入してくれます。というわけで、今回は左の仮想ネットワーク上の仮想マシンに frr をインストールして、経路広報マシンにします。Azure Route Server は BGP の NEXT_HOP 属性に対応しているので、「宛先 NAT 用の 172.16.30.0/24 の宛先は 172.16.2.7」というルーティングを BGP で Azure Route Server に広報します。

Current configuration:
!
frr version 8.1
frr defaults traditional
hostname vnetLeftVm
log file /var/log/frr.log
log stdout informational
log syslog
no ip forwarding
no ipv6 forwarding
service integrated-vtysh-config
!
ip route 0.0.0.0/0 172.16.1.1
ip route 172.16.30.0/24 lo
!
router bgp 65512
 bgp router-id 172.16.1.5
 bgp log-neighbor-changes
 no bgp ebgp-requires-policy
 neighbor 172.16.1.132 remote-as 65515
 neighbor 172.16.1.132 ebgp-multihop 255
 neighbor 172.16.1.133 remote-as 65515
 neighbor 172.16.1.133 ebgp-multihop 255
 !
 address-family ipv4 unicast
  network 172.16.30.0/24
  neighbor 172.16.1.132 route-map 1 out
  neighbor 172.16.1.133 route-map 1 out
 exit-address-family
exit
!
route-map 1 permit 1
 set ip next-hop 172.16.2.7
exit
!
end

そうすると、左の仮想ネットワーク上の仮想マシンの有効なルートに、仮想ネットワークゲートウェイから学習した「172.16.30.0/24 のネクストホップは 172.16.2.7」のルーティングが出てきます。

> Get-AzEffectiveRouteTable -NetworkInterfaceName vnetleftVmNic -ResourceGroupName vnetnat | Select-Object State,Source, AddressPrefix, NextHopIpAddress

State   Source                AddressPrefix    NextHopIpAddress
-----   ------                -------------    ----------------
Active  Default               {172.16.1.0/24}  {}
Active  Default               {172.16.2.0/24}  {}
Invalid Default               {172.16.20.0/24} {}
Active  VirtualNetworkGateway {192.168.1.0/24} {172.16.1.69}
Active  VirtualNetworkGateway {192.168.1.0/24} {172.16.1.68}
Invalid VirtualNetworkGateway {172.16.30.0/24} {172.16.2.7}
Active  User                  {172.16.3.0/24}  {172.16.2.7}
Active  User                  {172.16.2.64/26} {172.16.2.7}
Active  User                  {172.16.20.0/24} {172.16.2.7}
Active  User                  {172.16.30.0/24} {172.16.2.7}

さらに Router Server で Branch-to-Branch のオプションを有効化すると、Router Server と仮想ネットワークゲートウェイが BGP で経路交換します。

# Branch to Branch が無効な状態
# 仮想ネットワークゲートウェイ上に 172.16.30.0/24 が存在しない
> Get-AzVirtualNetworkGatewayLearnedRoute -VirtualNetworkGatewayName vnetleftVpnGw -ResourceGroupName vnetnat | ft *

LocalAddress Network          NextHop       SourcePeer    Origin  AsPath Weight
------------ -------          -------       ----------    ------  ------ ------
172.16.1.69  172.16.1.0/24                  172.16.1.69   Network         32768
172.16.1.69  172.16.2.0/24                  172.16.1.69   Network         32768
172.16.1.69  172.16.20.0/24                 172.16.1.69   Network         32768
172.16.1.69  192.168.1.0/24   192.168.1.126 192.168.1.126 EBgp    65514   32768
172.16.1.69  192.168.1.0/24   172.16.1.68   172.16.1.68   IBgp    65514   32768
172.16.1.69  192.168.1.126/32               172.16.1.69   Network         32768
172.16.1.69  192.168.1.126/32 172.16.1.68   172.16.1.68   IBgp            32768
172.16.1.68  172.16.1.0/24                  172.16.1.68   Network         32768
172.16.1.68  172.16.2.0/24                  172.16.1.68   Network         32768
172.16.1.68  172.16.20.0/24                 172.16.1.68   Network         32768
172.16.1.68  192.168.1.0/24   192.168.1.126 192.168.1.126 EBgp    65514   32768
172.16.1.68  192.168.1.0/24   172.16.1.69   172.16.1.69   IBgp    65514   32768
172.16.1.68  192.168.1.126/32               172.16.1.68   Network         32768
172.16.1.68  192.168.1.126/32 172.16.1.69   172.16.1.69   IBgp            32768

# Branch to Branch が有効な状態
# 仮想ネットワークゲートウェイ上に 172.16.30.0/24 がする。ソース IP アドレスの 172.16.1.132 と 172.16.1.133 は Route Server の IP アドレス
> Get-AzVirtualNetworkGatewayLearnedRoute -VirtualNetworkGatewayName vnetleftVpnGw -ResourceGroupName vnetnat | ft *

LocalAddress Network          NextHop       SourcePeer    Origin  AsPath Weight
------------ -------          -------       ----------    ------  ------ ------
172.16.1.69  172.16.1.0/24                  172.16.1.69   Network         32768
172.16.1.69  172.16.2.0/24                  172.16.1.69   Network         32768
172.16.1.69  172.16.20.0/24                 172.16.1.69   Network         32768
172.16.1.69  192.168.1.0/24   192.168.1.126 192.168.1.126 EBgp    65514   32768
172.16.1.69  192.168.1.0/24   172.16.1.68   172.16.1.68   IBgp    65514   32768
172.16.1.69  192.168.1.126/32               172.16.1.69   Network         32768
172.16.1.69  192.168.1.126/32 172.16.1.68   172.16.1.68   IBgp            32768
172.16.1.69  172.16.30.0/24   172.16.2.7    172.16.1.132  IBgp    65512   32768
172.16.1.69  172.16.30.0/24   172.16.2.7    172.16.1.133  IBgp    65512   32768
172.16.1.68  172.16.1.0/24                  172.16.1.68   Network         32768
172.16.1.68  172.16.2.0/24                  172.16.1.68   Network         32768
172.16.1.68  172.16.20.0/24                 172.16.1.68   Network         32768
172.16.1.68  192.168.1.0/24   192.168.1.126 192.168.1.126 EBgp    65514   32768
172.16.1.68  192.168.1.0/24   172.16.1.69   172.16.1.69   IBgp    65514   32768
172.16.1.68  192.168.1.0/24   172.16.1.69   172.16.1.133  IBgp    65514   32768
172.16.1.68  192.168.1.0/24   172.16.1.69   172.16.1.132  IBgp    65514   32768
172.16.1.68  192.168.1.126/32               172.16.1.68   Network         32768
172.16.1.68  192.168.1.126/32 172.16.1.69   172.16.1.69   IBgp            32768
172.16.1.68  172.16.30.0/24   172.16.2.7    172.16.1.132  IBgp    65512   32768
172.16.1.68  172.16.30.0/24   172.16.2.7    172.16.1.133  IBgp    65512   32768

仮想ネットワークゲートウェイは、Route Server から学習した 172.16.30.0/24 の経路をオンプレミスに広報します。その結果、オンプレミスには 172.16.30.0/24 のルーティングが存在するようになります。

# オンプレミスの仮想ネットワーク上の仮想マシンの有効なルート
> Get-AzEffectiveRouteTable -NetworkInterfaceName vnetOnpreVmNic -ResourceGroupName vnetnat | Select-Object State,Source, AddressPrefix, NextHopIpAddress

State  Source                AddressPrefix    NextHopIpAddress
-----  ------                -------------    ----------------
Active Default               {192.168.1.0/24} {}
Active VirtualNetworkGateway {172.16.1.69/32} {13.64.109.168}
Active VirtualNetworkGateway {172.16.30.0/24} {13.64.109.168}
Active VirtualNetworkGateway {172.16.20.0/24} {13.64.109.168}
Active VirtualNetworkGateway {172.16.2.0/24}  {13.64.109.168}
Active VirtualNetworkGateway {172.16.1.68/32} {13.64.109.168}
Active VirtualNetworkGateway {172.16.1.0/24}  {13.64.109.168}

やっとのことでオンプレミスの仮想ネットワークに宛先 NAT 用で利用する 172.16.30.0/24 のルーティングを持たせられました。その結果、オンプレの仮想ネットワーク上の仮想マシンから宛先 NAT 経由で右の仮想ネットワーク上の仮想マシンにアクセスできます。

# オンプレミスのオンプレのマシンから右の仮想マシンに通信成功
# RemoteAddr が 192.168.1.5 のままなので、送信元 NAT なしで右の仮想マシンに到達できている
vnetOnpreVm:~$ curl 172.16.30.5
{"RemoteAddr":"192.168.1.5:54702","RequestURI":"/","Xforwardedfor":"","Host":"172.16.30.5","XAzureFDID":"","XAzureFDHP":""}vnetOnpreVm:~$ 

Note

今回の検証では、あまり深いことを考えずに、左の仮想ネットワーク上の仮想マシンを経路広報マシンにしてしまいました。ですが、本来は NAT 用仮想マシンを経路広報マシンにした方がよいです。経路広報マシンが停止すると、オンプレミスに対する経路の広報も止まります。別の仮想マシンに経路の広報をゆだねる構成は、生殺与奪の件を他人に握らせることになってしまいます。

まとめ

今回のエントリでは、仮想ネットワーク上で NAT を実際に組んでみることを通じて、次の大事なポイントを説明しました。

  1. ユーザ定義ルートを利用して、 仮想ネットワークに、NAT 用仮想マシンが NAT で利用するアドレス帯のルーティングを追加する
  2. ユーザ定義ルートを利用して、仮想ネットワークに、自動的にルーティングを学習しないアドレス帯のルーティングを追加する
  3. 宛先 NAT で利用するアドレス帯をオンプレミスにも広報する。Azure 上に存在しないアドレス帯を利用する場合には Route Server を使う

仮想ネットワークの仕様を理解したうえで通信経路上のルーティングを整えるのは結構な手間です。1つでも間違えると通信できません。NAT の利用は計画的に。

Note

  • 当サイトは個人のブログです。このブログに示されている見解や意見は個人的なものであり、所属組織の見解や意見を表明するものではありません。
  • 公開情報を踏まえて正確な情報を掲載するよう努めますが、その内容の完全性や正確性、有用性、安全性、最新性について一切保証しません。
  • 添付文章やリンク先などを含む本サイトの内容は作成時点でのものであり、予告なく変更される場合があります。