1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

IBM Kubernetes Service (IKS) でIPアドレス制限を実装する

Last updated at Posted at 2023-05-12

はじめに

IBM Kubernetes Service(以降IKSとする)でデプロイしているアプリにIPアドレス制限(アプリに対し特定のIPアドレスを持つユーザーのみからのアクセスを許可する)の要望があり検証を行ったため、手順等をQiitaにまとめてみました。
参考程度に読んでいただければと思います。

IKS検証環境

バージョン1.24.10
クラシック・クラスター(VPCクラスターの場合少し手順が異なるかと思いますのでご注意ください)

前提

  • IBM CloudにてIKSクラスターが作成されていること
  • IKSクラスター内にIPアドレス制限を実装したいアプリがデプロイされていること(参考:CLI でアプリをデプロイする方法)。
    image.png

概要

IKSでデプロイしたアプリに対してIPアドレス制限を実装する手段はいくつかあると思いますが、今回自分が試したのは以下の2つです。

  1. ServiceでのIPアドレス制限
  2. IngressでのIPアドレス制限
    image.png

まず前提として、アプリはロードバランサーで設定を行うことでIP制限を実装することができます。
IKSではロード・バランサーをServiceかIngressで実装することが可能です。
Serviceでロード・バランサーを実装する場合はネットワーク・ロード・バランサー(NLB)、Ingressでロード・バランサーを実装する場合はアプリケーション・ロード・バランサー(ALB)になります。
よって、IKSでIPアドレス制限を実装する手段は2つあることになります。
参考: アプリの公開サービスの選択

どちらの手段を取るかについては、ほぼイコールでどちらでロード・バランサーを実装するかという判断になります。
ルーティングルールをカスタマイズしないのであれば「1.ServiceでのIPアドレス制限」を選択可能ですが、Ingressを使用してルーティングルールを実装する(アプリをhttps化したい・エラー画面を表示させたいなどの場合)は「2.IngressでのIPアドレス制限」での実装になります。
どちらを取るか迷われた場合は基本的に「2.IngressでのIPアドレス制限」で実装する方針で問題ないかと思います。

ご自身のアプリの要件に沿って実装方針を決め、それぞれの手順を踏んでください。

事前準備

  • デプロイに必要なIBM Cloud CLIとKubernetes CLIのセットアップを完了させる(参考:CLI のセットアップ)
  • アクセスを許可するIPアドレスとレンジを決めておく

1. ServiceでのIPアドレス制限

まずはServiceでのIPアドレス制限を実装する手順についてです。
こちらは公式のドキュメントにセットアップ手順が書いてあるので、こちらに沿って実装していきます。

手順概要

① アカウントでプロビジョンされているサブネットの確認
② NLBにてIP制限をする設定を組み込んだServiceを作成する
③ Serviceが作成されたことを確認する
④ IPアドレス制限が機能していることを確認する

① アカウントでプロビジョンされているサブネットの確認

以下のコマンドを実行します。
<クラスターID>としている箇所はご自身のクラスターのIDに置き換えた上で実行をしてください。

$ ibmcloud ks cluster get --cluster <クラスターID> --show-resources

出力内容からサブネット情報を確認します。

$ ibmcloud ks cluster get --cluster <クラスターID> --show-resources
クラスター <クラスターID> とそのすべてのリソースを取得中...
OK

名前:                                         sample-cluster
ID:                                           <クラスターID>
状態:                                         normal
状況:                                         All Workers Normal
作成日:                                       2022-07-06T09:44:43+0000
ロケーション:                                 tok02
...
サブネット VLAN //以下の値を参照する
VLAN ID   サブネット CIDR      パブリック   ユーザー管理
2234945   xxx.xxx.xxx.xxx/xx   false        false
2234943   xxx.xxx.xxx.xxx/xx   true         false 

② NLBにてIP制限をする設定を組み込んだServiceを作成する

ドキュメントを参考に、以下のようなyamlファイルを作成します。(名前はmynlb.yamlとします)

mynlb.yaml
apiVersion: v1
kind: Service
metadata:
  name: myloadbalancer
  annotations:
    service.kubernetes.io/ibm-load-balancer-cloud-provider-ip-type: <public_or_private>
    service.kubernetes.io/ibm-load-balancer-cloud-provider-vlan: "<vlan_id>"
