1. はじめに
OpenShiftでocコマンドを使って接続する際には、API Endpointにアクセスする必要がある。また、API Endpointにアクセスするためには、認証トークンが必要になる。一般的にはUsername/Passwordを指定して認証するが、ocコマンドを実行する度に認証をする必要がないのは実際には認証に伴ってOpenShiftによって発行される認証トークンを使っているからである。
oc login -u <username> -p <password> yyyy <API Endpoint> --loglevel=10
を実行してみると、まずAPI EndpointからOAuth認証用のEndpointを取得した後、そのEndpointを使って認証トークンを取得し、再度API Endpointにアクセスしていることがわかる。
Red Hat OpenShift on IBM Cloud(ROKS)におけるprivate only環境では
- API EndpointおよびOAuth認証用Endpointが共に、VPC内部からしかアクセスできない(166.8.0.0/14などのIBM Cloud管理のサービス用subnetから割り当てられる)。Direct Link経由でもインターネットからも直接はアクセスできない。
- API EndpointおよびOAuth認証用Endpointのポート番号が30000-32767のいずれかである(クラスターをデプロイするまで割り当てられる番号はわからない)。
という制約があり、企業ネットワークとIBM Cloud環境をDirect Linkで接続していても、敷居が高いことがある。VPN Clientを導入することができれば、IBM Cloud: private-only環境のROKS(Red Hat OpenShift on IBM Cloud)にClient-to-Server VPNを使ってアクセスする方法を使ってアクセスするのが最も楽だが、そもそも
- 端末にVPN Softwareを導入することがNG
- 端末がインターネットに繋がっていないのでVPNを実行できない
- 会社のルールとしてポート番号が443以外はアクセス許可していない
などの制約がある環境も多い。そこで、今回は以下のような構成をすることでポート443しかアクセスできない環境でもアクセスできる構成を試してみた。
- ROKS上にAPI EndpointにアクセスするためのRouteを作成する。これにより、API Endpointにポート443でアクセス可能となる。
- ROKS上にOAuth認証用のEndpointにアクセスするためのRouteを作成する。これにより、OAuth認証用のEndpointにもポート443でアクセス可能となる。
-
oc login -u <username> -p <password> yyyy <Routeで公開したAPI Endpoint>
だと、ocコマンドはオリジナルのOauth認証用Endpointにredirectされて認証を試みるため、上記で作成したRouteを通らない。先にOAuth認証用のEndpointから認証トークンを手動で取得しておき、その上でoc login --token xxxxx <Routeで公開したAPI Endpoint>
を実行することとする。 - 認証トークン取得方法については、こちらを参考にした。
2. 事前準備
以下は、VPC上のVSIなどで事前に構成しておく作業となる。
2-1: API Endpointのrouteを作成
$ ibmcloud oc cluster get --cluster privonly-syasuda-roksvpc
Retrieving cluster privonly-syasuda-roksvpc...
OK
Name: privonly-syasuda-roksvpc
ID: xxxxxxxxxxxxxxxxxxxx
State: normal
Status: All Workers Normal
Created: 2021-07-08 09:13:01 +0900 (2 months ago)
Resource Group ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Resource Group Name: Default
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-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud
Ingress Secret: privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-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:31811
Private Service Endpoint URL: https://c100.private.jp-tok.containers.cloud.ibm.com:31811
Pull Secrets: enabled in the default namespace
VPCs: xxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Master
Status: Ready (3 weeks ago)
State: deployed
Health: normal
Version: 4.7.23_1529_openshift
Location: Tokyo
URL: https://c100-e.private.jp-tok.containers.cloud.ibm.com:31811
ここで、一番最後にあるURL
の箇所のhttps://c100-e.private.jp-tok.containers.cloud.ibm.com:31811
がAPI Endpointである。
以下で、このAPI EndpointのIPアドレスを調べる。
$ host c100-e.private.jp-tok.containers.cloud.ibm.com
c100-e.private.jp-tok.containers.cloud.ibm.com is an alias for c100.private.jp-tok.containers.cloud.ibm.com.
c100.private.jp-tok.containers.cloud.ibm.com is an alias for prod-jp-tok-tugboat1.jp-tok.serviceendpoint.cloud.ibm.com.
prod-jp-tok-tugboat1.jp-tok.serviceendpoint.cloud.ibm.com has address 166.9.44.16
prod-jp-tok-tugboat1.jp-tok.serviceendpoint.cloud.ibm.com has address 166.9.40.22
prod-jp-tok-tugboat1.jp-tok.serviceendpoint.cloud.ibm.com has address 166.9.42.24
このIPアドレスとポート番号を元に、以下のようなYAMLファイルを作成する。
apiVersion: v1
kind: Service
metadata:
name: api-via-alb
spec:
ports:
- protocol: TCP
port: 8443
---
apiVersion: v1
kind: Endpoints
metadata:
name: api-via-alb
subsets:
- addresses:
- ip: 166.9.42.24
- ip: 166.9.40.22
- ip: 166.9.44.16
ports:
- port: 31811
このYAMLファイルを実行して、本来のAPI Endpointにアクセスするためのrouteを作成する。
$ oc create api-via-alb.yaml
$ oc create route passthrough api-via-alb --service api-via-alb
$ oc get svc,endpoints,route
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/api-via-alb ClusterIP 172.21.137.168 <none> 8443/TCP 17h
NAME ENDPOINTS AGE
endpoints/api-via-alb 166.9.42.24:31811,166.9.40.22:31811,166.9.44.16:31811 17h
NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD
route.route.openshift.io/api-via-alb api-via-alb-default.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud api-via-alb <all> passthrough None
2-2: OAuth認証用 Endpointのrouteを作成
OAuth認証用Endpointは、API Endpointから取得できる。
$ curl -sk https://c100-e.private.jp-tok.containers.cloud.ibm.com:31811/.well-known/oauth-authorization-server | jq -r .issuer
https://c100-e.private.jp-tok.containers.cloud.ibm.com:30701
以下のYAMLファイルを作成する(URL自体はAPI Endpointと同じであり、ポート番号だけが異なるはずである)。
apiVersion: v1
kind: Service
metadata:
name: oauth-via-alb
spec:
ports:
- protocol: TCP
port: 8443
---
apiVersion: v1
kind: Endpoints
metadata:
name: oauth-via-alb
subsets:
- addresses:
- ip: 166.9.42.24
- ip: 166.9.40.22
- ip: 166.9.44.16
ports:
- port: 30701
このYAMLファイルを実行して、本来のOAuth認証用のEndpointにアクセスするためのrouteを作成する。
$ oc create oauth-via-alb.yaml
$ oc create route passthrough oauth-via-alb --service oauth-via-alb
$ oc get svc,endpoints,route
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/api-via-alb ClusterIP 172.21.137.168 <none> 8443/TCP 17h
service/oauth-via-alb ClusterIP 172.21.239.220 <none> 8443/TCP 17h
NAME ENDPOINTS AGE
endpoints/api-via-alb 166.9.42.24:31811,166.9.40.22:31811,166.9.44.16:31811 17h
endpoints/oauth-via-alb 166.9.42.24:30701,166.9.40.22:30701,166.9.44.16:30701 17h
NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD
route.route.openshift.io/api-via-alb api-via-alb-default.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud api-via-alb <all> passthrough None
route.route.openshift.io/oauth-via-alb oauth-via-alb-default.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud oauth-via-alb <all> passthrough None
これで事前準備は完了
3. ocコマンドによるログイン
事前にIBM CloudのAPI Keyを取得しておく。
API EndpointおよびOAuth認証用Endpointは上記で作成したrouteのアドレスを入力する。
$ OPENSHIFT_APIKEY=apikey:<API_Key>
$ OPENSHIFT_API_ENDPOINT=https://api-via-alb-default.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud
$ OPENSHIFT_OAUTH_ENDPOINT=https://oauth-via-alb-default.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud
$ OPENSHIFT_TOKEN=$(curl -skI -u ${OPENSHIFT_APIKEY} -H "X-CSRF-Token: 1" "${OPENSHIFT_OAUTH_ENDPOINT}/oauth/authorize?client_id=openshift-challenging-client&response_type=token" | grep Location | sed -e "s/.*access_token=//"|sed -e "s/\&.*//")
初回ログインの時だけ以下のような警告が出るので受け入れる。
$ oc login --token=${OPENSHIFT_TOKEN} ${OPENSHIFT_API_ENDPOINT}
The server is using a certificate that does not match its hostname: x509: certificate is valid for kubernetes, kubernetes.default, kubernetes.default.svc, kubernetes.default.svc.cluster.local, kube-apiserver, kube-apiserver.master-xxxxxxxxxxxxxxxxxxxx.svc, kube-apiserver.master-xxxxxxxxxxxxxxxxxxxx.svc.cluster.local, openshift, openshift.default, openshift.default.svc, openshift.default.svc.cluster.local, c100.private.jp-tok.containers.cloud.ibm.com, c100.private.jp-tok.containers.cloud.ibm.com, c100-e.jp-tok.containers.cloud.ibm.com, c100-e.private.jp-tok.containers.cloud.ibm.com, c3j463dt0o165mnm7be0.vpe.private.jp-tok.containers.cloud.ibm.com, localhost, not api-via-alb-default.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud
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
Logged into "https://api-via-alb-default.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud:443" as "IAM#shiyasu@jp.ibm.com" using the token provided.
You have access to 68 projects, the list has been suppressed. You can list all projects with ' projects'
Using project "default".
Welcome! See 'oc help' to get started.
どうしてもこの警告が出るのが嫌だったら、、、、以下のいずれかを行なってc100-e.private.jp-tok.containers.cloud.ibm.com
にアクセスするというのも1つの方法。
- オリジナルのAPI EndpointのURL(今回だと
c100-e.private.jp-tok.containers.cloud.ibm.com
)のCNAMEをapi-via-alb-default.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud
に端末が利用するDNSで構成しておく -
/etc/hosts
にc100-e.private.jp-tok.containers.cloud.ibm.com
のIPアドレスとしてapi-via-alb-default.privonly-syasuda-roksvpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-i000.jp-tok.containers.appdomain.cloud
のIPアドレスを書いておく