Network Policy

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

Kubernetesセキュリティ

Network Policy とは

Network Policy は、Kubernetes で Pod 間のネットワーク通信をホワイトリスト方式で制御するリソースである。デフォルトでは 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 解決を許可
        - namespaceSelector: {}
      ports:
        - port: 53
          protocol: UDP

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

  • 受信 (Ingress): frontend Pod からの 8080/TCP のみ許可
  • 送信 (Egress): database Pod への 5432/TCP と DNS (53/UDP) のみ許可

よくある落とし穴

DNS の Egress 許可忘れ

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

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"]

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 CNI ⚠️ v1.14+ で対応 EKS のデフォルト。以前は非対応で Calico の追加が必要だった
Flannel ❌ 非対応 Network Policy を使うなら Calico に移行が必要

段階的な導入戦略

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

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

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

関連用語