Skip to main content

Kubernetesネットワークポリシーのベストプラクティス

著者

Peter De Tender

Kubernetes Blog

2022年12月21日

0 分で読めます

Kubernetes Pod内でコンテナ化されたワークロードのトラフィックを制御・フィルタリングすることは、従来型のネットワーク環境におけるファイアウォールと同様に重要です。このシナリオでは、そうした機能をKubernetes NetworkPolicy APIが提供します。

この記事では、ネットワークポリシーの例を作成し、主要なパラメーターを確認しながら、Kubernetes NetworkPolicyについて解説します。次に、一般的なNetworkPolicyのユースケースを取り上げ、kubectlを使った監視方法を紹介します。最後に、サードパーティ製のKubernetes拡張機能を使ってContainer Network Interface(CNI)を実装する方法を見ていきます。

Kubernetesネットワークポリシーをためらわずに導入すべき理由

Kubernetes環境の運用において、ネットワークポリシーの導入は不可欠です。ネットワークポリシーを設定していない場合、クラスター内のすべてのPodはデフォルトで相互に通信できます。そのため、Podに機密情報を保管するバックエンドデータベースなどの機密データが含まれる場合は、特定のフロントエンドPodだけが接続できるようにする必要があります。

また、開発環境のPodと本番環境で実行されているPodの間のネットワークトラフィックを分離することもできます。ネットワークポリシーがなければ、ネットワーク内のあらゆる場所との間で、すべてのトラフィックが自由に流れます。

幸い、Kubernetes NetworkPolicyの設定は、意図したとおりにネットワークトラフィックを流すための、シンプルで効果的かつ包括的な方法です。

Kubernetesネットワークポリシーの定義

サンプルのNetworkPolicyを見てみましょう。WordPressのフロントエンドとMySQLのバックエンドを備え、Webサービスとデータベースサービスの両方を含むPod群をKubernetesのdefaultネームスペースにデプロイした、サンプルワークロードを考えます。企業のセキュリティプロトコルでは、特定のワークロードのネットワークトラフィックを分離し、必要最小限の受信・送信トラフィックのみを許可することが求められています。

この方針には、次の条件が含まれます。

  • すべてのトラフィックを許可するKubernetesのデフォルト動作をブロックする。

  • defaultネームスペース内でwordpressラベルが付いたPod同士のみが通信できるようにする。

  • パブリックインターネットおよび172.16.0.0のIP範囲から、ポート80/443への受信(ingress)接続を許可する。

  • wordpressラベルが付いたPodだけが、ポート3306でMySQLデータベースのPodに接続できるようにする。

  • Kubernetes DNSサービス(ポート53)への接続は常に許可する。

  • クラスター外へのすべての送信接続をブロックする。

以下のネットワーク図は、これらのルールの構成例を示しています。

KubernetesのnamespaceにおけるデフォルトのIngressおよびEgress拒否ポリシーを示す図。ポート80、443への通信とDNSトラフィックは許可されています。

この例では、ネットワークポリシーを複数のポリシー定義ファイルに分けることも、すべてを1つのYAMLマニフェストファイルにまとめることもできます。ワークロードが1つ(webapp)なので、ルールベースの定義ファイルを1つにまとめるのが適切です。ただし、この例には複数の受信接続と送信接続があるため、クラスター内の接続ごとに個別の設定ファイルを作成する方法もあります。

ここからは、上記の設定に使われているいくつかのパラメーターを取り上げ、設定との関係やネットワークトラフィックへの影響を確認します。

APIとメタデータ

以下のYAMLファイルの1行目では、ネットワーキングAPI(networking.k8s.io)とそのバージョン(v1)を指定しています。また、YAMLファイルの種類をNetworkPolicyと定義し、ネットワークポリシーを設定することをKubernetes APIコントローラーに伝えます。metadataセクションのnameとnamespaceには、このルールセットの名前と関連付けるネームスペースを指定します。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: sample-network-policy
  namespace: default

