TT Lab
はじめる
学ぶ 学習パス コース

CCA — Cilium認定アソシエイト

ポリシーを追加したのに、なぜアクセスが広がるのか

TT Labで続きを見る

一言でいうと

ポリシーファイルをたくさん作ったからといって、通信がより安全になるわけではありません。どのPodを、どの方向に制限するのか、複数の許可ルールがどのように合わさるのか、名前解決に必要な別の通信が残っているかを、確認する必要があります。このモジュールは、セキュリティ作業のあとに発生した2つの障害を、実際のリクエストとCiliumの観測記録で切り分けます。

なぜ必要なのか

青チームは、社内の注文APIを管理しています。セキュリティ担当者に外部接続を減らしてほしいと言われたため、チームは、クライアントのegressをAPIの8080ポートに制限しました。ポリシーの適用は成功し、API PodもReadyでした。ところが、アプリケーションでは注文が止まりました。API PodのIPに直接リクエストすると応答しますが、Service名でリクエストすると、待たされて終わります。

最初はAPIの障害だと考えて、サーバーを再起動しました。しかし、サーバーを入れ替えても、結果は同じでした。ここで、対照群が重要になります。同じ送信元から、同じサーバーの同じポートへ向かいながら、アドレスを解決する経路だけを変えたとき、結果が分かれました。一度に複数の設定を変えず、この違いがどの依存関係を明らかにしているのかを、まず問う必要があります。

別のチームでは、協力組織にAPIを開くために、許可ポリシーを追加しました。既存のポリシーが依然として残っているので、新しいポリシーは追加の審査条件だと考えました。しかし、2つの許可ポリシーは、2つの出入口になりえます。要件をANDで書いておきながら、実装はORにしてしまったようなものです。セキュリティレビューは、ファイルの数ではなく、誰がどの出入口を通れるのかを確認する仕事です。

どう動くのか

1. APIが表現する意図と、実行主体を分ける

基本のKubernetes NetworkPolicyも、podSelectorとnamespaceSelectorをサポートしています。IPアドレスだけを並べるポリシーではありません。ポリシーの最上位のpodSelectorは保護する対象を、ingressのfromは入ってくる相手を、egressのtoは出ていく相手を選びます。同じpeerの中にnamespaceSelectorとpodSelectorを置くと、両方の条件に合う相手を意味し、別々のリスト項目に分けると、異なる許可経路になります。

実際にパケットを制御するのは、ポリシーをサポートするネットワークプラグインです。このラボでは、Ciliumが標準のNetworkPolicyとCiliumNetworkPolicyの両方を処理します。したがって、APIオブジェクトが保存されたという事実だけを見ず、選択されたエンドポイントと、実際のリクエストの結果も確認します。セレクターの意味の詳細は、Kubernetesの公式説明と照らし合わせてください。

2. 名前が同じクライアントでも、同じアイデンティティではない

Ciliumのidentityは、セキュリティ関連のラベルの集合に対応します。青チームのclientと赤チームのclientが、どちらもrole=clientだとしても、namespace関連のラベルは異なります。数値のIDだけを覚えたり、appラベル1つだけを比較したりしないでください。CEPのidentity.idとidentity.labelsを並べて読み、どの集合を区別しているのかを確認する必要があります。この数字を、アプリケーションの永続的な顧客番号のように保存してもいけません。Ciliumの用語説明が出発点です。

CNPのendpointSelectorは、そのポリシーが属するネームスペースの対象を選択します。別のネームスペースの送信元を許可するには、その境界を明示的に表現する必要があります。このモジュールは、Kubernetesに登録したnamespacedなCNPを使います。直接ポリシーAPIに入れたオブジェクトや、クラスター全体のポリシーまで、同じ範囲に一般化することはしません。ネームスペースの境界の案内もあわせて読んでください。

3. ingressをブロックすることと、egressをブロックすることは違う

この環境のpolicyEnforcementModeはdefaultです。どのポリシーにも選択されていない方向と、制限ルールに選択された方向を、区別する必要があります。サーバーのingressを絞ったからといって、クライアントのegressまで自動的に同じ範囲になるわけではありません。逆に、APIへ出ていく通信を許可したからといって、名前解決サーバーへ出ていく通信まで許可したことにもなりません。

