本文の内容は、2022年10月10日にNigel Douglasが投稿したブログ(https://sysdig.com/blog/denial-of-service-kubernetes-calico-falco/)を元に日本語に翻訳・再構成した内容となっております。
DoS(Denial-of-Service) は、マシンやネットワークを停止させ、本来のユーザーがアクセスできないようにするための攻撃なので、Kubernetesは潜在的なターゲットとなります。
分散型サービス拒否(DDoS)の場合、攻撃者は自分たちの活動が追跡できないように、ある種の匿名性を維持しようとします。彼らは、匿名の通信を維持しながら、ターゲットをスキャン、攻撃、または侵害するために、TorとVPNインフラストラクチャーを介してトラフィックをルーティングすることができます。
Kubernetesにおけるサービス拒否の影響を防御するために知っておくべきこと、そしてそれを防ぐためにCalicoなどのクラウドネイティブツールを使用する方法、またはそれを検出するためにFalcoを使用する方法について、読み進めてください。
KubernetesにおけるDoS攻撃の最初の一歩
まず考えられるのは、Kubernetesクラスターへのリクエストが信頼されていないネットワークから来たときに警告を出すことです。オープンソースのFalcoは、このような中継ノードに行われる接続を検出することができます。侵入検知システム(IDS)は、潜在的なDoSインシデントに関連するパターンと動作を管理者に通知するため、素晴らしいスタートとなります。検出のためにTorネットワークを介してトラフィックを中継する単純なコンテナとしてTorProxyを利用することができます。コンテナが実行されると、TOR ネットワークへの接続が開始されます。つまり、Falco のルールをテストするために、プロキシを使用するシステムを設定する必要はないのです。コンテナが起動するとすぐにアラートが出るはずです。
FalcoがTor接続を検出する方法については、記事から引用しています。
torproxyを実行します:
docker run -it --name torproxy -p 8118:8118 -p 9050:9050 -d dperson/torproxy
Falcoの出力を確認します:
journalctl -u falco | grep TOR
出力は以下のような感じになっているはずです:
Warning Detected connection to known Tor Node from pod or host. tor res=-115(EINPROGRESS)
これは良い出発点です。これは、FalcoがTorネットワークからのインバウンド接続を検出することを証明していますが、しかし、DoS Kubernetes攻撃を生成するこれらの接続をブロックすることはありません。
だからこそ、Kubernetes環境内で不要な横方向の動きを確実に防止しながら、クラスター環境への ingress の脅威から別のアプローチを検討する価値があるのです。ここでは、Kubernetes NetworkPoliciesが侵入防御システム(IPS)機能を備えた一種の仮想ファイアウォールとして機能し、KubernetesのDoSを防止する可能性があることを探っていきます。
コンテナネットワークインターフェースプラグイン
Container Network Interface(CNI)プラグインを利用することで、KubernetesのDoSを試みるリスクを軽減することができます。CNIはCloud Native Computing Foundationのプロジェクトで、Linuxコンテナでネットワークインターフェースを設定するための仕様とプラグインを記述するためのライブラリ、および多数のプラグインで構成されています。CNIは、コンテナのネットワーク接続と、コンテナの削除時に割り当てられたリソースを削除することのみに関係しています。ただし、最終的にどのパケットを「DROP」または「ACCEPT」するかを決定するルールは、NetworkPolicyプラグインで定義されます。
Kubernetesでは、以下の例に限らず、さまざまなオープンソースのネットワーキングプラグインを利用することができます。環境によっては、サポートされているプラグインとされていないプラグインがあります:
- Cilium
- Flannel
- Weavenet
- Calico
このブログでは、Project CalicoをCNIとして利用し、Calicoもポリシーエンフォースメントのために実行することにします。
デフォルトでは、Kubernetesは基本的なネットワークプラグインであるkubenetと、限定されたスコープのネットワークポリシープラグインを提供します。この2つのプラグインによってクラスター接続を保護することができますが、DoS攻撃からの保護を目的としているわけではありません。
Kubernetesで提供されるデフォルトのNetworkPolicyとは異なり、Calicoユーザーは複数のネームスペースで動作するワークロード(存在するかどうかに関わらず)に拡張する単一のGlobalNetworkPolicyを作成することができます。これは、潜在的に複数のネットワーク・ネームスペースに対するDoS攻撃を防御する場合に理想的です。その結果、私たちは Calico CNI とその NetworkPolicy の実装を使用して、クラスターとホスト全体で明示的な ‘Accept’ と ‘Drop’ Action を提供しています。
Calico ネットワークポリシーで DoS ミティゲーションルールを定義すると、Calico はその影響を最小限にするために可能な限り効率的に実行します。テストラボ環境にCalicoをインストールし、横移動によるDoS攻撃を防止するためのサンプルポリシーをご案内します。
Cloud-Nativeラボの構築
Stage や本番環境内で気軽に CNI プラグインを変更するのは危険です。私たちは、Linuxコンテナ脅威検出ラボを作成し、爆発半径を制限していきます。サンドボックス環境でCalicoをテストしたい場合は、ローカルマシンでMiniKubeまたはMicroK8sのいずれかを実行することができます。私たちの場合、KinDを使用してKubernetesラボを作成しました。
KinDはカスタマイズが豊富なので、CNIやネットワークポリシーは内蔵のものに頼らず、Calicoなどの代替ネットワークコンポーネントを自由にインストールすることができました:
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.12.0/kind-darwin-amd64
chmod +x ./kind
次に、既存のCNIプラグインを明示的に無効にするシンプルなYAMLファイルの作成に進みます:
設定が完了したら、Networking (CNI) プラグインなしでKinDクラスターを作成することができます:
./kind create cluster --config kind-calico.yaml
クラスタが立ち上がったら、kube-systemネームスペースのPodを確認し、kindnetが削除されたことを確認します:
kubectl get pods -n kube-system
kindnetがPodの一覧から消えているはずです。
注:corednsのPodはpending状態になっています。これは予想通りです! CNIプラグインがなければ、CoreDNSは機能しないはずです。
これらのPodは、CNIプラグインがインストールされるまでpending状態のままです。
Calicoのインストール
1. Calico Operatorをインストールします。これでCalico用のCRD(Custom Resource Definition)が作成されます:kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.24.0/manifests/tigera-operator.yaml
クラスターでCalicoを動作させるために必要な残りのカスタムリソースをインストールします:
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.24.0/manifests/custom-resources.yaml
すべてのPodが ‘calico-system’ ネームスペースで実行されていることを確認します。
kubectl get pods -n calico-system -w
各PodのSTATUSがRunningになるまで待ちます。
予想通り、CNIインストール後にそれらのcoredns podsがRunningの状態になりました。
XDPにCalicoを使用する
とはいえ、パケット処理パイプラインの中でパケットが最も早くドロップされるポイントは、LinuxカーネルのバージョンとNICドライバやNICハードウェアの性能に依存します。ありがたいことに、Calico は自動的に最速のオプションを使用します。このブログ記事では、攻撃を受けているときに素早く接続を切断するために、Calicoポリシーの中でDoS軽減ルールを定義します。Calicoでは、 extended Berkeley Packet Filter (eBPF) と eXpress Data Path (XDP)を利用することができ、利用可能な場合はハードウェアオフロードも利用できます。
事前の設定がないため、ここでのベストプラクティスは、クラスターに出入りするトラフィックを識別するためのHostEndpointリソース、ホストエンドポイントに出入りできるトラフィックにルールを適用するためのGlobalNetworkPolicy、Kubernetesクラスターと通信可能な不要な外部ネットワークを定義するためのGlobalNetworkSetをプロアク ティブに構築することにあります。
このいずれかを行う前に、以下のカスタムリソースを記述しておくと良いでしょう:
- HostEndpoints:ホストエンドポイントリソースは、Calicoを実行しているホストに接続されている1つまたは複数の実インターフェースまたは仮想インターフェースを表します。これは、これらのインターフェイスを通じてホストのデフォルトネットワークネームスペースに出入りするトラフィックに対して、Calico ポリシーを適用するものです。これにより、ホストレベルで宣言的なクラウドネイティブの検出とレスポンスを実現することができます。
- GlobalNetworkPolicy:グローバルネットワークポリシーリソースは、ラベルセレクターに一致するエンドポイントのコレクションに適用され、順序付けられたルールのセットを表します。ネットワークネームスペースごとにのみスコープされるKubernetesネットワークポリシーとは異なり、GlobalNetworkPolicyは、すべてのネームスペース内のワークロードエンドポイントリソースと、ホストエンドポイントリソースに適用されます。
私たちの場合、それを使用して Linux ホスト通信を保護し、拡張された Kubernetes 脅威検出を提供できます。
- GlobalNetworkSet:グローバルネットワークセットリソースは、IPサブネットワーク/CIDRの任意のセットを表し、Calicoポリシーでマッチングさせることができます。ネットワークセットは、外部の非Calicoネットワークから来る(または行く)トラフィックにポリシーを適用するのに便利です。DoS攻撃があった場合、Deny-ListしたいCIDRをグローバルネットワークセットに追加するだけで、迅速に対応することができます。GlobalNetworkSetsを使用して、C2ボットネットブロックリストやTorインフラクチャーをサブスクライブし、匿名化された攻撃に伴う爆発半径を制限するようにします。
1. HostEndpointリソース
まず、DoS軽減ルールを適用したいネットワークインターフェイスに対応するHostEndpointリソースを作成します。以下の例では、ノード ‘kind-control-plane’上のIP ‘172.18.0.2’を持つ ‘eth0‘ というネットワークインターフェースをHostEndpointで確保します:apiVersion: projectcalico.org/v3 kind: HostEndpoint metadata: name: hep-for-control-plane labels: node-ddos-protected: "true" spec: interfaceName: eth0 node: kind-control-plane expectedIPs: ["172.18.0.2"]
HostEndpointはapply-dos-mitigation: “true”としてラベル付けされています。
再掲:HostEndpointsの仕様
- interfaceName: * またはポリシーを適用する特定のインターフェースの名前のいずれか。interfaceNameを持つホストエンドポイントは、ホストのすべてのインターフェイスを表します。* を持つホストエンドポイントは、ホストのすべての実インターフェースまたは仮想インターフェースを表します。または、interfaceNameを空にして、インターフェイスのIPの一つをexpectedIPsに含めます。
- node: HostEndpoint が存在するノードの名前 (下の画像にあるように)。
- expectedIPs: ホスト/ノードのインターフェイスに関連する予想されるIPアドレス。
2. GlobalNetworkSetリソース
Calico GlobalNetworkSetを作成し、拒否するIPのCIDR範囲をリストアップします。Command & Control (C2)サーバーに関連する既知の不良IPを参照し、NetworkPolicyでブロックすることができます。スクリーンショット: ddos-block-listと書かれたddos-block-list: “true”と表示されている
Abuse.chによるFeodoTrackerの無料、脅威インテリジェンスフィードの一例です。
このフィードは毎日更新されています。
DDoSの観点からは、インターネット上で人気のある匿名化ネットワークであるTorの通信をブロックすることができます。ポリシー用のNetworkSetにリストからIPを追加してブロックします。
しかし、攻撃者の匿名化を完全に解除することは不可能です。そこで、インターネット上のすべてのTor exit IPs を追跡して、Torインフラクチャーを使用する攻撃者を特定するために、Tor exit IPs フィードが登場しました。
Falcoを使用して異常な振る舞いを検出する
Tor Bulk Exitフィードは、Torネットワークで使用されているインターネット上の利用可能なTor exitノードをリストアップします。このフィードは隔月で更新されるため、ネットワークセキュリティチームは年に数回NetworkSetに変更を加えるだけで、列挙の段階で早期に検出することができます。不要なDNSトラフィックに対するアラート
TORネットワークのIPアドレスへの接続が確立されないように監視し、計画していることも特筆すべき点です。しかし、Falcoは、予期しないFQDN(Fully Qualified Domain Name)に対して接続が試みられた場合に、管理者に通知することもできます。以下の例では、信頼できるドメイン名のリスト(sysdig.com、github.com、google.com)を定義しています。これらのドメイン名のいずれかによって解決されないIPアドレスへのネットワーク接続は、ポリシーをトリガーします。
- list: trusted_domains items: [sysdig.com, github.com, google.com] - rule: Unexpected outbound network connection desc: Detect outbound connections with destinations not on allowed list condition: > outbound and not (fd.sip.name in (trusted_domains)) output: Unexpected Outbound Connection (container=%container.name command=%proc.cmdline procpname=%proc.pname connection=%fd.name servername=%fd.sip.name serverip=%fd.sip type=%fd.type typechar=%fd.typechar fdlocal=%fd.lip fdremote=%fd.rip) priority: NOTICE
これらの新しいフィルターチェックは、ドメイン名を指定するとSysdigがIPアドレスを解決し、解決したIPアドレスをインテリジェントに維持することを可能にします。
つまり、(上記のNetworkSetsのように)信頼性の低いネットワークのIPアドレスを解決し、それを最新に保つという管理だけに頼ることなく、簡単にFalcoのドメイン名を渡して、外部サービスへの不当な接続に警告できるようになったのです。Torの場合は、隔月でフィードを更新すればよいので、これでよいのです。しかし、マルウェアC2サーバーのIPフィードを定期的に更新する場合、NetworkSetsの管理が大変になることがあります。
無料でアクセスできる代替フィードは、Abuse.chによるURLHausです。上記の FQDN の allow リストと同様に、Falco のルールでこれらの URL を bad ドメインとして明示的にリストアップすることができます。
3. GlobalNetworkPolicyリソース
最後に、Calico GlobalNetworkPolicy を作成し、GlobalNetworkSet ラベル (前のステップの dos-deny-list) をセレクターとして追加し、イングレストラフィックを拒否します。ホストへの転送トラフィックの拒否をパケットレベルでより迅速に実施するには、doNotTrack および applyOnForward オプションを使用します。Calico グローバルネットワークポリシーのオプションである doNotTrack: true は、接続追跡の前にポリシーのルールを適用し、これらのルールで許可されたパケットは追跡されないようにすることを示します。
最後に、doNotTrack ポリシーが動作するように applyOnForward: true 式を追加します。HEPを選択するポリシーでfalseに設定すると、ポリシーはホスト上で発生または終了するトラフィックにのみ適用されます:
cat << EOF | kubectl apply -f - apiVersion: projectcalico.org/v3 kind: GlobalNetworkPolicy metadata: name: dos-mitigation spec: selector: apply-dos-mitigation == 'true' doNotTrack: true applyOnForward: true types: - Ingress ingress: - action: Deny source: selector: dos-deny-list == 'true' EOF
GlobalNetworkPolicy は、ラベル dos-deny-list: “true” を使用してソースからのトラフィックを拒否しています。 これにより、Linux パケット処理パイプラインの早い段階で、通常のネットワーク ポリシー ルールの前にポリシーを適用でき、ポリシー順序フィールドとは無関係になります。 doNotTrack ポリシーを要約すると、Egress ルールは、トラフィックの送信先に関係なく、ホスト エンドポイントを介してすべての受信トラフィックに適用されます。
Egress ルールはホスト エンドポイントから送信されるトラフィックにのみ適用されるため、ポッドなどのローカル ワークロードには適用されないことに注意してください。
FalcoとCalicoでeBPFを活用する
Falcoは、Linuxカーネルのコア部分であるeBPFを利用するためにエージェントも適応させました。つまり、Falcoはユーザーランドでの活動だけでなく、カーネルスペースのイベントも監視できるはずです。CalicoがXDP経由でパケットをドロップすれば、これらのeBPFプログラム経由で処理されたシステムコールの数など、低ボリュームのデータを観測できるはずです。
eBPFプログラムは,静的なトレースポイント,動的なKernelやUserのプローブ,その他多くのフッキングポイントにアタッチすることによって,カーネル内の様々な実行ポイントで実行することができるため観測やトレースに理想的です。
CalicoネットワークにおけるXDPの場合、BPFのプログラムはカーネルやシステムサービス、コンテナを再起動することなく、トラフィックを遮断することなくアトミックに更新することが可能です。さらに、BPFマップを介した更新でもプログラムの状態を維持できるため、更新や再起動によるシステムのダウンタイムが少なく、安定性を確保できます。
まとめ
eXpress Data Path (XDP) は、BPFアプリケーションの中で高速なパケット処理を可能にします。XDPはネットワーク操作に対するレスポンスを高速化することで、 通常はネットワークインタフェースでパケットを受信すると同時にBPFプログラムを実行します。このように、XDP プログラムは、ネットワーク・インタフェースに接続された時点で、 受信したパケットに対して XDP_DROP を実行することが可能です。XDP_DROPに馴染みのない方は、この操作はパケットをドロップして処理しないので、Linuxカーネルがフラッディングされるのを防ぐことができます。eBPFプログラムはトラフィックパターンを分析し、フィルタを使用してXDPアプリケーションをリアルタイムで更新し、特定の種類のパケット(例えば、悪意のあるddosトラフィック)をドロップすることができます。
そのため、Podから発信されるネットワーク接続を追跡することは依然として必要です。残念ながら、Calicoのネットワーク・ポリシーでは、どのPodが内部または外部リソースへの接続を開こうとしたのかを簡単に確認することは困難です。
Falcoはシステムコールを活用したシンタックスによる行動監視なので、ファイルを開く、ルートになる、ネットワーク接続を行うなど、あらゆることに対してルールを書くことができます。Kubernetesのワークロードがどのポートとプロトコルで通信することになっているのか(例えばElasticsearchのアウトバウンドTCPトラフィックはポート…)が分かっていれば、アプリケーションの期待されるポート/プロトコルから外れたポート番号経由の予期せぬ横の動きに警告するFalcoのルールを作成することができます、以下にFalcoのドキュメントページからの例を挙げます:
- macro: outbound condition: syscall.type=connect and evt.dir=< and (fd.typechar=4 or fd.typechar=6) - macro: elasticsearch_cluster_port condition: fd.sport=9300 - rule: elasticsearch_unexpected_network_outbound desc: outbound network traffic from elasticsearch on a port other than the standard ports condition: user.name = elasticsearch and outbound and not elasticsearch_cluster_port output: "Outbound network traffic from Elasticsearch on unexpected port (connection=%fd.name)" priority: WARNING
FalcoやCalicoのようなプロジェクトは、強固なセキュリティ態勢を構築する上で、個々に優れています。
Falcoは、クラウドネイティブ環境における侵害の兆候を検出しますが、ネットワーク層でのDoS攻撃を防ぐことはできません。同様に、Project Calicoは、ホスト・インターフェースのNetworkPoliciesを介して、パケット処理パイプラインの最も早い時点で悪意のあるパケットを落とすことができますが、アクティブなインシデント対応アプローチに必要なフォレンジックを提供することはできません。
Kubernetesに完全なセキュリティソリューションを提供するためには、両方のオープンソースツールを使用する必要があります。
Sysdigは、強固なCloud Detection & Response(CDR)基盤には、オープンソースの基盤が不可欠であると考えています。
CI/CDパイプラインで悪意のあるイメージをスキャンしてブロックし、規制遵守の報告に必要なフォレンジックログを提供でき、将来起こりうるDoSインシデントを防止するネットワーク可視性を備えた真のCDRソリューションについては、Sysdig Secureの無料トライアルを今すぐお試しください。