GREトンネルを使って Oracle Cloud Infrasturcture Classic (Oracle Public Cloud) のNATを超えてプライベート通信する方法

# はじめに
Oracle Cloud Infrastructure Classic (OCI Classic : 旧称Oracle Public Cloud) には、自由にプライベート・ネットワークを構成できるIPネットワークという機能があります。これはクラウドの中でシステムが完結している場合はシンプルで使いやすいのですが、一旦外部のネットワークと通信しようとすると必ずNATを経由する形になります。
このため、NATを越えられないアプリケーション通信(典型的なのはWindowsのリモートアクセス(RAS)や、Windowsクライアントとドメコンの間のKerberos認証など)が必要になった場合に、どうにかしてNATを超えてプライベートIPのまま通信できる構成を行う必要があります。

NATを超えてプライベート通信を行う方法はいくつかありますが、今回はそのうちのGREトンネルを利用する方法について書きたいと思います。

# GREを使う理由と典型的なユースケース
ここまで読んでなぜGRE? と思った方もいると思います。
特にクラウドとプライベートIPで通信する場合IPsecトンネルを利用してVPNを構成する方法が一般的です。今回IPsecではなくGREを使うのは、**「IPsecのように暗号化を行わないのでより軽量に動作する」**というのが理由です。逆に言うと、**通信を暗号化するような要件がある場合にはGREを使わずにIPsecを利用するのがお勧め**です。OCI ClassicにはIPsec通信を行うためのVPNゲートウェイを構築する機能がありますので、素直にこちらを使いましょう。

IPsecではなくGREを使うようなケースとしては、以下のようなものが考えられます。

## ケース1 : Oracle Cloud at Customer (Oracle Cloud Machine)と社内LANなどをプライベート接続する場合
OCI Classicの利用形態のひとつとして、ユーザーのデータセンターにクラウド用のインフラを設置するOracle Cloud at Customerというものがあります。
こちらを利用する場合、クラウド環境がデータセンター内のプライベートなネットワーク内に設置されるため、セキュリティは予め確保されているはずです。NATを超えるためだけに暗号化を行うのはリソースを無駄に消費することになりますので、GREを利用する積極的な理由になります。
データセンター側LANに設置済のActive Directoryを使ってOracle Cloud at Customer内のWindowsサーバー・インスタンスの認証を行うなど、色々な場合に使えるでしょう。

## ケース2 : 専用線/閉域網サービスと組み合わせてオンプレミスとプライベートIPで接続する
OCI Classicまでインターネットではなく専用線や閉域網を利用して接続を行うFastConnectというサービスがあります。このサービスにはグローバルIP(パブリック・ピアリング)を通して接続する形態と、プライベートIPで接続する形態(プライベート・ピアリング)があります。
Oracle Cloudのサービスのうち、グローバルIPでのアクセスが必要なサービス(典型的なものはOracle Storage Cloud)を利用する場合には、パブリック・ピアリングで専用線/閉域網接続をすることが多いですが、この場合でもGREトンネルを利用することで、コンピュート・インスタンス等に対してはプライベートIPで接続することができるようになります。
既に専用線/閉域網サービスでMPLS-VPN等でセキュリティが確保されている
はずなので、GREで充分だと思います。IPsec VPN経由だとスループットがでないという場合にはGREは有効な手段となるでしょう。

## ケース3 : 同一データセンターの別コンピュート・サイトをプライベート接続する場合
現在のOCI Classicでは、同一データセンターであってもコンピュート・サイトが別であれば別のIPネットワークを構成する必要があります。この間をプライベート接続をする場合にはOracle Cloudのデータセンターの内部に閉じた通信で、仮想ネットワークによりセキュリティが分離されているため、GREでも充分な場合があります。
とはいえ重要な情報を平文で流すような使い方を推奨するわけではありませんので、セキュリティ要件に応じてどんな通信を流すかは充分検討してください。

# テスト
今回は、OCI Classicの中に2つのプライベート・ネットワークを構築して、その間をGREトンネルを通して1つの大きなネットワークとしてプライベート接続するテストを行います。ゲートウェイはOracle Linux 7.2のコンピュート・インスタンスを利用し、Linuxカーネルに組み込まれたGRE機能を利用します。ゲートウェイサーバー間のGRE通信は、グローバルIPを使って通信を行います。

以下がテスト環境のモデル図です。

