IBMCloud: インターネットからアクセスする際のVNF構成(ターゲットごとにNLBを構成する方法）

# 1. はじめに

インターネットからのアクセス時にVNFを経由してパケットチェックの後に、ターゲットのサーバーにアクセスさせたいので、その構成を実装した。ただし、インターネットからのingress routeはIBM Cloud上ではまだ稼働していないため、別の実装で対応する必要がある。

# 2. アーキテクチャー図

ALBを途中経路に介在させることも考えたが、ALBには

- ALB自体のメンテナンスやシステム負荷に応じてIPアドレスが変更される（ALBにはFQDNを利用したアクセスが必要）
- [idle connection timeout](https://cloud.ibm.com/docs/loadbalancer-service?topic=loadbalancer-service-advanced-traffic-management-with-ibm-cloud-load-balancer&locale=en#connection-timeouts)が存在する。
- VNFに到達する前に、クライアントのIPがALBのIPに置き換えられてしまう。VNFから見たパケットのSource IPはALBのprivate IP(reserved IP)である。

などの仕様もあり、VNFの前段に配置した場合にあまり効果が得られないケースもあると思われる。そこで、今回は以下のような構成を考えた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/c977bf73-43a0-dd8d-7d12-aa075ee16d87.png)

- それぞれのターゲットサーバーにPort 80/443でサービスを公開したいので、それぞれのターゲットサーバーごとにNLBを用意する。
- NLBはSource IPを維持する。そのため、NLBにて80/443で受信したパケットをそのまま80/443でVNFに転送すると、Source IP/Destination IP(=VNFのIP)/Portのどれを使っても、どのターゲットサーバーに転送すれば良いかをVNFは判断できない。そのため、どのNLBから受け取ったパケットなのかを区別できるように、今回はNLBで構成するBackend poolのポートは以下のような命名規則に従うように構成した。
    - 10.4.0.**08**:*80* に転送するためのポート: *80***08**
    - 10.4.0.**09**:*80* に転送するためのポート: *80***09**
    - 10.4.0.**10**:*80* に転送するためのポート: *80***10**
    - 10.4.0.**08**:*443* に転送するためのポート: *443***08**
    - 10.4.0.**09**:*443* に転送するためのポート: *443***09**
    - 10.4.0.**10**:*443* に転送するためのポート: *443***10**
    

もちろん、ingress routeを使っていないため、以下のような問題もある。

- ターゲットサーバーごとにNLBが必要。
- ICMPに対応していない(NLBがICMPに対応しないので）。
- 全てのポートに汎用的に対応させるのはできない。今回の例ではポート80とポート443のみであり、そのポートごとに設定を行っている。
- ターゲットサーバーごとにNATするのではなく、ターゲットサーバー＆ポートごとにVNFでNATを実行する必要があるので、公開ポートが増えるとより多くのNAT設定が必要となる。
- ターゲットサーバーやサービス（ポート）が増えるたびに、それに応じてVNFにてインターネット側からのポートをあける必要があり（今回の例では8008-80010や、44308-44310）、Well knownポートではないとはいえあまり好ましくない



# 3. Webサーバーのセットアップとテスト

Webサーバーのセットアップ方法は省略。VPC内部の踏み台サーバーからのHTTP/HTTPSのテスト結果は以下の通り。

```txt:testweb1
[root@new-syasuda-tok1-vpc1 ~]# curl http://10.4.0.8
This is testweb1
[root@new-syasuda-tok1-vpc1 ~]# curl -k https://10.4.0.8
This is testweb1
[root@new-syasuda-tok1-vpc1 ~]# curl -vvv https://10.4.0.8 2>&1 | grep CN
* 	subject: CN=syasuda-testweb1,O=IBM,L=Default City,C=JP
* 	issuer: CN=syasuda-testweb1,O=IBM,L=Default City,C=JP

```
```txt:testweb2
[root@new-syasuda-tok1-vpc1 ~]# curl http://10.4.0.9
This is testweb2
[root@new-syasuda-tok1-vpc1 ~]# curl -k https://10.4.0.9
This is testweb2
[root@new-syasuda-tok1-vpc1 ~]# curl -vvv https://10.4.0.9 2>&1 | grep CN
* 	subject: CN=syasuda-testweb2,O=IBM,L=Default City,C=JP
* 	issuer: CN=syasuda-testweb2,O=IBM,L=Default City,C=JP
```
```txt:testweb3
[root@new-syasuda-tok1-vpc1 ~]# curl http://10.4.0.10
This is testweb3
[root@new-syasuda-tok1-vpc1 ~]# curl -k https://10.4.0.10
This is testweb3
[root@new-syasuda-tok1-vpc1 ~]# curl -vvv https://10.4.0.10 2>&1 | grep CN
* 	subject: CN=syasuda-testhttp3,O=IBM,L=Default City,C=JP
* 	issuer: CN=syasuda-testhttp3,O=IBM,L=Default City,C=JP
```


# 4. Security Groupの設定

登場人物として、NLB、VNF、Webサーバーの3つ存在するため、それぞれにSecurity Groupを構成する必要がある。

- NLB: port 80/443でCustomer Siteからからのアクセスを許可する必要がある。。
- VNF: port 8008-8010および44308-44310で**Customer Siteから**のアクセスを許可する必要がある。**(NLBはSource IPを変更せずにパケットを割り振るため）**
- Webサーバー: port 80/443でVNFからのアクセスを許可する必要がある。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/ab229292-4ef8-c0a8-5dd1-78196e552a88.png)


# 5. VNFにおけるiptables設定

```
[root@syasuda-testvnf1 ~]# echo 1 > /proc/sys/net/ipv4/ip_forward
[root@syasuda-testvnf1 ~]# iptables -t nat -A PREROUTING -p tcp --dport 8008 -j DNAT --to-destination 10.4.0.8:80
[root@syasuda-testvnf1 ~]# iptables -t nat -A PREROUTING -p tcp --dport 8009 -j DNAT --to-destination 10.4.0.9:80
[root@syasuda-testvnf1 ~]# iptables -t nat -A PREROUTING -p tcp --dport 8010 -j DNAT --to-destination 10.4.0.10:80
[root@syasuda-testvnf1 ~]# iptables -t nat -A PREROUTING -p tcp --dport 44308 -j DNAT --to-destination 10.4.0.8:443
[root@syasuda-testvnf1 ~]# iptables -t nat -A PREROUTING -p tcp --dport 44309 -j DNAT --to-destination 10.4.0.9:443
[root@syasuda-testvnf1 ~]# iptables -t nat -A PREROUTING -p tcp --dport 44310 -j DNAT --to-destination 10.4.0.10:443
[root@syasuda-testvnf1 ~]# iptables -t nat -A POSTROUTING -j MASQUERADE
```
```
[root@syasuda-testvnf1 ~]# iptables -t nat -L -n
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8008 to:10.4.0.8:80
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8009 to:10.4.0.9:80
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8010 to:10.4.0.10:80
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:44308 to:10.4.0.8:443
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:44309 to:10.4.0.9:443
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:44310 to:10.4.0.10:443

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0
```

同様に２台目のVNFにも設定する。


# 6. NLB設定

以下に、VSI1(10.4.0.8)のためのNLBの構成を記載する。
VSI2(10.4.0.9)やVSI3(10.4.0.10)のためには、それぞれに別のNLBを購入して同様に構成する。

## 6-1. NLB1: Listner
Port 80/443でNLBはListenする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/54140d6a-e763-bfaa-048e-39273f41eebe.png)

## 6-2. NLB1: Backend Pool for Port 80
ヘルスチェックはTCPで実施
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/5d66801f-331c-2ae7-c652-3d64cfaf283b.png)
Port 8008でVNFを登録する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/72878715-dea9-11e0-c0f1-f0838eef4a74.png)

