IBM Cloud:  Red Hat OpenShift on IBM Cloud(ROKS)のPrivate only環境からのインターネットアクセスをProxy経由にしてみる

#1. はじめに
Red Hat OpenShift on IBM Cloud(ROKS)はVPC上でPrivate Only環境を構築することができる。もっと言えば、このROKS上のWorker nodeが配置されるSubnetは、Public Gatewayと紐づける必要もない。これにより、VPC内部からインターネットにさえアクセスできない閉域なOpenShift環境を構築することが可能である。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/61fc633c-b40b-3a65-d487-f690fc3aee5a.png)


しかし、、、

実際は、インターネットアクセスできないとDocker Imageが取得できない、Githubにアクセスできないといった制約も生じる。もちろん、**「いやいや、せっかく閉域環境で構築しているんだから、そりゃあ仕方がないでしょ。そもそもそういうレポジトリとかは全部プライベート環境に作るものだよ」**というのはごもっともであり、私もそのように構成するべきだと思う。でも、たとえばちゃんとオンプレミスにあるProxy経由でアクセス制御を行いつつ、「統制の取れた」インターネットアクセスをしたいという要望もあるだろう（Public GatewayではIPアドレス指定はできるがドメイン指定はできない）。

そこで、今回は、Proxyサーバーをsquidで構築し、ROKSインターネットアクセスをする際には必ずProxy経由になるように構成できないかを試してみた。以下の手順は、公式ドキュメントに載っている訳ではないが、とりあえず色々Proxyでログを取りつつ試行錯誤して確認したところうまく動いているように見えるので、あくまで参考情報としてもらいたい（ホストの設定を直接編集している時点で、サポートされる構成と言えるのかはちょっと微妙）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/b2aa63e5-01dd-f817-4403-4de0c71c1f93.png)



検証は、ROKS 4.7.29_1531で行った。
また、この手順例ではProxyとして`10.0.0.4:3128`のサーバーを利用している。

#2. cluster-wide proxyの構成。

https://access.redhat.com/documentation/ja-jp/openshift_container_platform/4.7/html/networking/nw-proxy-configure-object_config-cluster-wide-proxy

はじめ、このcluster-wideのproxy構成をすれば、全ての通信がproxy経由になると思っていたのだが、そうではなかった。

- ICOSへのアクセス
- （Build中に）ソースファイルをGitHubから取得
- （Build中に）DockerFileに指定されているベースイメージを取得
- Operator Hubへの通信

などのようなOCPプロセス内からの呼び出しに利用されているように見える。一方で、Builder Imageの取得や外部のDocker Imageそのものを取得する際には、後述のCRI-Oの構成が必要のように見える。

##2-1. 設定と確認

私の環境に設定したアドレスは以下になるが、VPC内部からROKSにアクセスするのであれば、VPC内部のIPアドレスもProxyを経由しないように`NoProxy`に入れておくと良いかもしれない。

```shell:設定
$ oc edit proxy/cluster
（省略）
spec:
  httpProxy: http://10.0.0.4:3128
  httpsProxy: http://10.0.0.4:3128
  noProxy: localhost,.svc,.cluster.local,.cloud-object-storage.appdomain.cloud,.containers.appdomain.cloud,icr.io,.icr.io,registry.au-syd.bluemix.net,registry.eu-de.bluemix.net,registry.eu-gb.bluemix.net,registry.ng.bluemix.net
  trustedCA:
    name: ""
（省略）
```

`noProxy`には、自動的に`c100-e.private.jp-tok.containers.cloud.ibm.com`などが追加されていた。

```shell:確認
$ oc get proxy/cluster -o json | jq -r '.spec,.status'
{
  "httpProxy": "http://10.0.0.4:3128",
  "httpsProxy": "http://10.0.0.4:3128",
  "noProxy": "localhost,.svc,.cluster.local,.cloud-object-storage.appdomain.cloud,.containers.appdomain.cloud,icr.io,.icr.io,registry.au-syd.bluemix.net,registry.eu-de.bluemix.net,registry.eu-gb.bluemix.net,registry.ng.bluemix.net",
  "trustedCA": {
    "name": ""
  }
}
{
  "httpProxy": "http://10.0.0.4:3128",
  "httpsProxy": "http://10.0.0.4:3128",
  "noProxy": ".cloud-object-storage.appdomain.cloud,.cluster.local,.containers.appdomain.cloud,.icr.io,.svc,10.0.0.0/16,127.0.0.1,172.17.0.0/18,172.21.0.0/16,c100-e.private.jp-tok.containers.cloud.ibm.com,icr.io,localhost,registry.au-syd.bluemix.net,registry.eu-de.bluemix.net,registry.eu-gb.bluemix.net,registry.ng.bluemix.net"
}
```