spec:
  type: LoadBalancer
  loadBalancerSourceRanges: 
    - "<アクセスを許可するIPアドレスのレンジ>"
  selector:
    <selector_key>: <selector_value>
  ports:
   - protocol: TCP
     port: <port>
     targetPort: <port> # Optional. By default, the `targetPort` is set to match the `port` value unless specified otherwise.

置き換えが必要な設定値の説明は以下の通りです。

  • service.kubernetes.io/ibm-load-balancer-cloud-provider-ip-type
    NLBのタイプをprivateまたはpublicから選択します。今回サービスはインターネットからのアクセスが想定されるためpublicを選択します。
  • service.kubernetes.io/ibm-load-balancer-cloud-provider-vlan
    前の手順で出力さえた情報のうち、publicのVLAN IDを記載します。
  • loadBalancerSourceRanges
    アクセスを許可するIPアドレスのレンジを記載します。
  • selector
    アプリをデプロイしたyamlファイルの spec.template.metadata.labels セクションで使用した、ラベル・キー(<selector_key>)と値 (<selector_value>)を記載します。
  • port
    Serviceがlistenするportの番号です。アプリをデプロイしたyamlファイルの、spec.containers.portsセクションのcontainerPortの値を記載します。

例として、port 3000を指定してデプロイしたアプリ「app: sample-app」に対するServiceが「111.222.333.0/24」のIPアドレスのレンジからのアクセスを許可するyamlファイルは以下のようになります。

mynlb.yaml
apiVersion: v1
kind: Service
metadata:
  name: myloadbalancer
  annotations:
    service.kubernetes.io/ibm-load-balancer-cloud-provider-ip-type: publicc
    service.kubernetes.io/ibm-load-balancer-cloud-provider-vlan: "2234943"
spec:
  type: LoadBalancer
  loadBalancerSourceRanges: 
    - "111.222.333.0/24"
  selector:
    app: sample-app
  ports:
   - protocol: TCP
     port: 3000
     targetPort: 3000 

※ IPアドレスを複数記載する場合は文頭にハイフン(-)をつけた上で改行し追記してください。
yamlファイルができたら以下コマンドにてServiceを作成します。

$ kubectl apply -f mynlb.yaml

③ Serviceが作成されたことを確認する

NLB サービスが正常に作成されたことを確認します。 サービスが作成され、アプリが利用可能になるまでに数分かかることがあります。

$ kubectl describe service myloadbalancer

実行すると以下のような出力があります。
出力内容から、EventにてServiceの作成が完了しているか、yamlにて設定した内容が反映されているかを確認してください。

$ kubectl describe service myloadbalancer
NAME:                   myloadbalancer
Namespace:              default
Labels:                 <none>
Selector:               app=sample-app
Type:                   LoadBalancer
Location:               tok02
IP:                     172.21.xxx.xxx
LoadBalancer Ingress:   169.xx.xxx.xxx
Port:                   <unset> 3000/TCP
NodePort:               <unset> 32040/TCP
Endpoints:              172.30.xxx.xxx:8080
Session Affinity:       None
External Traffic Policy:     Cluster
LoadBalancer Source Ranges:  111.222.333.0/24
Events:
    FirstSeen    LastSeen    Count    From            SubObjectPath    Type     Reason                      Message
    ---------    --------    -----    ----            -------------    ----     ------                      -------
    10s            10s            1        {service-controller }      Normal CreatingLoadBalancer    Creating load balancer
    10s            10s            1        {service-controller }        Normal CreatedLoadBalancer    Created load balancer

④ IPアドレス制限が機能していることを確認する

yamlファイルにてloadBalancerSourceRangesに記載したアクセスを許可するIPアドレスからアプリにアクセスし(前手順にて出力された"LoadBalancer Ingress"のIPアドレスからアクセスできます)、アクセスができることを確認してください。

続いてloadBalancerSourceRangesに記載されていないIPアドレスからアプリにアクセスすると、接続が拒否されアプリにアクセスができないことを確認してください。
image.png