YAMLファイルの次の部分にはspecsセクションがあり、ネットワークポリシーを適用するフィルターを指定できます。

以下の部分には、重要なパラメーターがいくつか含まれています。

  • podSelector — 指定したトラフィックポリシーの適用対象となるPodを指定します。この例ではmatchLabelsパラメーターを使い、app: wordpressのラベルが付いたすべてのPodにネットワークポリシーを適用します。その結果、このポリシーはそれ以外のすべてのPodには適用されません。

  • policyTypes — IngressとEgressの2種類があります。

  • Ingress — Pod、ネームスペース、Podグループへのすべての受信トラフィックを定義します。

  • Egress — Pod、ネームスペース、Podグループへのすべての送信トラフィックを定義します。

spec:
  podSelector:
    matchLabels:
      app: wordpress
  policyTypes:
    - Egress
    - Ingress

次に、ネットワークポリシーのingressセクションで、許可する受信トラフィックの種類を定義します。以下の設定では、次の送信元からポート443と80への受信を許可します。

  • wordpressラベルが付いたすべてのPod

  • パブリックインターネットからのすべてのトラフィック(cidr: 0.0.0.0/0)

  • 172.16.0.0/16の範囲内にあるすべてのIPアドレス。社内のIP範囲(VPN、VLAN、サブネットなど)を表す場合があります。

上記のトラフィックを許可するYAMLスニペットは、次のようになります。

  ingress:
    - from:
      - podSelector:
          matchLabels:
            app: wordpress
      ports:
        - port: 443
        - port: 80  
    - from:
      - ipBlock:
          cidr: 172.16.0.0/16
      ports:
        - port: 443
        - port: 80
    - from:
      - ipBlock:
          cidr: 0.0.0.0/0
      ports:
        - port: 443
        - port: 80

最後に、送信トラフィックのルールを定義するegressセクションを見てみましょう。webappラベルが付いたPodからポート1433(SQL)と53(DNS)へのすべての送信通信を許可します。

webappラベルを指定することで、他のPodがSQL Serverインスタンスと通信できなくなり、関連するセキュリティリスクを排除できます。同様に、この設定では、ポート53を使ったクラスター内のすべてのPodへの接続を許可します。

このポリシー定義には、もう1つ重要なポイントがあります。ネットワークポリシーを導入してPod間の接続を制御する場合、許可・拒否の設定を両方向で行う必要があります。バックエンドへの受信トラフィックを許可せずに、フロントエンドからの送信トラフィックだけを許可すると、通信できなくなります。

この部分のトラフィックを定義するYAMLスニペットは、次のとおりです。

  egress: 
    - to:
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - port: 53
          protocol: UDP

    - to:
        - podSelector:
            matchLabels:
              app: wordpress
      ports:
        - port: 3306

Kubernetesネットワークポリシーの適用

サンプルのYAML NetworkPolicyマニフェストが完成しました。次のようになります。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: sample-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: webapp
  policyTypes:
    - Egress
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: webapp
      ports:
        - port: 443
        - port: 80
    - from:
        - podSelector: {}
    - from:
        - ipBlock:
            cidr: 172.16.0.0/16
      ports:
        - port: 443
        - port: 80
    - from:
        - ipBlock:
            cidr: 0.0.0.0/0
      ports:
        - port: 443
        - port: 80
  egress:
    - to:
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - port: 53
          protocol: UDP
    - to:
        - podSelector: {}
    - to:
        - podSelector:
            matchLabels:
              app: webapp
      ports:
        - port: 443
        - port: 80

次に、このファイルをKubernetesクラスターに適用します。まず、ファイルをsample-network-policy.yamlとして保存します。

次に、他の多くのKubernetes設定と同様に、kubectlコマンドラインインターフェース(CLI)を使って定義ファイルを適用します。

次のコマンドを実行します。