##2-2. NoProxyで上記を指定した理由

NoProxyに何も設定しない場合は、Proxyサーバー上では以下のようなログが確認できた。


```txt:ICOSへのアクセス。後からNoProxyに入れた。
1631605621.901  90054 10.0.0.24 TCP_TUNNEL/200 4926 CONNECT s3.direct.ap.cloud-object-storage.appdomain.cloud:443 - HIER_DIRECT/161.26.85.12 -
```

ICOSのendpoint一覧はこちら。https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-endpoints

```txt:VPCLoadBalanerへのアクセス。後からNoProxyに入れた。
1631606804.225     17 10.0.0.24 TCP_TUNNEL/200 6129 CONNECT console-openshift-console.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud:443 - HIER_DIRECT/10.1.0.5 -
```

```txt:VPCLoadBalanerへのアクセス。後からNoProxyに入れた。
1631605630.946  30323 10.0.0.24 TCP_TUNNEL/200 6018 CONNECT canary-openshift-ingress-canary.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud:443 - HIER_DIRECT/10.1.0.5 -
```

```txt:インターネットアクセス
1631605620.556    636 10.0.0.24 TCP_TUNNEL/200 4402 CONNECT infogw.api.openshift.com:443 - HIER_DIRECT/34.225.158.211 -
```

