kubernetesの NetworkPolicyは、pod間のパケット転送を限定するリソースです。
内部pod間の接続トポロジーを限定できるほか、denyリストによるIP-banを実装できる場合もあります。
ただし、NetworkPolicyリソースの記述方法は標準化されているものの、解釈と挙動は実装により異なる点には注意が必要です。
たとえば
GKEのNetworkPolicyの実装は、従来はCalicoを採用しており、Dataplane V2を有効にしているクラスタではCiliumが動作しています。
そして、CalicoとCiliumで同じリソース定義でも挙動が異なります。
他のサービスや将来の移行を含め、クラスタごとに指定方法が異なるため、あらかじめ構成を検証することが必要です。
iptablesを置き換える機能
従来のベアメタルなLinuxホストのパケットフィルタリングはiptables
を用いた実装が一般的でしたが、kubernetesでは同様の目的にNetworkPolicyを用いて実装します。
実装にもよりますが、kubernetesの内部ネットワーク機能がiptablesと競合するため、コンテナ内ではiptables
やnftables
を利用できないことも多いでしょう。
無理やり従来のツールを導入すると仮想ネットワークが壊れる可能性があります。
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のフィルタとして機能している
- NetworkPolicyはネームスペース内リソースであり、
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.except
はipBlock.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では制御できないと考えた方が安全です。
Chuma Takahiro