k8sのパケットフィルタリング機能

kubernetesの NetworkPolicyは、pod間のパケット転送を限定するリソースです。

内部pod間の接続トポロジーを限定できるほか、denyリストによるIP-banを実装できる場合もあります。
ただし、NetworkPolicyリソースの記述方法は標準化されているものの、解釈と挙動は実装により異なる点には注意が必要です。

たとえば GKEのNetworkPolicyの実装は、従来はCalicoを採用しており、Dataplane V2を有効にしているクラスタではCiliumが動作しています。
そして、CalicoとCiliumで同じリソース定義でも挙動が異なります。

他のサービスや将来の移行を含め、クラスタごとに指定方法が異なるため、あらかじめ構成を検証することが必要です。

iptablesを置き換える機能

従来のベアメタルなLinuxホストのパケットフィルタリングはiptablesを用いた実装が一般的でしたが、kubernetesでは同様の目的にNetworkPolicyを用いて実装します。

実装にもよりますが、kubernetesの内部ネットワーク機能がiptablesと競合するため、コンテナ内ではiptablesnftablesを利用できないことも多いでしょう。
無理やり従来のツールを導入すると仮想ネットワークが壊れる可能性があります。

NetworkPolicyの定義

NetworkPolicyを用いて接続IPを制限する例のミニマムな記述は次のようなものになります。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
    - Ingress
  ingress:
    - from:
        - ipBlock:
            cidr: 172.17.0.0/16
            except:
              - 172.17.1.0/24

このように、対象podとフィルタを定義します。

  • 制御対象のpodはspec.podSelectorで指定する。対象は一般的なpodセレクターで定義
    • NetworkPolicyはネームスペース内リソースであり、metadata.namespaceも対象podのフィルタとして機能している
  • ingress.fromで接続元をフィルタしてアクセス制御する。
    • ipBlock.cidrは接続を許可、ipBlock.exceptは接続を拒否する。自明には見えないので注意
    • この例ではIPで判定しているが、podSelectorでpod間の接続を制御することも可能

定義から読みとりづらいポイントとして、このリソースを反映すると172.17.0.0/16以外の接続は拒否する挙動に変わります。

有効なNetworkPolicyはkubectl get networkpolicyコマンドで確認できます。
フィルタが機能していない場合、podセレクタが適切でないこともあります。意図と異なる定義の場合にも多くは明確にエラーにはならないため、設定をテストすることが重要です。
NetworkPolicyの変更は即座に反映されます。

GKE Dataplane V2のIP-ban実装

ipBlockの解釈が実装により異なるため一般論は語りえないのですが、GKEのDataplane V2は次のような定義でインターネットからのIP-banを実装できています。

  ingress:
    - from:
        - ipBlock:
            cidr: 0.0.0.0/0
            except:
              - 172.17.1.0/24

ipBlock.exceptipBlock.cidrのサブネットワークでなくてはならないのですが、0.0.0.0/0がすべてのIPを包含します。
ただし、Dataplane V2の0.0.0.0/0はじつは「全て」ではなく内部podのIPは除外する挙動になります。そのため、安易に適用すると内部接続が不通になります。

結論として、この形式のNetworkPolicyはネットに面しているエッジコンテナのみで想像どおりに動作します。
もう1点の制約として、そのコンテナのピアが外部エンドポイントのIPである必要もあります。言いかえれば、プロキシの背後ではIPフィルタが機能しないことがあります。

プロキシについても実装依存ですが、GKEの場合にはtype: LoadBalancerで作成したServiceのうちexternalTrafficePolicy: Local設定のエッジや、TCPプロキシの背後でProxyProtocolを用いてIPをデコードしたコンテナといった前提が必要でしょう。

GKEではtype: NodePortで作成したServiceでも期待どおりに動作しています。

内部のコンテナは、IPでは制御できないと考えた方が安全です。

⁋ 2023/12/03↻ 2024/11/07
中馬崇尋
Chuma Takahiro