1つ目のものはICOSへのアクセスでありVPC内部からのアクセスである必要があるため、必ず`noProxy`で除外設定をするべきである。2つ目と3つ目も、VPC Load BalancerへのアクセスなのでProxyを経由させる必要はないので、こちらも`noProxy`で除外されるように構成した。
また、[IBM Cloud: Red Hat OpenShift on IBM Cloud(ROKS)でicr.ioにpublic gatewayなしでアクセスできる理由](https://qiita.com/testnin2/items/0c85a9a83f283590b828)でも記載したとおり、`icr.io`や`registry.au-syd.bluemix.net`は、一見インターネットへのアクセスのように見えるが実際は内部NWにアクセス
するように構成されているので、その恩恵を受けるために除外した。。`image-registry.openshift-image-registry.svc`や`image-registry.openshift-image-registry.svc.cluster.local`なども明示的に内部NWにアクセス
するように構成されているので、こちらも`noProxy`で除外した（一応、`.svc`や`.cluster.local`は自動的に挿入されるようだが、明示的に入れた。）

なお、`infogw.api.openshift.com`はTelemetryのための情報収集用のインターネットアクセスのようだ。
https://docs.openshift.com/container-platform/4.7/installing/install_config/configuring-firewall.html


## 2-3. テスト(/host/etc/sysconfig/crio-network設定前）

```
$ oc new-app --as-deployment-config --name test1 https://github.com/nin2yasu/DO288-apps#container-build --context-dir container-build
```

```txt:Proxyサーバーのログ
1631610425.550    518 10.1.0.16 TCP_TUNNEL/200 5128 CONNECT github.com:443 - HIER_DIRECT/13.250.177.223 -
1631610426.902   1329 10.1.0.16 TCP_TUNNEL/200 1088883 CONNECT github.com:443 - HIER_DIRECT/13.250.177.223 -
1631610430.285    637 10.1.0.16 TCP_TUNNEL/200 3854 CONNECT quay.io:443 - HIER_DIRECT/50.16.140.223 -
1631610430.962    673 10.1.0.16 TCP_TUNNEL/200 5086 CONNECT quay.io:443 - HIER_DIRECT/50.16.140.223 -
1631610431.654    690 10.1.0.16 TCP_TUNNEL/200 14511 CONNECT quay.io:443 - HIER_DIRECT/50.16.140.223 -
1631610432.298    637 10.1.0.16 TCP_TUNNEL/200 5695 CONNECT quay.io:443 - HIER_DIRECT/50.16.140.223 -
1631610432.307    647 10.1.0.16 TCP_TUNNEL/200 5667 CONNECT quay.io:443 - HIER_DIRECT/50.16.140.223 -
1631610432.309    649 10.1.0.16 TCP_TUNNEL/200 5638 CONNECT quay.io:443 - HIER_DIRECT/50.16.140.223 -
1631610432.314    654 10.1.0.16 TCP_TUNNEL/200 5695 CONNECT quay.io:443 - HIER_DIRECT/50.16.140.223 -
1631610432.318    657 10.1.0.16 TCP_TUNNEL/200 5667 CONNECT quay.io:443 - HIER_DIRECT/50.16.140.223 -
1631610432.322    662 10.1.0.16 TCP_TUNNEL/200 5695 CONNECT quay.io:443 - HIER_DIRECT/50.16.140.223 -
1631610432.324     12 10.1.0.16 TCP_TUNNEL/200 6547 CONNECT cdn02.quay.io:443 - HIER_DIRECT/13.249.162.2 -
1631610432.325     15 10.1.0.16 TCP_TUNNEL/200 6547 CONNECT cdn02.quay.io:443 - HIER_DIRECT/13.249.162.2 -
1631610432.335     12 10.1.0.16 TCP_TUNNEL/200 6547 CONNECT cdn02.quay.io:443 - HIER_DIRECT/13.249.162.2 -
1631610432.343     17 10.1.0.16 TCP_TUNNEL/200 8043 CONNECT cdn02.quay.io:443 - HIER_DIRECT/13.249.162.2 -
1631610432.794    476 10.1.0.16 TCP_TUNNEL/200 6054459 CONNECT cdn02.quay.io:443 - HIER_DIRECT/13.249.162.2 -
1631610433.011    615 10.1.0.16 TCP_TUNNEL/200 5695 CONNECT quay.io:443 - HIER_DIRECT/50.16.140.223 -
1631610433.029     14 10.1.0.16 TCP_TUNNEL/200 6664 CONNECT cdn02.quay.io:443 - HIER_DIRECT/13.249.162.2 -
1631610436.397   4096 10.1.0.16 TCP_TUNNEL/200 71058269 CONNECT cdn02.quay.io:443 - HIER_DIRECT/13.249.162.2 -
```


#3. Worker Nodeにおける`/host/etc/sysconfig/crio-network`の構成

OpenShiftにおいてDockerImageを外界から取得しているのは、コンテナエンジンであるCRI-Oであるため、CRI-OがProxyを利用するように構成する必要"も"ある。
ちなみに、**Worker NodeのUpdateやReplaceを行うとこの設定は消えてしまうので、再度設定が必要になることにも注意（逆に言ったら設定を間違えたらUpdateやReplaceをすれば良い）**。理想的にはスクリプトを作り上げるとか、DaemonSetを作るとかをした方が良いかもしれない。**もっと良い設定方法などがあったら教えてください。**

##3-1. 設定と確認

```
# oc get nodes
NAME        STATUS   ROLES           AGE     VERSION
10.0.0.25   Ready    master,worker   4h41m   v1.20.0+9689d22
10.1.0.17   Ready    master,worker   4h40m   v1.20.0+9689d22
```

```shell:設定（以下の例は10.0.0.25ノードでの設定だが、全てのノードで繰り返し行う）
$ oc debug node/10.0.0.25
Creating debug namespace/openshift-debug-node-z6mx2 ...
Starting pod/100025-debug ...
To use host binaries, run `chroot /host`
Pod IP: 10.0.0.25
If you don't see a command prompt, try pressing enter

sh-4.4# echo HTTP_PROXY="http://10.0.0.4:3128/" >> /host/etc/sysconfig/crio-network;
sh-4.4# echo HTTPS_PROXY="http://10.0.0.4:3128/" >> /host/etc/sysconfig/crio-network;
sh-4.4# echo NO_PROXY="localhost,.svc,.cluster.local,127.0.0.1,172.16.0.0/16,172.17.0.0/18,172.18.0.0/16,172.19.0.0/16,172.20.0.0/16,172.21.0.0/16,172.30.0.0/16,161.26.0.0/16,166.8.0.0/14,icr.io,.icr.io,registry.au-syd.bluemix.net,registry.eu-de.bluemix.net,registry.eu-gb.bluemix.net,registry.ng.bluemix.net"  >> /host/etc/sysconfig/crio-network;
```

```shell:確認
sh-4.4# cat /host/etc/sysconfig/crio-network
# /etc/sysconfig/crio-network
CRIO_NETWORK_OPTIONS=
HTTP_PROXY=http://10.0.0.4:3128/
HTTPS_PROXY=http://10.0.0.4:3128/
NO_PROXY=localhost,.svc,.cluster.local,127.0.0.1,172.16.0.0/16,172.17.0.0/18,172.18.0.0/16,172.19.0.0/16,172.20.0.0/16,172.21.0.0/16,172.30.0.0/16,161.26.0.0/16,166.8.0.0/14,icr.io,.icr.io,registry.au-syd.bluemix.net,registry.eu-de.bluemix.net,registry.eu-gb.bluemix.net,registry.ng.bluemix.net
```

問題なければ、この構成を反映させるためにWorker nodeを再起動する。

##3-2. NoProxyで上記を指定した理由

CRI-OはどうやらKubernetes Networkである172.x.x.xなどと通信しており、NO_Proxyに何も入れないで全部Proxy経由にすると、（当然ProxyサーバーがKubernetes Networkを認識しているわけはないので）403エラーが多発してたちまち挙動がおかしくなった。
Proxyを通すべきではない、ROKSとして予約しているアドレスは例えば、https://cloud.ibm.com/docs/openshift?topic=openshift-plan_clusters&interface=ui などが参考になる。

```
1631611678.135      0 10.0.0.24 TCP_DENIED/403 3894 CONNECT 172.20.0.1:2040 - HIER_NONE/- text/html
1631611678.140      0 10.0.0.24 TCP_DENIED/403 3894 CONNECT 172.20.0.1:2040 - HIER_NONE/- text/html
1631611678.144      0 10.0.0.24 TCP_DENIED/403 3894 CONNECT 172.20.0.1:2040 - HIER_NONE/- text/html
1631611678.147      0 10.0.0.24 TCP_DENIED/403 3894 CONNECT 172.20.0.1:2040 - HIER_NONE/- text/html
1631611678.148      0 10.0.0.24 TCP_DENIED/403 3894 CONNECT 172.20.0.1:2040 - HIER_NONE/- text/html
1631611678.254      0 10.1.0.16 TCP_DENIED/403 3894 CONNECT 172.20.0.1:2040 - HIER_NONE/- text/html
1631611678.258      0 10.1.0.16 TCP_DENIED/403 3894 CONNECT 172.20.0.1:2040 - HIER_NONE/- text/html
1631611678.260      0 10.1.0.16 TCP_DENIED/403 3894 CONNECT 172.20.0.1:2040 - HIER_NONE/- text/html
```

また、NoProxyをあまり構成していなかった時は以下のようなアクセスログをProxyサーバーで確認できたが、この中には*.svcのような内部レジストリへのアクセスまで含まれており、当然Proxy経由では通信できないものなので、最終的にはNoProxyにて除外構成をした。
先述の通り、`icr.io`や`registry.au-syd.bluemix.net`は一見インターネットへのアクセスのように見えるが実際には内部NWにアクセスするように構成されていることに注意。

```txt:内部レジストリへのアクセス。後からNoProxyに入れた。
1631622802.457      0 10.0.0.25 TCP_DENIED/403 3993 CONNECT image-registry.openshift-image-registry.svc:5000 - HIER_NONE/- text/html
```
```txt:インターネットアクセスのように見せかけて実は内部NWへのアクセス（一応インターネット経由でも接続はできる）。後からNoProxyに入れた。
1631622650.584    609 10.0.0.25 TCP_TUNNEL/200 4565 CONNECT registry.au-syd.bluemix.net:443 - HIER_DIRECT/135.90.66.54 -
```
```txt:インターネットアクセスのように見せかけて実は内部NWへのアクセス（一応インターネット経由でも接続はできる）。後からNoProxyに入れた。
1631622803.430    574 10.0.0.25 TCP_TUNNEL/200 4629 CONNECT icr.io:443 - HIER_DIRECT/169.62.37.246 -
```
```txt:インターネットアクセス
1631622699.386    659 10.0.0.25 TCP_TUNNEL/200 3854 CONNECT quay.io:443 - HIER_DIRECT/3.213.173.170 -
```
```txt:インターネットアクセス
1631622804.322    144 10.1.0.17 TCP_TUNNEL/200 5391 CONNECT registry.redhat.io:443 - HIER_DIRECT/23.2.36.201 -
```

#4. 問題判別

- 必ずProxyサーバーのログとセットで構成を確認しましょう。
- Proxyサーバーのログに表示される宛先ドメインに対して、`ホスト内部から`名前解決をしてみましょう。[ここ](https://qiita.com/testnin2/items/0c85a9a83f283590b828)でも紹介した通り、Global IPアドレスだと思っていたものが、思わぬところでVPC内部からのアクセスが必須になることもあるかもしれません。その場合は、NoProxyに入れて構成する必要があります。