Network Policy

Kubernetes で Pod 間のネットワーク通信を制御し、不要な通信を遮断するセキュリティ機能

Kubernetesセキュリティ

Network Policy とは

Network Policy は、KubernetesPod 間のネットワーク通信をホワイトリスト方式で制御するリソースである。デフォルトでは Kubernetes クラスター内の全 Pod が相互に通信可能だが、Network Policy を適用すると、明示的に許可された通信のみが可能になる。

これはクラスター内のファイアウォールルールに相当する。従来のネットワークセキュリティが「サーバー間」の通信制御だったのに対し、Network Policy は「Pod 間」という、より細かい粒度で制御できる点が特徴だ。

なぜ必要なのか

Kubernetes のデフォルト設定では、同一クラスター内の全 Pod がフラットなネットワークで接続されている。これは開発の利便性は高いが、セキュリティ上は危険だ。

たとえば、フロントエンド Pod が侵害された場合、攻撃者はそこからデータベース Pod に直接アクセスできてしまう。本来フロントエンドはバックエンド API を経由してのみデータベースにアクセスすべきだが、ネットワークレベルでの制限がなければ、アプリケーションレイヤーの制御を迂回できる。

Network Policy を適用すれば、「フロントエンド → バックエンド API → データベース」という正規の通信経路のみを許可し、「フロントエンド → データベース」の直接通信を遮断できる。

基本的な構文

基本的な構文の例を示す。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes: ["Ingress", "Egress"]
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend
        - namespaceSelector:
            matchLabels:
              env: production
      ports:
        - port: 8080
          protocol: TCP
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: database
      ports:
        - port: 5432
          protocol: TCP
    - to:                          # DNS 解決を許可 (kube-system のみ)
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
      ports:
        - port: 53
          protocol: UDP
        - port: 53
          protocol: TCP

この例では api Pod に対して以下を制御している。

  • 受信 (Ingress): 同じ namespace の frontend Pod、または env: production ラベルを持つ namespace の全 Pod からの 8080/TCP。from の 2 要素は OR で評価されるので、後者はかなり広い許可になる (「frontend だけ」にしたいなら後述の AND 形で書く)
  • 送信 (Egress): database Pod への 5432/TCP と、DNS への 53 番ポートのみ許可
  • ports の番号は宛先 Pod のポートであって Service のポートではない。Service が 80 番で受けて containerPort 8080 に転送する構成なら、ポリシーに書くのは 8080 の側になる

よくある落とし穴

DNS の Egress 許可忘れ

Egress ルールを設定する際、DNS の許可を忘れるケースが非常に多い。Egress を制限した瞬間に Pod が名前解決できなくなり、全ての外部通信が失敗する。Network Policy を初めて導入するチームがほぼ確実にハマるポイントだ。

許可する側にも罠がある。クラスター DNS の Service (kube-dns) は 53/UDP と 53/TCP の両方を公開しており、応答が切り詰められた (TC ビットが立った) 場合、リゾルバは同じ問い合わせを TCP で送り直す。UDP だけ許可していると通常の名前解決は通るのに、応答の大きい問い合わせだけが失敗するという、原因を掴みにくい症状になる。宛先 namespace を絞るときは、コントロールプレーンが全 namespace に自動で付与する変更不可のラベル kubernetes.io/metadata.name を使うと、運用者のラベル付け忘れで壊れない。

podSelector と namespaceSelector の AND/OR

from 配列内の要素は OR 条件だが、1 つの要素内に podSelectornamespaceSelector を並べると AND 条件になる。この挙動は直感に反するため、意図しない許可や拒否が発生しやすい。

# OR: frontend Pod または production namespace の全 Pod
- from:
    - podSelector:
        matchLabels:
          app: frontend
    - namespaceSelector:
        matchLabels:
          env: production

# AND: production namespace 内の frontend Pod のみ
- from:
    - podSelector:
        matchLabels:
          app: frontend
      namespaceSelector:
        matchLabels:
          env: production

デフォルト拒否ポリシーの未設定

Network Policy は「追加」で動作する。Pod に Network Policy が 1 つも適用されていなければ、全通信が許可される。まず全拒否のデフォルトポリシーを適用し、その上で必要な通信を個別に許可する設計が安全だ。

# 全拒否のデフォルトポリシー
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector: {}          # namespace 内の全 Pod に適用
  policyTypes: ["Ingress", "Egress"]

ただし「全拒否」は 2 つの意味で全部ではない。1 つはスコープで、Network Policy は namespace スコープのリソースなので、クラスター全体に一括で効く既定は標準 API には無い。namespace を作るたびに同じポリシーを置く運用が必要になる。もう 1 つは例外で、IP 範囲 (ipBlock) による指定では、Pod が動作しているノードとの通信は、そのノードや Pod の IP に関わらず常に許可される。ノード発の通信はポリシーでは止められない。

CNI プラグインの対応状況

Network Policy は Kubernetes の標準 API だが、実際の通信制御は CNI (Container Network Interface) プラグインが担う。CNI プラグインが Network Policy をサポートしていなければ、リソースを作成しても何も起きない。エラーも出ないため、「設定したのに通信が制限されない」という事態になる。

CNI プラグインNetwork Policy サポート特徴
Calico完全対応L3/L4 制御、GlobalNetworkPolicy で全 namespace 横断
Cilium完全対応 (独自の拡張あり)L7 (HTTP, gRPC) レベルの制御も可能
AWS VPC CNIv1.14.0 以降で対応 (既定は無効)EKS のデフォルト。Kubernetes 1.25 以降が前提で、アドオン設定で機能を有効にして初めて効く。以前は非対応で Calico の追加が必要だった
Flannel非対応Network Policy を使うなら、ポリシーを実装するプラグイン (Calico など) の併用か移行が必要

段階的な導入戦略

本番クラスターに Network Policy を一気に導入すると、想定外の通信が遮断されてサービス障害を引き起こすリスクがある。以下の段階で導入する。

  1. 監査モード: Cilium の Policy Audit Mode や Calico のルール単位の Log アクションで、現在の通信パターンを可視化する
  2. 非本番環境で検証: staging 環境で Network Policy を適用し、アプリケーションの動作を確認する
  3. namespace 単位で段階適用: 影響範囲の小さい namespace から順に本番適用する
  4. 全拒否デフォルトの適用: 全 namespace にデフォルト拒否ポリシーを適用し、ホワイトリスト方式に移行する

基礎から学ぶなら関連書籍が手がかりになる。

この記事は役に立ちましたか?

関連用語

関連する記事