[Oracle Cloud] IPsec VPN の上限を緩和する SaaS 型ネットワークデザインを検証してみた

# はじめに

Oracle Cloud を使って、自分たちが持っているサービスを SaaS として展開するときに、ネットワーク構成は悩みポイントです。求められるセキュリティ要件に応じて、サーバーやネットワークやサービスを、どこまで共有するのか、どこから分離するのかを考えながら、設計していくのはなかなか骨の折れる作業です。

Oracle Cloud には Architecture Center という名前で、Oracle が考えるリファレンスアーキテクチャーがたくさん公開されています。その中に、SaaS アプリケーションをマルチテナントでホスティングするリファレンスアーキテクチャがあります。これは、Oracle Cloud の環境やサーバー、ネットワークをエンドユーザーごとに分離して提供している構成です。

https://docs.oracle.com/en/solutions/design-infra-saas/index.html#GUID-CF390239-C834-4A8E-A0B0-40FAFAA8F771

![saas-isv-multitenant-architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/f073ff17-a5f6-09cb-19a4-eac5de3df077.png)



なにやら複雑な構成ですね。OCI の仮想ネットワーク (VCN) の各種上限を緩和するために、このような構成になっています。ポイントは何点かあります。

- 全テナントを共通的に管理する Management SUBNET  (一番上)
- 各テナントごとに OCI テナンシーを提供している Tenant VCN (一番下)
- 一番上と一番下を接続するために、Linux 仮想マシンを使ったルーターでルーティング
- 同様に、クロス・テナンシー・ピアリングを使い、複数の OCI テナンシーを接続



テナンシーを複数使うことで、IPsec VPN などの接続の上限や、環境の分離を実現できます。ただ、見ればわかるようにだいぶネットワーク的に複雑な構成です。ネットワークセグメントの重複を許さない部分もありそうです。ということで、今回の記事では、このリファレンスアーキテクチャを基に検証してみてわかったこと、注意しないといけないことをご紹介します。



# 構成図

まず、検証した全体の構成図を乗せます。文字が小さい画像なので、拡大してみてもらえると嬉しいです (画像の中の、具体的なIP アドレスは既に削除しています)

構成図の内容を簡単に説明します。