![WIP_Figure_Qiita_記事.png](https://qiita-image-store.s3.amazonaws.com/0/117710/c5c7f82d-7f12-941e-ce8e-f19f22807434.png)

## 準備

今回の手順は、コンピュート・サイトがUSCOM-CENTRAL-1の環境で作成しています。現在作業中のコンピュート・サイトは、Compute Classic サービスコンソールの右上に表示されています。もしサイト名が US00n_Znn のような名前の場合には、下記手順に必要な機能(IPネットワークでの予約IPの取得)が利用できない場合があります。その場合はサイト名をクリックすると立ち上がるサイト・セレクタで、uscom-xxxxx-1 のような名前のサイトを選択してください。

![WS000440.JPG](https://qiita-image-store.s3.amazonaws.com/0/117710/fb366930-daf1-05c9-8e05-fe8842375078.jpeg)

他に uscom-east-1、gbcom-south-1、aucom-east-1 のような名前のサイトや、日本データセンター(AP005_Z11)でも今回の機能は利用することができると思います。

もしサイト・セレクタの選択肢に上記のどのサイトもない場合は、Oracleのサポートにサービス・リクエストを申請すれば、すぐに割り当ててもらえますので、まずその作業を実施してください。

## 1. ネットワークの作成
OCI ClassicのIPネットワークの機能を利用して、2つのネットワークを作成します。
通常はOCI Classicの中と外のネットワークを接続する場合が多いと思いますが、今回は両方OCI Classicの中に作成してテストを行います。

### 1-1. IPネットワーク交換の作成

ipex100、ipex200 という名前のIP交換を2つ作成します。これは後から作成する複数のサブネット(IPネットワーク)をつなぎ合わせて大きなネットワークを作成するのに使用します。

【作業】
Oracle Compute Cloud Classic の管理コンソールから
ネットワーク → IPネットワーク → IP交換
にアクセスし、下記を参考にIP交換を2つ(ipex100、ipex200)作成します。

![WS000431.JPG](https://qiita-image-store.s3.amazonaws.com/0/117710/5b1f5094-8aab-5bb5-0630-c495534e7444.jpeg)

### 1-2. IPネットワークの作成

IPネットワーク(サブネット)を4つ作成し、2つずつをIP交換でまとめます。これで2つのサブネットからなる2つのネットワークが作成されます。

【作業】
ネットワーク → IPネットワーク → IPネットワーク
にアクセスし、下記を参考にIPネットワークを4つ作成します。

|名前|IPアドレス接頭辞|IP交換|
|----|--------------|------|
|ipnet100|192.168.100.0/24|ipex100|
|ipnet101|192.168.101.0/24|ipex100|
|ipnet200|192.168.200.0/24|ipex200|
|ipnet201|192.168.201.0/24|ipex200|

![WS000432.JPG](https://qiita-image-store.s3.amazonaws.com/0/117710/494b49a4-b771-c596-a217-309867ad6c21.jpeg)


## 2. ゲートウェイ・インスタンスの作成
GREトンネルを作成するゲートウェイ・インスタンスを、各ネットワークに1つずつ作成します。

### 2-1. ゲートウェイ用のグローバルIPの取得
GREインスタンスに割り当てるグローバルIPを予め取得しておきます。

【作業】
**ネットワーク** → **IPネットワーク** → **IP予約** にアクセスし **IP予約の作成** ボタンを押します。
立ち上がったウィンドウで、以下を参考に public-ippool から gw100-gip、gw200-gip という2つのIP予約を取得します。
取得したグローバルIPは後で使うので、ここでメモっておくと楽です。

![WS000438.JPG](https://qiita-image-store.s3.amazonaws.com/0/117710/9a88f4dd-b686-c11c-2fed-7bd62f7dbc34.jpeg)

### 2-2. 1つめのゲートウェイ・インスタンスの作成

【作業】
**インスタンス** → **インスタンス** にアクセスし **インスタンスの作成** ボタンを押します。
**クイックスタート** という画面が立ち上がるので **カスタマイズ** ボタンを押します。

![WS000433.JPG](https://qiita-image-store.s3.amazonaws.com/0/117710/532e0ee0-b9c1-0a76-b19e-4f5cbacc376c.jpeg)

**イメージ** 画面で、**Oracleイメージ** から **OL_7.2_UEKR4_X86_64** を選択します

![WS000434.JPG](https://qiita-image-store.s3.amazonaws.com/0/117710/5160b644-ec28-8eb8-fa5a-e830a0ed1581.jpeg)

次の **シェイプ** 画面では任意のシェイプを選択してOKです。今回は汎用のoc3インスタンスを利用しました。

**インスタンス** 画面で、名前に gw100 を入力し、生成済のSSH公開鍵を登録します。

![WS000435.JPG](https://qiita-image-store.s3.amazonaws.com/0/117710/7c6d9d34-2b13-4811-f06c-fd8cd97fd55a.jpeg)

**ネットワーク** 画面では **DNSホスト名接頭辞** に gw100 と入力し **共有ネットワーク** チェックボックスのチェックを外します。その後 **インタフェースの構成** ボタンを押します。

![WS000436.JPG](https://qiita-image-store.s3.amazonaws.com/0/117710/120c3455-81af-45ad-e487-330d6ce78652.jpeg)

立ち上がったウィンドウで、以下を入力してネットワーク・インタフェースを構成します。指定がないものはデフォルトのままでOKです。

|入力項目|入力内容|
|---|---|
|IPネットワーク|ipnet100(192.168.100.0/24)|
|静的IPアドレス|192.168.100.254|
|パブリックIPアドレス|グローバルIPアドレス*(gw100-gip)|
|デフォルトのゲートウェイ|チェックをつける|

*グローバルIPアドレスは環境によって異なります

![WS000439.JPG](https://qiita-image-store.s3.amazonaws.com/0/117710/f3a61881-63d1-eace-41c6-6f257e7ca3ae.jpeg)

**ストレージ** 画面はそのままでOKです。最後に **確認** 画面で間違いがなければ **作成** ボタンを押してインスタンスを作成します。

## 2-3. 2つめのゲートウェイ・インスタンスを作成
2-2 と同じやり方で、もう一つのゲートウェイ・インスタンスを作成します。入力項目はネットワークに合わせて変更します。

|画面|入力項目|入力内容|
|---|---|---|
|イメージ|イメージ|OracleイメージからOL_7.2_UEK4_x86_64を選択|
|シェイプ|シェイプ|oc3|
|インスタンス|名前|gw200|
||SSHキー|SSH公開鍵を登録|
|ネットワーク|DNSホスト名接頭辞|gw200|
||ネットワーク・オプション|共有ネットワークのチェックをはずす|
|IPネットワーク・インタフェースの構成|IPネットワーク|ipnet200(192.168.200.0/24)|
||静的IPアドレス|192.168.200.254|
||パブリックIPアドレスIPネットワーク|グローバルIPアドレス*(gw200-gip)|
||デフォルトのゲートウェイ|チェックをつける|

*グローバルIPアドレスは環境によって異なります

## 3. 通信許可の設定
作成したGWEゲートウェイ・インスタンスが正しく通信できるように設定します。
今回は、ゲートウェイの設定のためのSSHのインバウンド通信と、お互いのインスタンス間のグローバルIPでのGRE通信の許可を設定します。

### 3-1. GREゲートウェイ・インスタンスへのSSH通信の許可
今後の設定のために、インターネットからのSSH通信を許可します。
今回はANYに対してポートを空けますが、必要に応じてIPホワイトリストや踏み台サーバーの利用を検討してください。

【作業】
**ネットワーク** → **IPネットワーク** → **セキュリティ・ルール** にアクセスし **セキュリティ・ルールの作成** ボタンを押します。

以下を参考に、ssh通信の許可設定を行います。
GREゲートウェイのインスタンスは、defaultという事前定義済のアクセス制御リストに紐付いていますので、ここに対してすべてのssh通信の受信を許可します。
もしインスタンスをdefaultではなく個別のアクセス制御リストに紐付けていた場合は、必要に応じて適切なアクセス制御リストを設定してください。

![WS000441.JPG](https://qiita-image-store.s3.amazonaws.com/0/117710/4e829721-8609-7ffc-217f-c1783845af79.jpeg)

### 3-2. GREゲートウェイ・インスタンス間のGRE通信の許可
GREはプロトコル47を利用しますが、このプロトコルはOCI Classicに事前定義されていませんので、まずそれを定義します。

【作業】
**ネットワーク** → **IPネットワーク** → **セキュリティ・プロトコル** にアクセスし **セキュリティ・プロトコルの作成** ボタンを押します。
立ち上がった画面で下記を参考にGREを定義します。

![WS000463.JPG](https://qiita-image-store.s3.amazonaws.com/0/117710/aecd3729-379b-4ebd-2e92-92749c011adf.jpeg)


次に、許可する送信元として利用するために、GREゲートウェイ・インスタンスのグローバルIPを登録します。

【作業】
**ネットワーク** → **IPネットワーク** → **IPアドレス接頭辞セット** にアクセスし **IPアドレス接頭辞セットの作成** ボタンを押します。
立ち上がった画面で、手順2-1でIP予約を取得したときのグローバルIPに名前をつけて登録してください。

![WS000444.JPG](https://qiita-image-store.s3.amazonaws.com/0/117710/6419d13f-77d5-b50c-c97c-c00a4915ced7.jpeg)

アクセス制御リストを作成して、GREゲートウェイ・インスタンスのグローバルIPからのGRE通信を許可します。

【作業】
**ネットワーク** → **IPネットワーク** → **セキュリティ・ルール** にアクセスし **セキュリティ・ルールの作成** ボタンを押します。

以下を参考に、GRE通信の許可設定を行います。
今回は各GREインスタンスのグローバルIPだけを送信元として許可するので、ソースIPアドレス接頭辞セットに先程作成したipaddr-gregwsを設定しています。

<画面ショットをあとで挿入>

## 4. GREトンネルの作成
各GREゲートウェイ・インスタンスで、GREトンネルとインタフェース間でのルーティングを設定します。

### 4-1. IPフォワードの設定
GREトンネル・インタフェースとIPネットワークのインタフェース間でIPフォワードを設定します。
gw100、gw200インスタンスにsshでログインし、sudoで /etc/sysctl.confを編集します。

```vim:/etc/sysctl.conf@gw100/gw200
net.ipv4.ip_forward = 1
```
以下を実行して、変更を反映します。

```shell-session:opc@gw100/gw200
sudo sysctl -p
```

変更の反映を確認します。


```shell-session:opc@gw100/gw200
cat /proc/sys/net/ipv4/ip_forward
1
```

★注意★
今回はテストのため、すべてのインタフェースの間のIPフォワードを許可する設定にしてありますが、本番環境で利用する際には忘れずに iptables などで適切なフィルタリングを設定するようにしてください

## 4-1. GREトンネルの構成

【手順】
gw100インスタンスにopcユーザーでssh接続し、以下を実行します。
今回は、GREトンネル用として gre1 という名前のインタフェースを新しく作成し、192.168.100.253 というアドレスを割り当てています。インタフェース名やアドレスは任意で変更してください。

```shell-session:opc@gw100
sudo ip tunnel add gre1 mode gre local 192.168.100.254 remote <相手側GW(gw200)のグローバルIP> key 1
sudo ip addr add 192.168.100.253/24 dev gre1
sudo ip link set up dev gre1
sudo ip link set gre1 mtu 1460
sudo ip route add 192.168.200.0/24 dev gre1
sudo ip route add 192.168.201.0/24 dev gre1
```

gw200インスタンスでも同じように設定します。こちらは 192.168.200.253 を新しいインタフェースに割り当てます。

```shell-session:opc@gw200
sudo ip tunnel add gre1 mode gre local 192.168.200.254 remote <相手側GW(gw100)のグローバルIP> key 1
sudo ip addr add 192.168.200.253/24 dev gre1
sudo ip link set up dev gre1
sudo ip link set gre1 mtu 1460
sudo ip route add 192.168.100.0/24 dev gre1
sudo ip route add 192.168.101.0/24 dev gre1
```

これで、GREトンネルと、そこを通る相手側ネットワークへの静的ルーティングが構成できました。
pingを打つと、互いのローカルIPのインタフェースに対してアクセスができるようになっています。

```shell-session:opc@gw100
[opc@gw100 ~]$ ip addr list
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 8900 qdisc mq state UP qlen 1000
    link/ether c6:b0:c0:a8:0b:fe brd ff:ff:ff:ff:ff:ff
    inet 192.168.100.254/24 brd 192.168.100.255 scope global dynamic eth0
       valid_lft 584sec preferred_lft 584sec
    inet6 fe80::c4b0:c0ff:fea8:bfe/64 scope link
       valid_lft forever preferred_lft forever
3: gre0@NONE: <NOARP> mtu 1476 qdisc noop state DOWN
    link/gre 0.0.0.0 brd 0.0.0.0
4: gretap0@NONE: <BROADCAST,MULTICAST> mtu 1462 qdisc noop state DOWN qlen 1000
    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
5: gre1@NONE: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1460 qdisc noqueue state UNKNOWN
    link/gre 192.168.100.254 peer 129.150.103.57
    inet 192.168.100.253/24 scope global gre1
       valid_lft forever preferred_lft forever
    inet6 fe80::5efe:c0a8:bfe/64 scope link
       valid_lft forever preferred_lft forever
[opc@gw100 ~]$
[opc@gw100 ~]$ ping -c 3 192.168.200.254
PING 192.168.200.254 (192.168.200.254) 56(84) bytes of data.
64 bytes from 192.168.200.254: icmp_seq=1 ttl=64 time=0.612 ms
64 bytes from 192.168.200.254: icmp_seq=2 ttl=64 time=0.559 ms
64 bytes from 192.168.200.254: icmp_seq=3 ttl=64 time=0.626 ms

--- 192.168.200.254 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.559/0.599/0.626/0.028 ms
[opc@gw100 ~]$
```

## 5. 相手側ネットワークへの静的ルーティングの設定

ここまでで基本的なGREトンネルの設定は完了していますが、今はまだGREゲートウェイのインスタンス間でのプライベート通信が確立しただけで、その裏のネットワークにはまだ到達できない状態です。裏のネットワーク(192.168.200.0/24とか192.168.201.0/24)に到達するには、各ネットワーク側で静的ルーティングを設定する必要があります。

### 5-1. 仮想NICセットの作成
静的ルート設定の前提として、仮想NICセットというものを作成しておく必要があります。これはルートの次ホップとして設定するために必要となるものです。

【作業】
**ネットワーク** → **IPネットワーク** → **仮想NICセット** にアクセスし **vNICセットの作成** ボタンを押します。
立ち上がったウィンドウで、各ゲートウェイ・インスタンスの仮想NICに名前をつけます。gw100、gw200両方に対して作成してください。

![WS000445.JPG](https://qiita-image-store.s3.amazonaws.com/0/117710/29bcf44f-3d97-bb51-bf14-91d35eb12271.jpeg)

### 5-2. 静的ルートの作成
Oracle Cloudでの静的ルーティングの設定は、**ルート** 機能で設定します。基本的には一般的なルーターなどのルートテーブルと同じような設定をしますが、Oracle Cloudの場合は次ホップとして仮想NICセットを設定するように作ります。

【作業】
**ネットワーク** → **IPネットワーク** → **ルート** にアクセスし **ルートの作成** ボタンを押します。
立ち上がったウィンドウで、相手方ネットワークへの静的ルートを設定します。
下記の例ではipex200のIPアドレス範囲(192.168.200.0/24, 192.168.200.1/24)を含むネットワークへの次ホップとして、先程作成したgw100_eth0という仮想NICセットを設定しています。

![WS000446.JPG](https://qiita-image-store.s3.amazonaws.com/0/117710/c2baca51-c9ec-046d-167f-a56013d19d1f.jpeg)

同じように、逆側のipex100に対する静的ルートも設定します。

## 6. コンピュート・インスタンスを作成してプライベートIP通信を確認

ここまで完了したら、作成したIPネットワーク(ipnet100、ipnet101、ipnet200、ipnet201)のに好きなインスタンス(図で言うインスタンスA~D)を立ち上げると、お互いに通信ができるようになっているはずです。
Oracle Cloudでのインスタンスの作成方法については、色々参考になるドキュメントがありますので、そちらを参考にして作成してみてください。

【参考資料】
[Oracle Compute Cloud Service：構成ガイド（仮想マシンの作り方） ](https://www.slideshare.net/oracle4engineer/oracle-compute-cloud-service-61181444)

下記は、192.168.101.0/24 (図のインスタンスBに相当) においたWindows 2012サーバーから、192.168.202.0/24 (図のインスタンスDに相当) に設置したActive Directoryで認証を行っているスクリーンショットです。うまくNATを越えてプライベートIPで通信できている様子がわかります。
![imlbonikghgdecie.png](https://qiita-image-store.s3.amazonaws.com/0/117710/c9bf3959-0a64-c67b-cae7-23d5caada572.png)



# まとめ
今回はOracle Linux 7.2のインスタンスをゲートウェイにして、OCI Classicの中でGREトンネルを構成しましたが、実ケースではOCI Classicの中と外との間で構成する場合が多いと思います。その場合はGREをサポートするルーター機器はたくさんあるので、外側のゲートウェイはハードウェアで構成することもあるでしょう。
また、OCI Classic側のゲートウェイについても、Cent OSやUbuntuなどの他Linuxディストリビューションでもほぼ同じ手順が使えると思いますし、Windows ServerでもGREをサポートしているようなので、ゲートウェイをWindows Serverにするのもいいと思います。ぜひ色々試してみて頂きたいと思います。