## 6-3. NLB1: Backend Pool for Port 443
ヘルスチェックはTCPで実施
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/e8c1d23a-3362-8efc-3916-db5a28608498.png)
Port 44308でVNFを登録する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/a74e11d3-18b0-a1e4-c1a3-76332093fd80.png)


## 6-4. NLB2の構成（抜粋）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/de476b44-03cd-b095-02bd-9860151a0bdb.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/58902d91-8fc1-97fb-bdae-283e17b10c49.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/81b7ea36-9ca2-e061-8751-b388b5b1009e.png)

## 6-5. NLB3の構成（抜粋）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/19ebe707-bb55-bf2b-4a64-bb2df0b460de.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/2bc399f4-7a76-e667-fea1-df5d110415d4.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/3de00fe1-55b6-acab-8efa-8db9f01af27a.png)


# 7. クライアント（VPC外部）からのテスト

```txt:testweb1
syasuda@MacBook ~ % curl http://<NLB1のIP address>
This is testweb1
syasuda@MacBook ~ % curl -k https://<NLB1のIP address>
This is testweb1

```
```txt:testweb2
syasuda@MacBook ~ % curl http://<NLB2のIP address>
This is testweb2
syasuda@MacBook ~ % curl -k https://<NLB2のIP address>
This is testweb2
```
```txt:testweb3
syasuda@MacBook ~ % curl http://<NLB3のIP address>
This is testweb3
syasuda@MacBook ~ % curl -k https://<NLB3のIP address>
This is testweb3
```