- 一番左の 疑似On-Premise : オンプレミス環境。IPsec VPN を使って OCI に接続。OCI 環境を疑似的にオンプレミスと見立てて使っている
- 真ん中の Tenancy : 各エンドユーザーごとに用意する OCI テナント環境。他のテナント環境とは分離されている専用の環境
- 右側の Tenancy にある VCN (customerX) : 共通の管理サブネット(manage) から各エンドユーザーのテナント環境に接続するためのネットワーク。ここを専用にするのか、共有にするのかで、収容できるテナント数の上限が変動する (後述)
- 一番右の VCN (manage) : 各テナンシーに共通に接続できるマネジメントサブネット。manage からどこまで接続させるかによって、ネットワークの重複禁止範囲が変動する (後述)
- router : Linux で作成したルーター。2つの VCN に NIC を伸ばして、ルーティングをしている。この記事では、ルーターをシングル構成にしているが、冗長構成にしたい場合は、Pacemaker や Corosync を使って実施すると良い。[参考](https://qiita.com/mmarukaw/items/66fac6c8e0843df6b7c0)

![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/11cfa11c-4259-a02d-fd65-467f4ee4f10b.png)



各VCN や LPG(Local Peering Gateway), DRG(Dynamic Routing Gateway), SGW(Service Gateway) などに、複雑な Route Table を設定することで、各環境間のルーティングをコントロールしています。詳細に Route Table を書いたので、これを参考に設定すると通信出来ます。



# 通信出来る範囲

今回の検証では、通信出来る範囲を次のように設定しました。

- 緑色 : 通信出来る経路

- 赤色 : 通信出来ない経路

![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/84cdf56a-f9f0-a928-30c7-c7ae93070423.png)



赤色の矢印の部分は、エンドユーザーの環境から、共通管理用のマネジメントセグメントへ直接アクセスを禁止しています。それ以外の緑色の矢印経路は直接通信出来ます。理由はいくつかあります

- エンドユーザー環境から、共通管理用マネジメントセグメントに通信する要件は無さそう (セキュリティ的にも辞めたほうが良さそう)
- エンドユーザー環境から、共通管理用マネジメントセグメントに通信をさせた場合、各エンドユーザーのIP アドレス範囲の重複が出来ない

2点目の重複が出来ない事について、次の画像で説明します。
紫色の Route Rule を追加すれば、エンドユーザー環境と共通管理用マネジメントセグメントが直接通信できます。ただ、吹き出しで書いている通り、エンドユーザー環境の IP アドレスが重複していると、宛先 `10.200.0.0/16` が同じになってしまい、共通管理用の Route Table に Route Rule を設定できません。エンドユーザー環境が全て重複していないネットワークなら問題ないのですが、現実的にありえなく、重複してしまう可能性があります。直接通信をさせないことで、エンドユーザーのネットワークの重複を許容できるため、柔軟なメリットがあります。

![003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/28a25174-61db-d4a8-5e7a-4382fd8775f0.png)



# ネットワーク重複禁止制限

ただ、この構成でも1点だけネットワークの重複が出来ない部分があります。エンドユーザー環境と共通管理ネットワークの部分です (薄いピンク色の部分)
重複することで、吹き出しで書いている Route Table の `192.168.0.0/24` 宛の通信の宛先が設定できません。共通管理サブネットに、Zabbix などの管理用のソフトウェアを入れて全テナント環境を統合管理したい用途がありますが、これが制限されてしまう構成になります。

![004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/00203428-1721-e351-e755-eb71b7c5c4f5.png)



じゃあどうすればいいのかというと、色々な方法がありますが、次の方法が良いのかなと考えています



重複の可能性を軽減する策

- 共通管理セグメントを出来るだけ珍しいセグメントにする : 主観ですが、クラスA (10.0.0.0～10.255.255.255) の後半の方は重複することが少ない気がします・・・(たぶん)
- BGP を使って、オンプレミスのネットワークを Oracle Cloud へ 広報する時に、必要最低限のネットワークに絞る : 本当に必要なネットワークにのみ絞ってもらうことで、重複の可能性を下げる



重複したときに打開する策 (机上検討のみ。未検証)

- ルーティングではなく、NAT をする

次の画像で説明します。ルーティングをしていた Linux マシンを、NAT に切り替えることで、IP アドレスの重複を打開します。※机上検討のみ。未検証

![005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/e8095b01-f6d0-3511-637f-dfb5ac387645.png)



# Router の注意点

今回の記事では、Linux マシンを仮想ルーターにしています。この仮想ルーターのルーティングについて、注意点があります。

- Primary NIC は、テナント側がお勧め
- 共通管理側のRouting について



まず、仮想ルーターPrimary NIC は、テナント側を向けるのがお勧めです。デフォルトルートをテナント側に向けたほうが、ルーティングの設定が簡単になります。

![006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/07c1d208-0ffa-98ce-7b16-a0d7ebbafaf3.png)



共通管理側のRoutingですが、テナント側と通信させたいマシンは基本的に、ルーターと同一セグメントに配置するのが良いです。別セグメントでも良いのですが、Linux のポリシーベースルーティングに手を加えないと行けなくなるので、多少面倒です。ポリシーベースルーティングを何も意識していないと、共通管理側はルーターと同一セグメントしか通信しないため、注意してください。

![007.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/b7382cb5-7a0b-5854-aaa5-b329f6d00f1c.png)







# スケール上限

今まで説明してきた構成は、若干スケールの上限が低いです。Route Table に設定出来る Route Rule が 100個までの上限がボトルネックになっています。テナント数で考えると、約50テナントほどで上限になります。どこが上限に達するのか、次の画像で説明します。共通管理サブネットの Route Table が上限 100 になることを考慮しています。1テナントあたり、2 Route Rule を消費するので、約50テナントがこの構成の上限です。

![008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/2a0ea6a8-3464-70d6-59e8-3aa8a3b1b670.png)



それ以上のスケールを実現したいときは、Route Rule の割り当て方や、ルーターのルーティング範囲を共有することが考えられます。机上検討ですが、最大限スケールするためのルールを考えてみます。

- 共通管理サブネットの Route Rule の削減をしたい
- 1つの Route Rule に出来るだけたくさんのテナントの収容する
- ルーターが複数のテナンシーを担当する



次の構成が一番スケールする構成だと思います。Route Table の 1 Rule に対して、10個のテナントが収容される形です。各テナントの IP アドレスを連続したものにまとめることで、`10.0.0.0/20` のルールでまとめてルーティングが出来ます。この構成の上限を精査しているわけではないですが、500テナントくらいが上限になるはずです。management の テナントあたり、VCN が 50個までの上限があり、500テナントほどと想像しました (VCN の作成上限緩和すれば、1000テナントまではいけそう)

![010.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/44e0a001-3948-c005-edef-50596f958cf1.png)



# Router 構築

ここまでで 構成に関する気になるところを説明しました。あとは参考までに、Linux でルーティングする設定を紹介します。OCI 上で、適当に Oracle Linux を構築します。Cent OS でも良いです。忘れずに、Primary NIC をカスタマーテナンシー側に向けるように構築しましょう。



## vNIC の構成

仮想マシンの構築直後は NIC は1つです。実際に Linux に SSH ログインして確認しています。デフォルトルートが、カスタマーテナンシー側の GW となっています。

```
[opc@router1 ~]$ ip -d a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0 minmtu 0 maxmtu 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 02:00:17:00:b7:1c brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 68 maxmtu 65535 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 172.16.0.3/24 brd 172.16.0.255 scope global dynamic ens3
       valid_lft 86304sec preferred_lft 86304sec
[opc@router1 ~]$
[opc@router1 ~]$ ip r
default via 172.16.0.1 dev ens3
169.254.0.0/16 dev ens3 proto static scope link
169.254.0.0/16 dev ens3 scope link metric 1002
172.16.0.0/24 dev ens3 proto kernel scope link src 172.16.0.3
[opc@router1 ~]$
```



vNIC の設定変更をします。Prymary VNIC を分かりやすい名前に変更

![1605275246719.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/5e81cf80-5bd4-36e9-2761-5f997b92407a.png)



変更。SKIP SOURCE/DESTINATION CHECK の ON を忘れずに入れましょう

![1605278498477.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/9648bea0-a7d6-a31a-e129-06e59c818e93.png)



2個目の vNIC を作成します。Create VNIC

![1605275329959.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/62fa9415-058b-cda2-ad7f-0d9d0698aeba.png)



Create

![1605278579479.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/0fb19540-8e3c-6999-8893-9af11a168165.png)



2つの vNIC が出来ました

![1605278612815.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/71ef0a8b-041e-619f-ddfe-d5ffb29d74dd.png)



Linux の中で確認すると、NIC は認識しているがIP アドレスはありません。色々方法はありますが、ocid サービスを使うのが楽です。

```
[opc@router1 ~]$ ip -d a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0 minmtu 0 maxmtu 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 02:00:17:00:b7:1c brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 68 maxmtu 65535 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 172.16.0.3/24 brd 172.16.0.255 scope global dynamic ens3
       valid_lft 86133sec preferred_lft 86133sec
3: ens5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 02:00:17:00:36:1e brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 68 maxmtu 65535 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
[opc@router1 ~]$
```



oci-utils パッケージに含まれる ocid サービスを起動 (約60秒ほどまつ)

```
sudo systemctl enable ocid
sudo systemctl start ocid
```



正常に起動できていればOKです

```
[opc@router1 ~]$ sudo systemctl status ocid
● ocid.service - Oracle Cloud Infrastructure utilities daemon
   Loaded: loaded (/etc/systemd/system/ocid.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2020-11-13 14:48:13 GMT; 52s ago
 Main PID: 11659 (python3)
   CGroup: /system.slice/ocid.service
           └─11659 /usr/bin/python3 /usr/lib/python3.6/site-packages/oci_utils/impl/ocid-main.py --no-daemon

Nov 13 14:48:13 router1 sudo[13107]:     root : TTY=unknown ; PWD=/ ; USER=root ; COMMAND=/usr/sbin/ip link set dev...000 up
Nov 13 14:48:13 router1 sudo[13112]:     root : TTY=unknown ; PWD=/ ; USER=root ; COMMAND=/bin/mkdir --parents /etc...onf.d/
Nov 13 14:48:13 router1 sudo[13116]:     root : TTY=unknown ; PWD=/ ; USER=root ; COMMAND=/usr/bin/touch /etc/Netwo...E.conf
Nov 13 14:48:13 router1 sudo[13120]:     root : TTY=unknown ; PWD=/ ; USER=root ; COMMAND=/bin/sh -c /usr/bin/cat >...E.conf
Nov 13 14:48:13 router1 sudo[13125]:     root : TTY=unknown ; PWD=/ ; USER=root ; COMMAND=/bin/cp --archive /etc/ip...es.bck
Nov 13 14:48:13 router1 sudo[13129]:     root : TTY=unknown ; PWD=/ ; USER=root ; COMMAND=/bin/sh -c /usr/bin/cat >...tables
Nov 13 14:48:13 router1 sudo[13133]:     root : TTY=unknown ; PWD=/ ; USER=root ; COMMAND=/bin/rm -f /etc/iproute2/...es.bck
Nov 13 14:48:13 router1 sudo[13138]:     root : TTY=unknown ; PWD=/ ; USER=root ; COMMAND=/usr/sbin/ip route add de...e ort3
Nov 13 14:48:13 router1 sudo[13142]:     root : TTY=unknown ; PWD=/ ; USER=root ; COMMAND=/usr/sbin/ip rule add fro...p ort3
Nov 13 14:48:13 router1 systemd[1]: Started Oracle Cloud Infrastructure utilities daemon.
Hint: Some lines were ellipsized, use -l to show in full.
[opc@router1 ~]$
```



2つ目の Interface に IP アドレスが設定されています

```
[opc@router1 ~]$ ip -d a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0 minmtu 0 maxmtu 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 02:00:17:00:b7:1c brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 68 maxmtu 65535 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 172.16.0.3/24 brd 172.16.0.255 scope global dynamic ens3
       valid_lft 85791sec preferred_lft 85791sec
3: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 02:00:17:00:36:1e brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 68 maxmtu 65535 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 192.168.0.4/24 scope global ens5
       valid_lft forever preferred_lft forever
[opc@router1 ~]$
```



route table も反映されています。

```
[opc@router1 ~]$ ip r
default via 172.16.0.1 dev ens3
169.254.0.0/16 dev ens3 proto static scope link
169.254.0.0/16 dev ens3 scope link metric 1002
172.16.0.0/24 dev ens3 proto kernel scope link src 172.16.0.3
192.168.0.0/24 dev ens5 proto kernel scope link src 192.168.0.4
[opc@router1 ~]$
```



ポリシーベースルーティングが採用されています。

```
[opc@router1 ~]$ routel
         target            gateway          source    proto    scope    dev tbl
        default        192.168.0.1                                     ens5 ort3
        default         172.16.0.1                                     ens3
   169.254.0.0/ 16                                   static     link   ens3
   169.254.0.0/ 16                                              link   ens3
    172.16.0.0/ 24                      172.16.0.3   kernel     link   ens3
   192.168.0.0/ 24                     192.168.0.4   kernel     link   ens5
      127.0.0.0          broadcast       127.0.0.1   kernel     link     lo local
     127.0.0.0/ 8            local       127.0.0.1   kernel     host     lo local
      127.0.0.1              local       127.0.0.1   kernel     host     lo local
127.255.255.255          broadcast       127.0.0.1   kernel     link     lo local
     172.16.0.0          broadcast      172.16.0.3   kernel     link   ens3 local
     172.16.0.3              local      172.16.0.3   kernel     host   ens3 local
   172.16.0.255          broadcast      172.16.0.3   kernel     link   ens3 local
    192.168.0.0          broadcast     192.168.0.4   kernel     link   ens5 local
    192.168.0.4              local     192.168.0.4   kernel     host   ens5 local
  192.168.0.255          broadcast     192.168.0.4   kernel     link   ens5 local
            ::/ 96     unreachable                                       lo
::ffff:0.0.0.0/ 96     unreachable                                       lo
    2002:a00::/ 24     unreachable                                       lo
   2002:7f00::/ 24     unreachable                                       lo
   2002:a9fe::/ 32     unreachable                                       lo
   2002:ac10::/ 28     unreachable                                       lo
   2002:c0a8::/ 32     unreachable                                       lo
   2002:e000::/ 19     unreachable                                       lo
   3ffe:ffff::/ 32     unreachable                                       lo
[opc@router1 ~]$
```



ポリシーベースルーティング関連の確認

```
[opc@router1 ~]$ ip rule show
0:      from all lookup local
32765:  from 192.168.0.4 lookup ort3
32766:  from all lookup main
32767:  from all lookup default
[opc@router1 ~]$
```



ポリシーベースルーティング関連の確認

```
[opc@router1 ~]$ ip route show table ort3
default via 192.168.0.1 dev ens5
[opc@router1 ~]$
```



## Routing 設定

Linux がルーターになる設定を入れます。カーネルパラメーターに `ip_forward` の設定が有ります。デフォルトだと 0 になっていて、これを 1 にすることで、ルーティングしてくれます。

```
[opc@router1 ~]$ cat /proc/sys/net/ipv4/ip_forward
0
```



sysctl.conf を編集します

```
sudo vim /etc/sysctl.conf
```



次の一文を追記します

```
net.ipv4.ip_forward = 1
```



反映コマンド

```
sudo sysctl -p
```



確認すると、1になっています

```
[opc@router1 ~]$ cat /proc/sys/net/ipv4/ip_forward
1
```



firewalld(iptables) のルールでルーティングが遮断されるので、これも止めます

```
sudo systemctl stop firewalld
sudo systemctl disable firewalld
```



これで Linux を使ったルーターが出来ました。あとは、VCN の Route Table を各種設定していけば、通信が出来るようになります。構成図を参考に、Route Table を設定していくのがお勧めです。



# クロス・テナンシー・ピアリングの構成

LPG を使うことで、テナントをまたいでピアリングが出来ます。詳細はこちらを参考にしてください。

https://qiita.com/sugimount/items/ea3d1c1df8390a9c02e9



# 付録 : 仮想ネットワークの制限

- IPsec VPN : 4 per Region
- CPE : 10 per Region
- VCN : 50 per Region
- Local Peering Gateway : 10 per VCN
- Dynamic Routing Gateway : 5 per Region
- Route Table : 300 per VCN
- Route Rule : 100Route Rule per Route Table

https://docs.cloud.oracle.com/en-us/iaas/Content/General/Concepts/servicelimits.htm
https://docs.cloud.oracle.com/en-us/iaas/Content/Network/Tasks/localVCNpeering.htm
https://docs.cloud.oracle.com/en-us/iaas/Content/Network/Tasks/remoteVCNpeering.htm 



# 参考URL

Architecture Center
https://docs.oracle.com/en/solutions/design-infra-saas/index.html#GUID-CF390239-C834-4A8E-A0B0-40FAFAA8F771

OCI ComputeにセカンダリVNICを追加する Part 1
https://qiita.com/yamada-hakase/items/a6d4d846e4cf4afb9453

OCI ComputeにセカンダリVNICを追加する Part 2
https://qiita.com/yamada-hakase/items/6b0c49a0b2b3c5e4c4dd

OCI ComputeにセカンダリVNICを追加する Part 3
https://qiita.com/yamada-hakase/items/abe8114d327c19c98acd

IP Forwarding を有効
http://safe-linux.homeip.net/network/Gateway_Server-06.html