このラボでは、API 8080だけを許可したクライアントと、DNSも許可したクライアントを、別々に残します。前者は、IPへの直接リクエストの成功を維持しながら、名前によるリクエストが失敗し、後者は、2つのリクエストがどちらも成功する必要があります。DNSの復旧には、kube-systemのkube-dnsエンドポイントとUDP/TCP 53を指定します。すべてのegressを開けてエラーをなくすと、課題の範囲を逸脱します。default以外にも、alwaysとnever、enableDefaultDenyとL7の例外もあるので、ここで見た現象を、すべての設定にそのまま当てはめないでください。ポリシーの強制モードで条件を確認します。

4. 許可の和集合と、明示的な拒否を区別する

unionサーバーには、青チームのclientを許可するCNPがあります。ここに、赤チームのclientを許可する標準のNetworkPolicyを追加すると、両方のチームが通過する状態を作れます。新しいポリシーが、既存の許可をさらに絞るフィルターだと読んではいけません。同じPodに適用されたすべての許可経路を、広げて見ます。

denyサーバーには、上と同じ許可経路を置いたうえで、赤チームを明示的に拒否するCNPを追加します。Ciliumの明示的なdenyは、標準のNetworkPolicyを含むallowより優先されます。これは、単に許可ルールがないためにブロックされるdefault-denyとは、別の概念です。この機能で、特定のURLやFQDNをdenyできると、拡大解釈しないでください。明示的な拒否の優先順位と制限を参照します。

対象 青client 青stranger 赤client 比較する理由
baseline 許可 許可 許可 サーバー自体が応答する対照群
native 許可 拒否 拒否 標準NPの同じネームスペースの選択
ingress 許可 拒否 拒否 CNPの送信元の選択
union 許可 拒否 許可 異なるAPIの許可の和集合
deny 許可 拒否 拒否 赤チームのallowより優先されるdeny

この表は、これから構成する分離ラボの目標状態です。初期状態から、正解のポリシーがすべて適用されているという意味ではありません。実際のポリシーを読み、リクエストを送って、目標と異なるマスを絞り込んでいきます。

現場での姿

HTTP 000は、サーバーが送ったステータスコードではありません。curlがHTTP応答コードを得られなかった場合にも表示されます。timeoutだからという理由だけで、ネットワークポリシーのせいだと断定しないでください。サーバーが起動していない、アドレスが間違っている、接続経路の問題も、同じ形で見えることがあります。したがって、サーバーのReady、IPへの直接の対照群、クライアントの位置、ポリシーのspec、Hubbleのverdictを、あわせて見ます。

HubbleのDROPPEDを1行探すだけでは、不十分です。観測バッファには、以前の実験や、別のPodのリクエストもあります。送信元のPodとネームスペース、IP、宛先ポート、固有のsource port、該当の時刻を合わせると、調査の範囲を絞り込めます。CEPのidentityまで照合すれば、同じ名前の別のエンドポイントを混同するリスクも減ります。TCP SYNが転送されたという事実と、HTTP 200を受け取ったという事実も区別します。前者は転送経路の観察であり、後者はアプリケーションの応答です。Hubble CLIの案内のフィルターを使って、自分で範囲を絞り込んでみてください。

実際の事前探査では、22件のリクエストのうち、DNS解決で止まった1件に、TCPフローがありませんでした。これをTCPログの欠落と判定すると、観測器が間違います。そのリクエストは、API接続の前の段階で止まったからです。DNSのUDP 53のドロップと、IPへの直接リクエストの成功を、あわせて見る必要があります。当時のDNSの証拠は、時間帯と送信元Podの比較であり、query IDまで結びつけたパケットの証明ではありませんでした。証拠の範囲を書くことも、障害レポートの一部です。

次のラボですること

用意された分離VMで、まずアイデンティティと対照群を確認します。続いて、標準NPとCNPのセレクター、DNSが抜けたegressと復旧したegress、allowの和集合とdenyの優先順位を、それぞれ別の対象に構成します。ステップが終わっても、以前の比較対象は残しておいてください。最後に、ポリシーと観測結果を突き合わせたインシデントレポートを作成します。

このラボで、わざと開けておくunionとbaselineは、比較のための分離された対象です。そのまま本番環境にコピーしないでください。成果物を保管するには、セッションを終了する前にエクスポートする必要があります。このモジュールの実験は、1つのVM内のCiliumポリシーの動作であり、マルチクラスター接続、BGPルーティング、L7のURL制限までを検証するものではありません。