Linode Kubernetes Engine (LKE) のワーカーノードの IP を外部に公開する必要がある場合、ネットワークアクセス制御のためにLinode Firewall を設定します。サービスタイプ:NodePort
で起動されたそれぞれのワーカーノードに Firewall を適用する場合、その管理が課題になるケースがあります。Kubernetesはノードのオートスケールに対応しているものの、Firewall の適用を手動で実行する必要がありました。この手動プロセスは、クラスターのオートスケール、アップグレード、サイズ変更、ノードプールのリサイクルで問題となり、メンテナンスの労力とヒューマンエラーのリスクを増加させます。
本文で紹介する Linode Firewall Operator を用いると、クラスターワーカーノードを Linode Firewall インスタンスに自動接続する構成をとれるため、上記の課題に対処し、クラスターのセキュリティ管理を改善します。
ロードバランサーを使うパターンでは、ワーカーノードはロードバランサーの後方に配置されるので、各ワーカーノードに対する Firewall 管理は不要です。NodeBalancer へ Firewall を適用できるからです。LKE クラスターにロードバランサーを適用する場合は下記の資料を参考にしてください。
ロードバランサーを適用できないパターンに本文で紹介する Firewall Operator は有効です。例えば、ロードバランサーが本原稿執筆時点で対応していない UDP で通信する必要がある場合や、それぞれのワーカーノードが直接パブリック IP を持って外部と通信する必要がある場合です。
Linode Firewall Operator の動き
イベント駆動型の自動 Firewall 適用
Operator は Kubernetes クラスターイベントに基づいて、該当する Linode Firewall からワーカーノードを自動的に追加または削除します。ノードが作成または削除されると、現在のノードリストと Firewall のデバイスリストが照合され管理すべきデバイス(ノード)を最新の状態に保ちます。
クラスター内のノードに同じ Firewall ルールを適用
Linode Firewall Operator はクラスターと Firewall インスタンスの間に 1:1 の関係を想定し、ノードプールに関係なくすべてのノードを平等に扱い、同じ Firewall ルールを適用します。
ノード削除処理
Linode は削除されたノードを自動的に Firewall のリストから削除します。そして、Operator はこれらの削除を検証し、ログに記録します。
将来の開発では、Oprator を使うことなく、Firewall インスタンスに Kubernetes クラスターをマッピングできる予定です。この機能に興味がある方はご連絡ください。
クイックスタート
以下にあるコードを使って実行します。
前提条件
Linode Firewall インスタンスID、Linode APIキー、LKEインスタンスを準備します。
Firewall ID は次の API Doc を参考に取得してください。
Linode API キーは下記の記事を参考にしてください。
設定手順
Operator を起動して実行するには 2 つのステップを行います。
必要な Custom Resource Definitions(CRD) と Operator を配置する
curl -s https://raw.githubusercontent.com/gangyi89/deploy-linode-operator/main/deploy-linode-fw-operator.sh | bash -s -- <MY_NAMESPACE>
Firewall オブジェクトをコピーする
1. サンプルで提供されている cluster-firewall.yaml をコピーします。
2. Firewall ID と API-Key を設定します。
パラメータの説明です。
1 | 2 |
---|---|
ClusterFirewall | オブジェクトを宣言する際に利用可能なパラメータです |
firewallId | クラスタ専用の Firewall インスタンスのIDです |
apiKeySecret | Kubernetes Secretに格納されている 「Firewalls Read/Write 」権限を持つAPIキーです |
Interval(オプション | 定期的なリコンサイルを実行します |
3. Firewallオブジェクトをデプロイします。以下は default ネームスペースの例です。
kubectl apply -f cluster-firewall.yaml -n default
Kubernetes deployment を確認する (Option)
% kubectl get deployments linode-fw-operator
NAME READY UP-TO-DATE AVAILABLE AGE
linode-fw-operator 1/1 1 1 9d
Linode Firewall Operator の Pod を確認する
linode-fw-operator
で始まる Pod が動作していれば設定は完了しています。
% kubectl get pods
NAME READY STATUS RESTARTS AGE
linode-fw-operator-XXXXXXXXXXX-XXXds 1/1 Running 0 41m
static-site-deployment-XXXXXXXXXX-9hzvl 1/1 Running 0 35m
static-site-deployment-XXXXXXXXXX-rqxlx 1/1 Running 0 41m
static-site-deployment-XXXXXXXXXX-rxn49 1/1 Running 0 35m
デバッグ方法
kubectl describe
% kubectl describe clusterfirewall
Warning: Use tokens from the TokenRequest API or manually created secret-based tokens instead of auto-generated secret-based tokens.
Name: clusterfirewall
Namespace: default
Labels: app.kubernetes.io/name=linodeoperator
Annotations: <none>
API Version: firewall.operator.linode.io/v1alpha1
Kind: ClusterFirewall
Metadata:
Creation Timestamp: 2024-07-19T02:52:29Z
Generation: 1
Resource Version: 102467285
UID: 16274495-5999-497d-823d-2c4c106385e0
Spec:
API Key Secret:
Key: api-key
Name: linode-api-key
Firewall Id: 6....5
Status:
Nodes:
lkeZZZZZZ-XXXXXX-YYYYYYYYYY1b
lkeZZZZZZ-XXXXXX-YYYYYYYYYYee
lkeZZZZZZ-XXXXXX-YYYYYY87YY00
lkeZZZZZZ-XXXXXX-YYYYYYYYYYcb
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal DeviceDeleted 58m clusterfirewall-controller Node lkeZZZZZZ-XXXXXX-1d915e640000 is removed from firewall ID 6....5
Normal DeviceDeleted 40m clusterfirewall-controller Node lkeZZZZZZ-XXXXXX-YYYYYYYYYYcb is removed from firewall ID 6....5
Normal DeviceAdded 39m clusterfirewall-controller Node lkeZZZZZZ-XXXXXX-YYYYYYYYYYcb is added to firewall ID 6....5
Normal DeviceDeleted 37m clusterfirewall-controller Node lkeZZZZZZ-XXXXXX-YYYYYYYYYY1b is removed from firewall ID 6....5
Normal DeviceAdded 36m clusterfirewall-controller Node lkeZZZZZZ-XXXXXX-YYYYYYYYYY1b is added to firewall ID 6....5
Normal DeviceAdded 34m clusterfirewall-controller Node lkeZZZZZZ-XXXXXX-YYYYYY87YY00 is added to firewall ID 6....5
Normal DeviceDeleted 32m clusterfirewall-controller Node lkeZZZZZZ-XXXXXX-YYYYYYYYYYee is removed from firewall ID 6....5
Normal DeviceAdded 31m (x2 over 37m) clusterfirewall-controller Node lkeZZZZZZ-XXXXXX-YYYYYYYYYYee is added to firewall ID 6....5
kubectl logs
% kubectl logs linode-fw-operator-XXXXXXXXXXX-XXXds --tail 5
Warning: Use tokens from the TokenRequest API or manually created secret-based tokens instead of auto-generated secret-based tokens.
2024-07-28T07:04:29Z DEBUG events Node lkeZZZZZZ-XXXXXX-YYYYYYYYYYee is removed from firewall ID 6....5 {"type": "Normal", "object": {"kind":"ClusterFirewall","namespace":"default","name":"clusterfirewall","uid":"16274495-5999-497d-823d-2c4c106385e0","apiVersion":"firewall.operator.linode.io/v1alpha1","resourceVersion":"102466194"}, "reason": "DeviceDeleted"}
2024-07-28T07:04:29Z INFO Reconciliation Completed {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall", "ClusterFirewall": {"name":"clusterfirewall","namespace":"default"}, "namespace": "default", "name": "clusterfirewall", "reconcileID": "2f329979-2b25-475b-a622-2226f1a0c38f"}
2024-07-28T07:05:28Z INFO Reconciliation Started {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall", "ClusterFirewall": {"name":"clusterfirewall","namespace":"default"}, "namespace": "default", "name": "clusterfirewall", "reconcileID": "1b107132-29f7-4c0b-a2de-836f727e828e"}
2024-07-28T07:05:28Z DEBUG events Node lkeZZZZZZ-XXXXXX-YYYYYYYYYYee is added to firewall ID 6....5 {"type": "Normal", "object": {"kind":"ClusterFirewall","namespace":"default","name":"clusterfirewall","uid":"16274495-5999-497d-823d-2c4c106385e0","apiVersion":"firewall.operator.linode.io/v1alpha1","resourceVersion":"102466984"}, "reason": "DeviceAdded"}
2024-07-28T07:05:28Z INFO Reconciliation Completed {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall", "ClusterFirewall": {"name":"clusterfirewall","namespace":"default"}, "namespace": "default", "name": "clusterfirewall", "reconcileID": "1b107132-29f7-4c0b-a2de-836f727e828e"}
動作確認
Operator が動作していない Node をとめる
まずは、Operator が動作していないノードを止めて、Linode のインスタンスと Firewall の関係がどのように動くのか見てみます。Linode Firewall Operator である linode-fw-operator-XXXXXXXXXXX-XXXds
は lkeZZZZZZ-XXXXXX-YYYYYYYYYYcb
のノードで動いています。
% kubectl get pods -o wide
Warning: Use tokens from the TokenRequest API or manually created secret-based tokens instead of auto-generated secret-based tokens.
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
linode-fw-operator-XXXXXXXXXXX-XXXds 1/1 Running 0 64m 10.2.0.4 lkeZZZZZZ-XXXXXX-YYYYYYYYYYcb <none> <none>
static-site-deployment-XXXXXXXXXX-9hzvl 1/1 Running 0 57m 10.2.1.3 lkeZZZZZZ-XXXXXX-YYYYYYYYYY1b <none> <none>
static-site-deployment-XXXXXXXXXX-rqxlx 1/1 Running 0 64m 10.2.0.2 lkeZZZZZZ-XXXXXX-YYYYYYYYYYcb <none> <none>
static-site-deployment-XXXXXXXXXX-rxn49 1/1 Running 0 57m 10.2.1.132 lkeZZZZZZ-XXXXXX-YYYYYY87YY00 <none> <none>
Linode firewall Operator が動作していない lkeZZZZZZ-XXXXXX-YYYYYY87YY00
をリサイクルすると、 Linode Cloud Firewall は次のようにイベントを受け取り、 Linode Cloud Firewall から該当するノードを一旦削除します。
% kubectl logs linode-fw-operator-XXXXXXXXXXX-XXXds --tail 1 -f
2024-07-28T08:18:16Z INFO Reconciliation Started {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall", "ClusterFirewall": {"name":"clusterfirewall","namespace":"default"}, "namespace": "default", "name": "clusterfirewall", "reconcileID": "a42b650e-a6d8-4e3d-83e7-966cea156438"}
2024-07-28T08:18:16Z DEBUG events Node lkeZZZZZZ-XXXXXX-YYYYYY87YY00 is removed from firewall ID 6....5 {"type": "Normal", "object": {"kind":"ClusterFirewall","namespace":"default","name":"clusterfirewall","uid":"16274495-5999-497d-823d-2c4c106385e0","apiVersion":"firewall.operator.linode.io/v1alpha1","resourceVersion":"102484424"}, "reason": "DeviceDeleted"}
2024-07-28T08:18:16Z INFO Reconciliation Completed {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall", "ClusterFirewall": {"name":"clusterfirewall","namespace":"default"}, "namespace": "default", "name": "clusterfirewall", "reconcileID": "a42b650e-a6d8-4e3d-83e7-966cea156438"}
UI 上でも lkeZZZZZZ-XXXXXX-YYYYYY87YY00
のノードは Firewall のデバイスリストから削除されています。
しばらくして、linode-fw-operator-XXXXXXXXXXX-XXXds
のログを見ると次のように表示されています。lkeZZZZZZ-XXXXXX-YYYYYY87YY00
のノードがリサイクルされ、再度起動したタイミングで Firewall のデバイスリストに登録されているメッセージが見えます。
2024-07-28T08:19:27Z INFO Reconciliation Started {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall", "ClusterFirewall": {"name":"clusterfirewall","namespace":"default"}, "namespace": "default", "name": "clusterfirewall", "reconcileID": "8f4aaae5-b838-4bb6-8527-eeec2471b729"}
2024-07-28T08:19:28Z DEBUG events Node lkeZZZZZZ-XXXXXX-YYYYYY87YY00 is added to firewall ID 6....5 {"type": "Normal", "object": {"kind":"ClusterFirewall","namespace":"default","name":"clusterfirewall","uid":"16274495-5999-497d-823d-2c4c106385e0","apiVersion":"firewall.operator.linode.io/v1alpha1","resourceVersion":"102485027"}, "reason": "DeviceAdded"}
2024-07-28T08:19:28Z INFO Reconciliation Completed {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall", "ClusterFirewall": {"name":"clusterfirewall","namespace":"default"}, "namespace": "default", "name": "clusterfirewall", "reconcileID": "8f4aaae5-b838-4bb6-8527-eeec2471b729"}
UI 上でも lkeZZZZZZ-XXXXXX-YYYYYY87YY00
のノードが Firewall のデバイスリストに再登録されています。
このように Operator の仕組みを使うと、デバイスの削除、追加に伴い、登録した動作を自動で行ってくれます。
Operator が動作している Node を削除する
Operator はいずれかの Node 内の Pod で動きますが、その Node が停止しても、Operator は自動的に別の Node で動きます。
Operator が動作している Node をリサイクルすると、次のように Operator のログは取れなくなります。
% kubectl logs linode-fw-operator-XXXXXXXXXXX-XXXds --tail 1 -f
2024-07-28T08:40:09Z INFO Stopping and waiting for non leader election runnables
2024-07-28T08:40:09Z INFO Stopping and waiting for leader election runnables
2024-07-28T08:40:09Z INFO Shutdown signal received, waiting for all workers to finish {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall"}
2024-07-28T08:40:09Z INFO All workers finished {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall"}
2024-07-28T08:40:09Z INFO Stopping and waiting for caches
W0728 08:40:09.090703 1 reflector.go:470] pkg/mod/k8s.io/client-go@v0.30.0/tools/cache/reflector.go:232: watch of *v1alpha1.ClusterFirewall ended with: an error on the server ("unable to decode an event from the watch stream: context canceled") has prevented the request from succeeding
W0728 08:40:09.090864 1 reflector.go:470] pkg/mod/k8s.io/client-go@v0.30.0/tools/cache/reflector.go:232: watch of *v1.Node ended with: an error on the server ("unable to decode an event from the watch stream: context canceled") has prevented the request from succeeding
W0728 08:40:09.090947 1 reflector.go:470] pkg/mod/k8s.io/client-go@v0.30.0/tools/cache/reflector.go:232: watch of *v1.Secret ended with: an error on the server ("unable to decode an event from the watch stream: context canceled") has prevented the request from succeeding
2024-07-28T08:40:09Z INFO Stopping and waiting for webhooks
2024-07-28T08:40:09Z INFO Stopping and waiting for HTTP servers
2024-07-28T08:40:09Z INFO shutting down server {"name": "health probe", "addr": "[::]:8081"}
2024-07-28T08:40:09Z INFO Wait completed, proceeding to shutdown the manager
%
Linode Firewall Operator が動いていたノード lkeZZZZZZ-XXXXXX-YYYYYYYYYYcb
は一旦見えなくなります。
% kubectl get nodes
NAME STATUS ROLES AGE VERSION
lkeZZZZZZ-XXXXXX-YYYYYY87YY00 Ready <none> 20m v1.29.2
lkeZZZZZZ-XXXXXX-YYYYYYYYYYee Ready <none> 94m v1.29.2
lkeZZZZZZ-XXXXXX-YYYYYYYYYY1b Ready <none> 99m v1.29.2
しかし、Linode Firewall Operator は別のノードで動いています。
% kubectl get pods -o "custom-columns=NAME:.metadata.name,NODENAME:.spec.nodeName"
NAME NODENAME
linode-fw-operator-XXXXXXXXXXX-wqj8p lkeZZZZZZ-XXXXXX-YYYYYYYYYY1b
static-site-deployment-XXXXXXXXXX-29849 lkeZZZZZZ-XXXXXX-YYYYYYYYYYee
static-site-deployment-XXXXXXXXXX-9hzvl lkeZZZZZZ-XXXXXX-YYYYYYYYYY1b
static-site-deployment-XXXXXXXXXX-sn9f9 lkeZZZZZZ-XXXXXX-YYYYYY87YY00
先ほどまでは、lkeZZZZZZ-XXXXXX-YYYYYYYYYYcb
で動いていましたが、そのノードを止めた後、lkeZZZZZZ-XXXXXX-YYYYYYYYYY1b
で動いていることが確認できます。
% kubectl get pods
NAME READY STATUS RESTARTS AGE
linode-fw-operator-XXXXXXXXXXX-wqj8p 1/1 Running 0 27s
static-site-deployment-XXXXXXXXXX-29849 1/1 Running 0 25m
static-site-deployment-XXXXXXXXXX-9hzvl 1/1 Running 0 96m
static-site-deployment-XXXXXXXXXX-sn9f9 1/1 Running 0 27s
新しい Pod の名前でログを見ます。
% kubectl logs linode-fw-operator-XXXXXXXXXXX-wqj8p -f
Warning: Use tokens from the TokenRequest API or manually created secret-based tokens instead of auto-generated secret-based tokens.
2024-07-28T08:40:11Z INFO setup starting manager
2024-07-28T08:40:11Z INFO starting server {"name": "health probe", "addr": "[::]:8081"}
I0728 08:40:11.313307 1 leaderelection.go:250] attempting to acquire leader lease default/a7b178ce.operator.linode.io...
I0728 08:40:29.230370 1 leaderelection.go:260] successfully acquired lease default/a7b178ce.operator.linode.io
2024-07-28T08:40:29Z DEBUG events linode-fw-operator-XXXXXXXXXXX-wqj8p_b461bad2-3710-4450-9426-ed5e8bdd4aed became leader {"type": "Normal", "object": {"kind":"Lease","namespace":"default","name":"a7b178ce.operator.linode.io","uid":"41d508cb-91ac-41fa-a4e0-6dcb62b7680c","apiVersion":"coordination.k8s.io/v1","resourceVersion":"102490618"}, "reason": "LeaderElection"}
2024-07-28T08:40:29Z INFO Starting EventSource {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall", "source": "kind source: *v1alpha1.ClusterFirewall"}
2024-07-28T08:40:29Z INFO Starting EventSource {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall", "source": "kind source: *v1.Node"}
2024-07-28T08:40:29Z INFO Starting Controller {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall"}
2024-07-28T08:40:29Z INFO Starting workers {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall", "worker count": 1}
2024-07-28T08:40:29Z INFO Reconciliation Started {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall", "ClusterFirewall": {"name":"clusterfirewall","namespace":"default"}, "namespace": "default", "name": "clusterfirewall", "reconcileID": "52dde7aa-0419-416e-b4d3-9b9441e15b50"}
2024-07-28T08:40:29Z INFO Reconciliation Completed {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall", "ClusterFirewall": {"name":"clusterfirewall","namespace":"default"}, "namespace": "default", "name": "clusterfirewall", "reconcileID": "52dde7aa-0419-416e-b4d3-9b9441e15b50"}
2024-07-28T08:41:21Z INFO Reconciliation Started {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall", "ClusterFirewall": {"name":"clusterfirewall","namespace":"default"}, "namespace": "default", "name": "clusterfirewall", "reconcileID": "0205df5f-7d0e-4b69-b07d-f4da3d2f989f"}
2024-07-28T08:41:21Z DEBUG events Node lkeZZZZZZ-XXXXXX-YYYYYYYYYYcb is added to firewall ID 6....5 {"type": "Normal", "object": {"kind":"ClusterFirewall","namespace":"default","name":"clusterfirewall","uid":"16274495-5999-497d-823d-2c4c106385e0","apiVersion":"firewall.operator.linode.io/v1alpha1","resourceVersion":"102490626"}, "reason": "DeviceAdded"}
2024-07-28T08:41:21Z INFO Reconciliation Completed {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall", "ClusterFirewall": {"name":"clusterfirewall","namespace":"default"}, "namespace": "default", "name": "clusterfirewall", "reconcileID": "0205df5f-7d0e-4b69-b07d-f4da3d2f989f"}
clusterfirewall にイベントが登録されています。
% kubectl describe clusterfirewall
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal DeviceDeleted 30m clusterfirewall-controller Node lkeZZZZZZ-XXXXXX-YYYYYY87YY00 is removed from firewall ID 6....5
Normal DeviceAdded 28m (x3 over 106m) clusterfirewall-controller Node lkeZZZZZZ-XXXXXX-YYYYYY87YY00 is added to firewall ID 6....5
Normal DeviceAdded 7m3s clusterfirewall-controller Node lkeZZZZZZ-XXXXXX-YYYYYYYYYYcb is added to firewall ID 6....5
このように Operator は動いているノードが削除されても、自律的に API Server 経由でイベントを受け取り、新しいノードで Opertor を継続して動かすことができるので、信頼性ある仕組みを作ることができます。
新しいノードを追加する
新しいノードが追加されたときに自動的に Firewall ルールが適用されるかを確認します。ここでは 5 つ目のノードを追加します。ノードが5つ見えます。
% kubectl get nodes
Warning: Use tokens from the TokenRequest API or manually created secret-based tokens instead of auto-generated secret-based tokens.
NAME STATUS ROLES AGE VERSION
lkeZZZZZZ-XXXXXX-YYYYYY9dYY00 Ready <none> 9m59s v1.29.2
lkeZZZZZZ-XXXXXX-YYYYYY87YY00 Ready <none> 65m v1.29.2
lkeZZZZZZ-XXXXXX-YYYYYYYYYYcb Ready <none> 43m v1.29.2
lkeZZZZZZ-XXXXXX-YYYYYYYYYYee Ready <none> 139m v1.29.2
lkeZZZZZZ-XXXXXX-YYYYYYYYYY1b Ready <none> 144m v1.29.2
そのときに、Linode Firewall Operator はイベントを補足し、次のイベントを駆動します。
2024-07-28T09:15:02Z INFO Reconciliation Started {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall", "ClusterFirewall": {"name":"clusterfirewall","namespace":"default"}, "namespace": "default", "name": "clusterfirewall", "reconcileID": "1d51b8a5-63dc-484f-8253-c412d01d6fb0"}
2024-07-28T09:15:03Z DEBUG events Node lkeZZZZZZ-XXXXXX-YYYYYY9dYY00 is added to firewall ID 6....5 {"type": "Normal", "object": {"kind":"ClusterFirewall","namespace":"default","name":"clusterfirewall","uid":"16274495-5999-497d-823d-2c4c106385e0","apiVersion":"firewall.operator.linode.io/v1alpha1","resourceVersion":"102490855"}, "reason": "DeviceAdded"}
2024-07-28T09:15:03Z INFO Reconciliation Completed {"controller": "clusterfirewall", "controllerGroup": "firewall.operator.linode.io", "controllerKind": "ClusterFirewall", "ClusterFirewall": {"name":"clusterfirewall","namespace":"default"}, "namespace": "default", "name": "clusterfirewall", "reconcileID": "1d51b8a5-63dc-484f-8253-c412d01d6fb0"}
clusterfirewall にも新しいイベントの記録が見えます。
Normal DeviceAdded 70s clusterfirewall-controller Node lkeZZZZZZ-XXXXXX-YYYYYY9dYY00 is added to firewall ID 6....5
UI 上でも次のように自動的に新しいノードに対して Firewall ルールが適用されていることが分かります。
このように LKE 内でノードが新規に追加されても、Operator が動的に Linode Firewall を適用してくれます。
ノードを削減する
ノードが削減されたときにどのように動くのか見てみます。ノードの数を 5 から 3 に削減します。次の結果は削減された後のステータスです。
% kubectl get nodes
Warning: Use tokens from the TokenRequest API or manually created secret-based tokens instead of auto-generated secret-based tokens.
NAME STATUS ROLES AGE VERSION
lkeZZZZZZ-XXXXXX-YYYYYYYYYYcb Ready <none> 58m v1.29.2
lkeZZZZZZ-XXXXXX-YYYYYYYYYYee Ready <none> 154m v1.29.2
lkeZZZZZZ-XXXXXX-YYYYYYYYYY1b Ready <none> 159m v1.29.2
UI でも 5 から 3 つのデバイスに変更されていることが分かります。
Linode Firewall Operator のサンプルルール
Outbound ルールを Drop をデフォルトにすると、内部の通信で問題がおきます。以下にサンプルのルールを置いていますので参考にしてください。
まとめ
本記事は Linode Kubernetes Engine クラスターで Operator を設定した例です。イベント駆動で、それ自体で回復することができる素晴らしいソリューションです。LKE 内のクラスターノードに動的に Firewall ルールが設定できれば良いのですが、本原稿執筆時点ではその機能が提供されていないため、Operator を使って同様なことを実現しました。Operatorはノード上のPodとして動作し、ノードがリサイクルされると、新しい Operator がすぐに別のノードで実行されます。その後、Operator は新しいノード上で Firewall をアタッチすることができています。Kubernetes Operator はその名の通り、動的なオペレーターとして動かすことができるため、有効な手段として今回は紹介させていただきました。是非ご活用ください。