Red Hat OpenShift on IBM Cloud でアプリへのアクセス元 IPアドレス を取得する

# 概要

Red Hat OpenShift on IBM Cloud サービスで稼働するアプリケーションにおいて、クライアントのアクセス元の IP アドレスを取得することはデフォルトの構成では不可能でした。先日リリースされた OpenShift 4.13 のクラスターでは PROXY プロトコルを利用することでIPアドレスの取得が可能になったので、実際に稼働させて確認します。
なお、この方法が利用できるのは、Red Hat OpenShift on IBM Cloud サービスの OpenShift クラスターのうちOpenShift バーション 4.13 以降かつ IBM Cloud VPC 上で稼働するクラスターのみです。



# デフォルトの構成

OpenShift クラスター上に HTTP リクエストのヘッダーを表示する[アプリケーション]()をデプロイしました。このアプリにアクセスしてみると以下のような結果を得ます。注目してほしいのは最後の `x-forwarded-for` の値で `10.248.0.10` となっています。この IP アドレスはOpenShiftのクラスターを構成する VPC の内部で使っているプライベートのIPアドレスで残念ながらアクセス元のグローバル IP アドレスとは異なるものです。


<details><summary>デフォルトの構成でのアクセス結果(PROXYプロトコルを使わない)</summary>

```
Method
GET
Headers
sec-ch-ua
"Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"
sec-ch-ua-mobile
?0
sec-ch-ua-platform
"macOS"
upgrade-insecure-requests
1
user-agent
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
accept
text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
sec-fetch-site
same-site
sec-fetch-mode
navigate
sec-fetch-user
?1
sec-fetch-dest
document
referer
https://console-openshift-console.mycluster-jp-osa-1-319738-c82dcc5867b41450588f49284670f9a8-0000.jp-osa.containers.appdomain.cloud/
accept-encoding
gzip, deflate, br
accept-language
en-US,en;q=0.9,ja;q=0.8
cookie
_ga=GA1.2.536257552.1658995136
host
get-request-info-mfapp1.mycluster-jp-osa-1-319738-c82dcc5867b41450588f49284670f9a8-0000.jp-osa.containers.appdomain.cloud
x-forwarded-host
get-request-info-mfapp1.mycluster-jp-osa-1-319738-c82dcc5867b41450588f49284670f9a8-0000.jp-osa.containers.appdomain.cloud
x-forwarded-port
443
x-forwarded-proto
https
forwarded
for=10.248.0.10;host=get-request-info-mfapp1.mycluster-jp-osa-1-319738-c82dcc5867b41450588f49284670f9a8-0000.jp-osa.containers.appdomain.cloud;proto=https
x-forwarded-for
10.248.0.10
```

</details>


# PROXY プロトコルを利用するように設定を変更する

PROXY プロトコルを利用するためには OpenShift クラスターの Ingress Controller の設定を変更します。Ingress Controller は標準の状態では以下のセクション内にあるようなingress controller を持ちます。 `spec/endpointPublishingStrategy` の設定を変更することで PROXY プロトコルを有効化します。
変更後の Ingress Controller セクションでハイライトされている4行を追加して保存します。保存後構成の変更が行われおおよそ5分後には新しいアプリケーションにアクセスできるようになります。この変更は同じクラスターで稼働している他のアプリケーションへのアクセスにも影響します。一時的ではありますが OpenShift の Web コンソールを始めとするすべてのアプリケーションにアクセスできなくなりますので、ご注意ください。




<details><summary>デフォルト構成のIngress Controller</summary>

``` :
% oc edit ingresscontroller/default -n openshift-ingress-operator

# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: operator.openshift.io/v1
kind: IngressController
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"operator.openshift.io/v1","kind":"IngressController","metadata":{"annotations":{},"name":"default","namespace":"openshift-ingress-operator"},"spec":{"endpointPublishingStrategy":{"loadBalancer":{"scope":"External"},"type":"LoadBalancerService"},"nodePlacement":{"tolerations":[{"key":"dedicated","value":"edge"}]}},"status":{}}
    razee.io/build-url: https://travis.ibm.com/alchemy-containers/armada-ingress-secret-mgr/builds/1431086
    razee.io/source-url: https://github.ibm.com/alchemy-containers/armada-ingress-secret-mgr/commit/9fd150661bcfd75707090cfacbf3a064f4cd5512
  creationTimestamp: "2023-06-22T03:59:37Z"
  finalizers:
  - ingresscontroller.operator.openshift.io/finalizer-ingresscontroller
  generation: 3
  name: default
  namespace: openshift-ingress-operator
  resourceVersion: "19314"
  uid: 45979d7e-f6bf-40e3-a26c-d642b77fc74c
spec:
  clientTLS:
    clientCA:
      name: ""
    clientCertificatePolicy: ""
  defaultCertificate:
    name: mycluster-jp-osa-1-319738-c82dcc5867b41450588f49284670f9a8-0000
  endpointPublishingStrategy:
    loadBalancer:
      dnsManagementPolicy: Managed
      scope: External
    type: LoadBalancerService
  httpCompression: {}
  httpEmptyRequestsPolicy: Respond
  httpErrorCodePages:
    name: ""
  nodePlacement:
    tolerations:
    - key: dedicated
      value: edge
  tuningOptions:
    reloadInterval: 0s
  unsupportedConfigOverrides: null
<以下省略>

```


</details>