手順は以上です。

補足

EKSでの話のようですが、こちらの記事にて「設定可能なIPアドレスは60件までで、それ以上を設定すると機能しなくなる」との記載がありましたので、たくさんIPアドレスを設定する場合はご注意ください。

2. IngressでのIPアドレス制限

こちらの手順についてはIKSのドキュメントに記載がないため、こちらのEKSでの実装に関する記事を参考させていただき検証を行いました。

事前準備

事前準備としてアプリに接続するためのServiceと、IPアドレス制限前のIngressを作成します。
すでに作成済みのものがあれば、こちらは飛ばして問題ありません。

Serviceの作成

以下のようなService作成用のyamlファイルを作成します。

myservice.yaml
apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  type: ClusterIP
  selector:
    <selector_key>: <selector_value>
  ports:
   - protocol: TCP
     port: <port>
     targetPort: <port> # Optional. By default, the `targetPort` is set to match the `port` value unless specified otherwise.

置き換えが必要な設定値の説明は以下の通りです。

  • selector
    アプリをデプロイしたyamlファイルの spec.template.metadata.labels セクションで使用した、ラベル・キー(<selector_key>)と値 (<selector_value>)を記載します。
  • port
    Serviceがlistenするportの番号です。アプリをデプロイしたyamlファイルの、spec.containers.portsセクションのcontainerPortの値を記載します。

「1. ServiceでのIPアドレス制限」で作成したServiceと異なる点は以下の2点です。

  • NLBの設定項目が削除されたこと
  • Ingressと接続するため、Serviceタイプが"ClusterIP"になっていること

yamlを作成したら、以下のコマンドを実行しSeriviceを作成してください。

$ kubectl apply -f myservice.yaml

Ingressの作成

以下のようなIngress作成用のyamlファイルを作成します。(今回はパブリックALBを前提として定義します)

myingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myingress
  annotations:
    kubernetes.io/ingress.class: "public-iks-k8s-nginx"
spec:
  tls:
  - hosts:
    - <ドメイン名>
    secretName: <TLSシークレット名>
  - host: <ドメイン名>
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service: 
            name: myservice
            port:
              number: 3000