kubectl apply -f sample-network-policy.yaml
サンプルの Kubernetes ネットワークポリシーを作成するために kubectl apply を実行しているターミナル

Kubernetesネットワークポリシーの検証と監視

従来型のファイアウォール管理と同様に、Kubernetesネットワークポリシーの検証と監視には運用上の監督が欠かせません。既存のネットワークルールが関連するワークロードに引き続き適用されるか、定期的に見直す必要があります。

また、トラフィックの問題をトラブルシューティングしたり、異なるネットワークポリシー間の競合を調査したりするために、ルールベースを検証する必要が生じることもあります。幸い、kubectl CLIを使ってNetworkPolicyを検証できます。次のコマンドを実行すると、現在のネットワークポリシーを分析・監視できます。

kubectl describe networkpolicy <networkpolicy name as listed in the YAML manifest>

以下は、ingressポリシータイプの出力例です。

「イングレス通信を許可」が強調表示され、ポート443と80のルールが示されたKubernetes NetworkPolicyのターミナル出力。

また、この画像はegressポリシータイプの出力例を示しています。

kube-dnsおよびWebアプリのPodへの許可された送信トラフィックと、EgressおよびIngressのポリシータイプを示すターミナル出力

Kubernetesネットワークポリシーを適用する際のベストプラクティス

他のネットワークセキュリティ設定と同様に、Kubernetesネットワークポリシーでは、次のベストプラクティスに従いましょう。

  • 明示的に許可した通信のみが行われるよう、デフォルトのdeny-allネットワークポリシーを使用する。

  • 相互に通信する必要があるPodを、PodSelectorパラメーターを使ってグループ化する。

  • ネームスペース間の通信は、必要な場合にのみ許可する。

  • Kubernetesクラスター内であっても、不要なネットワーク通信は許可しない。

  • クラスター内のPodが、クラスター外からのネットワークトラフィックを受信できるようにする場合は慎重に判断する。

  • パブリックインターネットへの送信トラフィックを拒否すると、特定のアプリケーションの更新や検証プロセスに支障が出る場合があります。

Kubernetes CNIプラグインでネットワークポリシー管理を最適化

CNIプラグインの利点の1つは、Network Policyの実装の詳細を抽象化できることです。これにより、クラスター管理者は基盤技術の複雑さに煩わされることなく、ニーズに最適なソリューションを選択できます。

ただし、ディストリビューションやプロバイダーが追加していない限り、KubernetesのデフォルトインストールにはCNIプラグインがあらかじめ含まれていません。そのため、ニーズに合ったプラグインを選んでインストールする必要があります。また、ディストリビューションにデフォルトのプラグインが含まれていても、別のプラグインの方が要件に適している場合があります。

多数のCNIプロバイダーがあり、特に広く使われているものには次のようなものがあります。

プラグインごとに独自の機能があるため、ネットワークとネットワークセキュリティの要件に最適なものを判断するには、いくつか試してみる必要があるかもしれません。

まとめ

複雑なルーティング、トラフィックルール、セキュリティインテグレーションを伴うエンタープライズネットワークトポロジーの設定には、手間がかかります。幸い、Kubernetes環境では、従来型インフラストラクチャでファイアウォールが担っていた役割をネットワークポリシーで実現できます。

もちろん、ネットワークポリシーの設定は、定期的な再評価とメンテナンスが必要なプロセスの第一歩にすぎません。組み込みのkubenetプラグインはポリシー管理に一定のネットワーク機能を提供しますが、他のCNIプラグインには、より高度な機能があります。適切なポリシーと管理方法を組み合わせることで、ネットワークトラフィックを安全かつ効率的に保つことができます。

Kubernetesセキュリティに関するその他のリソース

ソースコードの段階からインフラを保護

Snykはワークフロー内のIaCセキュリティとコンプライアンスを自動化し、構成ドリフトや不足しているリソースを検出します。