``` :PROXYプロトコルを有効化するための変更点
endpointPublishingStrategy:
  type: LoadBalancerService
  loadBalancer:
    scope: External
    providerParameters:
      type: IBM
      ibm:
        protocol: PROXY
```




<details><summary>変更後のIngress Controller</summary>

``` diff:
% oc edit ingresscontroller/default -n openshift-ingress-operator

# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: operator.openshift.io/v1
kind: IngressController
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"operator.openshift.io/v1","kind":"IngressController","metadata":{"annotations":{},"name":"default","namespace":"openshift-ingress-operator"},"spec":{"endpointPublishingStrategy":{"loadBalancer":{"scope":"External"},"type":"LoadBalancerService"},"nodePlacement":{"tolerations":[{"key":"dedicated","value":"edge"}]}},"status":{}}
    razee.io/build-url: https://travis.ibm.com/alchemy-containers/armada-ingress-secret-mgr/builds/1431086
    razee.io/source-url: https://github.ibm.com/alchemy-containers/armada-ingress-secret-mgr/commit/9fd150661bcfd75707090cfacbf3a064f4cd5512
  creationTimestamp: "2023-06-22T03:59:37Z"
  finalizers:
  - ingresscontroller.operator.openshift.io/finalizer-ingresscontroller
  generation: 4
  name: default
  namespace: openshift-ingress-operator
  resourceVersion: "78313"
  uid: 45979d7e-f6bf-40e3-a26c-d642b77fc74c
spec:
  clientTLS:
    clientCA:
      name: ""
    clientCertificatePolicy: ""
  defaultCertificate:
    name: mycluster-jp-osa-1-319738-c82dcc5867b41450588f49284670f9a8-0000
  endpointPublishingStrategy:
    loadBalancer:
      dnsManagementPolicy: Managed
+      providerParameters:
+        type: IBM
+        +        ibm:
+          protocol: PROXY
      scope: External
    type: LoadBalancerService
  httpCompression: {}
  httpEmptyRequestsPolicy: Respond
  httpErrorCodePages:
    name: ""
  nodePlacement:
    tolerations:
    - key: dedicated
      value: edge
  tuningOptions:
    reloadInterval: 0s
  unsupportedConfigOverrides: null
<以下省略>

```

</details>

# 変更後のアプリケーションにアクセスする

同じアプリにアクセスしてみると以下のセクションに示した結果を得ます。注目してほしいのは最後の `x-forwarded-for` の値で `116.***.102.171` となっています（値を一部マスクされていただきました）。この IP アドレスはアクセス元のグローバル IP アドレスで、アクセス元のIPアドレスがとれていそうですね。IP アドレスを使ったアクセス元の制御などは若干古典的なアプリケーションのアクセス制御になりつつありますが、このパラメータを使ってアプリ側でロジックを組み込むことができます。

<details><summary>構成変更後のアプリへのアクセス結果(PROXYプロトコルを使う)</summary>


```
Method
GET
Headers
cache-control
max-age=0
sec-ch-ua
"Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"
sec-ch-ua-mobile
?0
sec-ch-ua-platform
"macOS"
upgrade-insecure-requests
1
user-agent
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
accept
text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
sec-fetch-site
cross-site
sec-fetch-mode
navigate
sec-fetch-user
?1
sec-fetch-dest
document
referer
https://console-openshift-console.mycluster-jp-osa-1-319738-c82dcc5867b41450588f49284670f9a8-0000.jp-osa.containers.appdomain.cloud/
accept-encoding
gzip, deflate, br
accept-language
en-US,en;q=0.9,ja;q=0.8
cookie
_ga=GA1.2.536257552.1658995136
host
get-request-info-mfapp1.mycluster-jp-osa-1-319738-c82dcc5867b41450588f49284670f9a8-0000.jp-osa.containers.appdomain.cloud
x-forwarded-host
get-request-info-mfapp1.mycluster-jp-osa-1-319738-c82dcc5867b41450588f49284670f9a8-0000.jp-osa.containers.appdomain.cloud
x-forwarded-port
443
x-forwarded-proto
https
forwarded
for=116.***.102.171;host=get-request-info-mfapp1.mycluster-jp-osa-1-319738-c82dcc5867b41450588f49284670f9a8-0000.jp-osa.containers.appdomain.cloud;proto=https
x-forwarded-for
116.***.102.171
```

</details>



# まとめ

Red Hat OpenShift on IBM Cloud のデフォルト構成に少し変更を加えることで、アプリでアクセス元の IP アドレスを取得できるようになりました。従来はCloud Internet Serviceなどを利用しないとアクセス元のIPアドレスを取得できませんでしたが、追加費用なしでアクセス元の IP アドレスを取得できるようになりました。
この方法は実は兄弟サービスの IBM Cloud Kubernetes サービスでも同様に利用できるので、アクセス元の IP アドレスを取得されたい方はぜひ利用を検討ください。

# 参考資料


- [Know your real clients: Use PROXY protocol on Red Hat OpenShift on IBM Cloud](https://www.ibm.com/blog/know-your-real-clients-use-proxy-protocol-on-red-hat-openshift-on-ibm-cloud/)

- [Ingressの構成 - ソースIPアドレスの保持](https://cloud.ibm.com/docs/openshift?topic=openshift-ingress-configure#ingress-configure-source-ip)

- [Know Your Real Clients: Use PROXY Protocol on IBM Cloud Kubernetes Service](https://www.ibm.com/cloud/blog/know-your-real-clients-use-proxy-protocol-on-ibm-cloud-kubernetes-service)