置き換えが必要な設定値の説明は以下の通りです。(詳細はこちら

  • tls.hosts/host
    IBM提供のIngressサブドメインまたはカスタム・ドメインで置き換えます。

  • tls.secretName
    TLS証明書が保管されている Kubernetes シークレットの名前に置き換えます。

yamlを作成したら、以下のコマンドを実行しIngressを作成してください。(現時点のIngressを作成するとアプリが制限なく公開されるのでご注意)

$ kubectl apply -f myingress.yaml

myingress.yaml内のhostに定義したドメインにアクセスし、アプリにアクセスできるか確認してください。

手順概要

① アクセス元のIPアドレスを保持する設定にALBを変更する
② IPアドレス制限設定を行う
③ IPアドレス制限が機能していることを確認する

① アクセス元のIPアドレスを保持する設定にALBを変更する

こちらの手順に関してはIKSのドキュメントに記載があるため、そちらに沿って設定変更を行います。

前動作確認

まず、ALBにてIPアドレス制限をかける場合はアクセス元のIPアドレスは保持する必要がありますが、デフォルトではALBはアクセス元のIPアドレスは保持されません。
よってIKSにデプロイしたアプリ側のバックエンドでリクエストヘッダー内の'x-forwarded-for'を出力すると、実際のアクセス元のIPアドレスではなく、アプリがデプロイされているワーカー・ノードのIPアドレスが表示されます。

以下node.jsのバックエンドサーバーにてIPアドレスを出力する例です。

server.js
app.use((req, res, next) => {
  const ip = req.headers['x-forwarded-for']||'null';
  console.log('IP : ' + ip) //ワーカー・ノードのIPアドレスが出力される
  return next()
})

アプリで出力させるのが難しい場合は、ALB Podのログから確認することも可能です。
ALB Podのログを確認するには、まず以下のコマンドにてALB PodのIDを確認します。

$ kubectl get pods -n kube-system | grep alb

続いて、以下のコマンドにて対象のALB Podのログを出力します(コマンドはログの最後20行を出力させるものとなっています)。
<ALB_pod_ID>となっている箇所は前手順で確認したALB PodのIDに置き換えてください。

$ kubectl logs --tail=20 <ALB_pod_ID> nginx-ingress -n kube-system

これらを本来のアクセス元のIPアドレスを保持させたいとなった場合は、ALBの設定変更が必要となります。
設定変更前のIPアドレスの受け渡し状況を確認したら、本題の設定変更に移ります。

ALBの設定変更

今回は単一のALBのアクセス元のIPアドレスを保持をセットアップします。
ALBの設定変更をするために、まず対象となるALBのIDを取得します。

$ kubectl get svc -n kube-system | grep alb

出力例は以下の通りです。

$ kubectl get svc -n kube-system | grep alb
public-xxxxx-alb1   LoadBalancer   aaa.aaa.aaa.aaa     bbb.bbb.bbb.bbb   cc:ccccc/TCP,ddd:ddddd/TCP   44m

対象となるALBのIDを確認したら、以下のコマンドを実行します。
<ALB_ID>としている箇所は、前手順で確認した対象ALBのIDに置き換えて実行してください。

$ kubectl edit svc <ALB_ID> -n kube-system

実行するとALBの設定ファイルをviモードで編集できるようになります。
変更が必要な箇所は、"spec.externalTrafficPolicy"です。こちらの設定値の値がデフォルトで「Cluster」になっているところを「Local」に変更します。

...
  clusterIPs:
  - xxx.xxx.xxx.xxx
  externalTrafficPolicy: Local //この設定値を「Cluster」から「Local」に変更
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
...

編集が完了したら、viモードと同様「:wq」で保存・終了してください。

後動作確認

編集完了直後から設定が反映されます。こちらで確認した限り、ALBのダウンタイムは発生しませんでした。
アプリないしはALB Podのログからきちんと変更が反映されているかを確認してください。

ちなみにこのexternalTrafficPolicyの設定がClusterのままだと後続のIPアドレス制限設定が機能しないので、ご注意ください。

② IPアドレス制限設定を行う

設定変更の反映が確認できたら事前準備で作成したmyingress.yamlにIPアドレス制限の設定を加えます。
以下のように、"nginx.ingress.kubernetes.io/whitelist-source-range"設定を追加したyamlを作成してください。

myingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myingress
  annotations:
    kubernetes.io/ingress.class: "public-iks-k8s-nginx"
    nginx.ingress.kubernetes.io/whitelist-source-range: <アクセスを許可するIPアドレスのレンジ>
spec:
  tls:
  - hosts:
    - <ドメイン名>
    secretName: <TLSシークレット名>
  - host: <ドメイン名>
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service: 
            name: myservice
            port:
              number: 3000

※ IPアドレスを複数記載する場合はコンマ(,)区切りで1文で記載してください。
yamlを作成したら、以下のコマンドを実行しIngressを更新してください。

$ kubectl apply -f myingress.yaml

③ IPアドレス制限が機能していることを確認する

Ingressの更新が完了したら、動作確認をします。

nginx.ingress.kubernetes.io/whitelist-source-rangeで定義した、アクセスを許可するIPアドレスからアプリにアクセスし、アプリにアクセスが可能であることを確認してください。

続いて、nginx.ingress.kubernetes.io/whitelist-source-rangeに定義していないIPアドレスからアプリにアクセスすると、403エラーでアクセスが拒否されることを確認してください。

手順は以上です。

最後に

手順が分かってしまえば簡単にIPアドレス制限を実装できることがわかりました。
アプリの改修をせずに制限を実装できるのも魅力的ですね。

ちなみに、IngressでIPアドレス制限を実装した場合デフォルトではnginxの403エラー画面が表示されますが、こちらのエラー画面のカスタマイズもできることを確認してますので気が向いたらこちらも記事にしたいと思います。
こちらの手順についてはこの記事で割と丁寧に記載があるので気になる方は参考にしていただければと思います。

参考文献

おわり

更新履歴

  • 2023/5/12 公開
  • 2023/6/5 IPアドレスの複数記載方法を追記
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?