Cilium Cilium

ネットワークポリシーを書く:L3/L4 から L7 ルールまで

Kubernetes はすべての Pod が他のすべての Pod に到達できる状態から始まります。CiliumNetworkPolicy はそれを絞り込む手段で、必要なら HTTP メソッドまで制限できます。

12 min learn.level.中級

デフォルトでは、Kubernetes のネットワーキングに制限はなく、どの Pod もクラスター内の他のどの Pod にも、どのポートでも到達できます。マルチテナントや、「内部はすべて信頼する」以上のセキュリティ要件があるクラスターでは、このデフォルトは通常、適切ではありません。CiliumNetworkPolicy は、単純な許可リストから、実際の HTTP リクエストを検査するルールまで、それを絞り込む手段です。

出発点:すべてが開いている

何かを変更する前に、デフォルトの状態を確認します。

kubectl run client --image=curlimages/curl --command -- sleep infinity
kubectl exec client -- curl -s http://some-other-service.default.svc.cluster.local

ポリシーがない場合、client が何であれ、some-other-service が何をするものであれ、このリクエストは成功します。いずれかのポリシーが、ある方向(ingress または egress)について Pod を選択すると、その方向の Pod のトラフィックはデフォルト拒否になり、ポリシーが明示的に許可したものだけが通過します。どのポリシーにも選択されていない Pod は、完全に開いたままです。これは最初のポリシーを書く前に理解すべき最も重要な点です。範囲を狭く絞りすぎたポリシーは、それが選択するすべての Pod について、意図していないトラフィックを黙って遮断してしまう可能性があります。

L3/L4:アイデンティティとポートで制限する

最も一般的なポリシーの形は、IP アドレスではなく Cilium のラベルベースのアイデンティティ(このシリーズの Cilium が eBPF をどう使うかのガイドで説明)を使って、どの Pod がどの Pod に、どのポートで到達できるかを制限します。

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-frontend-to-api
  namespace: default
spec:
  endpointSelector:
    matchLabels:
      app: api
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: frontend
      toPorts:
        - ports:
            - port: "8080"
              protocol: TCP

読み方は次のとおりです。これは app: api ラベルの Pod(endpointSelector)に適用され、app: frontend ラベルの Pod からの、TCP ポート 8080 のみへの受信トラフィック(ingress)を許可します。このポリシーが存在することで ingress がデフォルト拒否になるため、他のすべての Pod と他のすべてのポートは、api Pod に対して拒否されます。

egress も同様に、逆方向で機能する

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: api-egress-to-database
  namespace: default
spec:
  endpointSelector:
    matchLabels:
      app: api
  egress:
    - toEndpoints:
        - matchLabels:
            app: database
      toPorts:
        - ports:
            - port: "5432"
              protocol: TCP

api Pod は、ポート 5432 の database Pod に対してのみ、外向きの接続を開始できるようになります。ingress ルールと egress ルールは、同じポリシー内に組み合わせても、分けておいても構いません。環境に合わせて読みやすいほうを選んでください。機能的には、同じ Pod に対して endpointSelector が一致する別々のポリシーも、正しく組み合わされます。

クラスター外へ、またはクラスター外からのトラフィックを許可する

fromEndpoints/toEndpoints は、ラベルで Pod に一致します。クラスターの Pod ネットワークの外にあるものへ、またはそこからのトラフィックには、代わりに DNS ベースや CIDR ベースのルールを使います。

  egress:
    - toFQDNs:
        - matchName: "api.external-service.com"
      toPorts:
        - ports:
            - port: "443"
              protocol: TCP

toFQDNs は標準の Kubernetes NetworkPolicy を超える Cilium 固有の拡張機能で、IP アドレスを事前に把握して固定する代わりに、名前付きの外部ドメインへの egress を許可できます。これは、IP を自分で制御できず、予告なく変わる可能性がある外部サービスでは重要です。

L7:実際のリクエストを読むポリシー

ここまではすべて L3/L4 で動作しており、トラフィックの中身は見ずに、アイデンティティとポートだけを扱っています。Cilium はさらに踏み込んで、理解できる L7 プロトコルの内容に基づいて判定できます。最も一般的なのは HTTP です。

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: api-read-only-for-reporting
  namespace: default
spec:
  endpointSelector:
    matchLabels:
      app: api
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: reporting
      toPorts:
        - ports:
            - port: "8080"
              protocol: TCP
          rules:
            http:
              - method: "GET"
                path: "/reports/.*"

これにより、reporting サービスはポート 8080 で api に到達できますが、パスが /reports/.* に一致する GET リクエストに限られます。同じポートへの POST や、リストにないパスへの GET は、L3/L4 ルールだけなら同じ Pod、同じポートで丸ごと許可されていたとしても、拒否されます。これはルールが適用される Pod に対して、Cilium の組み込み Envoy プロキシが適用します。L7 ポリシーには、純粋な L3/L4 の eBPF による適用と比べて、実際のコストがありますが、一般に控えめです。スループットが非常に高いパスで、実際のセキュリティ要件に対して L3/L4 の制限で十分な場合は、この点を念頭に置いてください。

信頼する前にテストする

誤って適用したポリシーは、開いた状態ではなく閉じた状態で失敗し、トラフィックを拒否します。これはより安全な障害モードですが、誤ったトラフィックであれば、それでも障害になります。実際のトラフィックを処理しているものに、新しい制限的なポリシーを適用する前に実行します。

kubectl apply --dry-run=server -f policy.yaml

次に、まず下位の環境に適用し、許可されるべきトラフィックと拒否されるべきトラフィックを生成して、両方が期待どおりに動作することを確認してから、本番を処理するものに同じポリシーを昇格させます。

すべて許可から始めて、意図的に絞り込む

既存のポリシーがないクラスターでの現実的な導入方法は、初日に完全で正しいポリシーセットを書こうとしないことです。まず実際のトラフィックパターンを観察します(このテクノロジーのトップページで説明している Hubble は、まさにこのために作られています)。正当だと観察されたものに一致するポリシーを書き、本番以外の環境にまず適用し、その後にはじめて本番のトラフィックをそれに合わせて絞り込みます。実際に観察したパターンではなく、推測したトラフィックパターンに対して制限的なポリシーを書くことは、障害を引き起こす一般的な原因です。Cilium の問題のように見えても、実際には、誰も記載することを思いつかなかった正当なパターンを考慮していなかったポリシーなのです。

人気のガイド