IBM Cloud: ibmcloudコマンド（CLI）/ocコマンドによるプライベートエンドポイントアクセスについての注意点


#1. サポート状況
[release notes](https://github.com/IBM-Cloud/ibm-cloud-cli-release/releases/tag/v1.3.0)にもあるとおり、現在は`us_south`と`us_east`のみのサポートである。

また、各プラグインのサポート状況は以下から確認可能。

```
$ ibmcloud plugin list
Listing installed plug-ins...

Plugin Name                                 Version   Status   Private endpoints supported
cloud-databases                             0.10.2             false
cloud-dns-services                          0.3.4              false
cloud-functions/wsk/functions/fn            1.0.53             false
cloud-object-storage                        1.2.3              false
power-iaas                                  0.3.2              false
vpc-infrastructure/infrastructure-service   0.8.2              true
cloud-internet-services                     1.13.1             false
container-registry                          0.1.514            false
container-service/kubernetes-service        1.0.233            false
key-protect                                 0.6.0              false
```

実際、private endpointにアクセスした状態でibmcloud ksと実行すると以下のようなエラーが発生する。

```
$ ibmcloud config --check-version=false
$ ibmcloud login -a private.cloud.ibm.com --apikey @ibmcloud_apikey -r us-south
$ ibmcloud oc
FAILED
The plug-in 'container-service 1.0.233' does not support the private endpoint. Run 'ibmcloud api' to set a public API endpoint and try again.
```

しかし、us-southのprivate API endpointに対してREST APIで呼び出すことは可能のようだ。

- ACCESS_TOKENの取得方法は、[IBM CloudにおけるIAMトークンの取得方法](https://qiita.com/testnin2/items/3a4ca8a1a2b79b713c48)を参照。
- API endpoint情報: https://cloud.ibm.com/docs/openshift?topic=openshift-cs_api_install

```json
$ export ACCESS_TOKEN=`ibmcloud iam oauth-tokens | awk '{printf $4}'`
$ curl -s https://private.us-south.containers.cloud.ibm.com/global/v2/vpc/getClusters -H "Content-Type:application/json" -H "Authorization: Bearer $ACCESS_TOKEN" | jq '.[] | {id:.id, name:.name, region:.region, provider:.provider, masterURL:.masterURL}'
{
  "id": "c1m589st0l31fgh5364g",
  "name": "privonly-syasuda-roksvpc",
  "region": "jp-tok",
  "provider": "vpc-gen2",
  "masterURL": "https://c100-e.private.jp-tok.containers.cloud.ibm.com:30753"
}
{
  "id": "c1m5btct00o07vhsd7ug",
  "name": "pubpriv-syasuda-roksvpc",
  "region": "jp-tok",
  "provider": "vpc-gen2",
  "masterURL": "https://c100-e.jp-tok.containers.cloud.ibm.com:31322"
}
```


#2. `private.cloud.ibm.com`とは何か？

API Endpointと指定するからには、そういうURLがあるのかと思っていたが、以下のようにdigを実行しても名前解決できるわけではない。それなのに実際に`ifdown eth1`などを実行してIBM CloudのVSIからInternetアクセスを禁じて通信してみたら、実際に確かにアクセスはできている。なんでだろうと思って、ibmcloudコマンド実行時に`IBMCLOUD_TRACE=true`という環境変数をつけてデバッグをしてみたら、実際には`private.cloud.ibm.com`なんかにはアクセスしていない。どうも、これはアクセス先のURLではなく、単にCLIにprivate accessであることを知らせるパラメーター文字列に過ぎないように見える。

```
[root@syasudacentos7 ~]# dig +short private.cloud.ibm.com
（何も返ってこない）
```

```shell:CLIの最新バージョンをチェックしに行くケース
$ ibmcloud config --check-version=true
$ IBMCLOUD_TRACE=true ibmcloud login -a private.cloud.ibm.com --apikey @ibmcloud_apikey -r us-south 2>&1 | grep -i "Host:"
Host: private.us-south.globalcatalog.cloud.ibm.com
Host: private.us-south.globalcatalog.cloud.ibm.com
Host: private.us-south.globalcatalog.cloud.ibm.com
Host: private.us-south.globalcatalog.cloud.ibm.com
Host: private.us-south.globalcatalog.cloud.ibm.com
Host: private.us-south.globalcatalog.cloud.ibm.com
Host: private.us-south.iam.cloud.ibm.com
Host: private.us-south.accounts.cloud.ibm.com
Host: private.us-south.clis.cloud.ibm.com
Host: cloud.ibm.com
```

```shell:CLIの最新バージョンをチェックしに行かないように無効にしたケース
$ ibmcloud config --check-version=false
$ IBMCLOUD_TRACE=true ibmcloud login -a private.cloud.ibm.com --apikey @ibmcloud_apikey -r us-south 2>&1 | grep -i "Host:"
Host: private.us-south.globalcatalog.cloud.ibm.com
Host: private.us-south.globalcatalog.cloud.ibm.com
Host: private.us-south.globalcatalog.cloud.ibm.com
Host: private.us-south.globalcatalog.cloud.ibm.com
Host: private.us-south.globalcatalog.cloud.ibm.com
Host: private.us-south.globalcatalog.cloud.ibm.com
Host: private.us-south.iam.cloud.ibm.com
Host: private.us-south.accounts.cloud.ibm.com

```

#3. API Endpoint(Private)利用時のアクセス元について


以下のようにCLIでアクセスするprivate endpoint URLのIPアドレスは、166.9.xx.xxというCloud Service Endpointである。そのため、Direct Link経由で直接アクセスできない。よって、

- IBM CloudのVSIからアクセスする
- IBM Cloud上のサーバーをproxy/socksとして利用する。例えば[SSHを使ってSOCKS経由でWebにアクセスする方法](https://qiita.com/testnin2/items/64c570859b297dfac8b1)も１つの方法。
- VPCのVPNaaSを利用する

などを考慮する必要がある。

```
$ dig +short private.us-south.globalcatalog.cloud.ibm.com
gc.us-south.proxy.serviceendpoint.cloud.ibm.com.
166.9.250.231
166.9.250.199
166.9.251.7
$ dig +short private.us-south.iam.cloud.ibm.com
166.9.250.226
$ dig +short private.us-south.accounts.cloud.ibm.com
bss.us-south.proxy.serviceendpoint.cloud.ibm.com.
166.9.251.4
166.9.250.196
166.9.250.228
$ dig +short private.us-south.clis.cloud.ibm.com
cli-repo-192936.us-south.serviceendpoint.cloud.ibm.com.
166.9.58.105
166.9.48.172
```

#4. ROKS(Red Hat OpenShift on IBM Cloud)にインターネットに出れない環境からアクセス可能か？

ROKSには[ここ](https://qiita.com/testnin2/items/78ce4a04728f59da9a02)で紹介した通り、API keyさえあればROKSのMgmt Clusterにprivate endpoint経由でID/Passwordなしでログインは可能である。ただし、初回に`ibmcloud oc cluster config`でprivate endpointに対する構成情報を取得しておく必要があるため、この情報取得時だけはIBM CloudのPublic Endpointにアクセスできる場所から実行して事前にコピーしておく必要がある。

##4-1. ibmcloudコマンドでpublic endpointにアクセスする。

上記で説明した通り、`ibmcloud oc`コマンドはprivate endpointからは実施できないので、public endpointを利用する。
[IBM Cloud: ibmcloudにAPI Keyでログインする方法](https://qiita.com/testnin2/items/3ff57e6c92eacd664ff3)を参照。

```shell:
$ ibmcloud login -a cloud.ibm.com --apikey @ibmcloud_apikey -r jp-tok
```

##4-2 該当クラスターのprivate endpoint用のconfigを取得する。

参考docs: https://cloud.ibm.com/docs/openshift?topic=openshift-access_cluster#access_api_key

```shell:クラスター情報の確認
$ ibmcloud oc cluster ls
OK
Name                               ID                     State      Created        Workers   Location                  Version                 Resource Group Name   Provider
privonly-syasuda-roksvpc           c1m589st0l31fgh5364g   normal     17 hours ago   2         Tokyo                     4.6.22_1538_openshift   Common                vpc-gen2
pubpriv-syasuda-roksvpc            c1m5btct00o07vhsd7ug   normal     17 hours ago   2         Tokyo                     4.6.22_1538_openshift   Common                vpc-gen2

$ ibmcloud oc cluster get --cluster privonly-syasuda-roksvpc
Retrieving cluster privonly-syasuda-roksvpc...
OK

Name:                           privonly-syasuda-roksvpc
ID:                             c1m589st0l31fgh5364g
State:                          normal
Status:                         All Workers Normal
Created:                        2021-04-06 21:29:27 +0900 (18 hours ago)
Resource Group ID:              89e3e245955e4c59a83bc9d0db590082
Resource Group Name:            Common
Pod Subnet:                     172.17.0.0/18
Service Subnet:                 172.21.0.0/16
Workers:                        2
Worker Zones:                   jp-tok-1, jp-tok-2
Ingress Subdomain:              privonly-syasuda-roksvpc-c82dcc5867b41450588f49284670f9a8-i000.jp-tok.containers.appdomain.cloud
Ingress Secret:                 privonly-syasuda-roksvpc-c82dcc5867b41450588f49284670f9a8-i000
Ingress Status:                 healthy
Ingress Message:                All Ingress components are healthy
Public Service Endpoint URL:    https://c100-e.private.jp-tok.containers.cloud.ibm.com:30753
Private Service Endpoint URL:   https://c100.private.jp-tok.containers.cloud.ibm.com:30753
Pull Secrets:                   enabled in the default namespace
VPCs:                           r022-85621b2c-a349-4ae6-87e3-767ddeac7298

Master
Status:     Ready (17 hours ago)
State:      deployed
Health:     normal
Version:    4.6.22_1538_openshift
Location:   Tokyo
URL:        https://c100-e.private.jp-tok.containers.cloud.ibm.com:30753
```

```shell:config(PrivateEndpoint)の取得
$ ibmcloud oc cluster config -c privonly-syasuda-roksvpc --endpoint private
OK
The configuration for privonly-syasuda-roksvpc was downloaded successfully.

Added context for privonly-syasuda-roksvpc to the current kubeconfig file.
You can now execute 'kubectl' commands against your cluster. For example, run 'kubectl get nodes'.
If you are accessing the cluster for the first time, 'kubectl' commands might fail for a few seconds while RBAC synchronizes.

$ cat .kube/config |grep https
    server: https://c100.private.jp-tok.containers.cloud.ibm.com:30753
    server: https://c100.private.jp-tok.containers.cloud.ibm.com:30753
```

##4-3 （オプション）プライベートエンドポイントアクセスが必要な端末に移動する。

ホームディレクトリ配下にある`.kube`を該当の端末にコピー。
この端末は、`c100.private.jp-tok.containers.cloud.ibm.com`にアクセスできる必要がある。

##4-4 ログイン

[IBM Cloud: ibmcloudにAPI Keyでログインする方法](https://qiita.com/testnin2/items/3ff57e6c92eacd664ff3)で取得したAPI Keyを環境変数にセットして、`oc login`で指定する。

```
$ export APIKEY=<IBM CloudのAPI Key>
$ oc login -u apikey -p $APIKEY
The server uses a certificate signed by an unknown authority.
You can bypass the certificate check, but any data you send to the server could be intercepted by others.
Use insecure connections? (y/n): y

Login successful.

You have access to 63 projects, the list has been suppressed. You can list all projects with ' projects'

Using project "default".
```


# 参考

- [IBM Cloud: ibmcloudにAPI Keyでログインする方法](https://qiita.com/testnin2/items/3ff57e6c92eacd664ff3)
- [IBM Cloud CLI を使ってプライベートエンドポイント経由でログインする](https://qiita.com/khayama/items/b574a97a85cc7858bce2)