公開日
2022年11月21日

スッキリ、繋げて、コンテナセキュリティを得意分野に! #4 コンテナ間通信の制御・ネットワーク概要

このシリーズでは、コンテナセキュリティの重要だけど分かりづらいと思われる部分を中心に扱います。
お忙しい皆さんに代わって、あちこちから情報をかき集めて整理していきます。(おそらく皆さんにとっては時短になるはず!)
皆さんの、ここが分からなかった!というモヤモヤをスッキリさせ、点と点を繋げていき、コンテナ分野を『苦手』から『面白い≒得意』にできるようなコンテンツをお届けしていきます。
(面白いと感じられれば、積極的に学習が進む好循環が回って得意になるという寸法)

本シリーズのおすすめの読み方は、根幹となる『コンテナセキュリティで重要な観点』(初回投稿)をおさえて、枝葉(今回以降)のうち、皆さんの気になるものをご確認いただければと思います。

今回は、コンテナ間通信の制御やコンテナネットワークの概要について見ていきます。
コンテナが侵害された際の挙動のひとつとして、他コンテナへ横展開(ラテラルムーブメント)での攻撃拡大が想定されます。
「コンテナは隔離空間で動く」と言っていますが、コンテナ間の通信は可能なのか?制御は可能か?
そもそもコンテナのネットワークってどうなっている?

ということで今回は、コンテナのネットワーク周りに触れていこうと思います。
(このブログではKubernetes(以下、K8sとも呼称)におけるネットワークについて扱います。)

1.今回の結論をはじめに

まず、今回の結論をまとめました。(※ブログ作成時点Kubernetes v1.24までの情報をもとに記載しております)
出てくる用語も一通り、このブログ内で解説していくので、まずは「ふーん」と眺めるだけでも大丈夫です。

Pod間の通信は可能なのか?に対するアンサー:
Kubernetesクラスタ内において、通常、Namespaceを超えてPod間の通信が可能(デフォルトでは制限なし)

制御する方法は以下の通り
Pod間の通信を制御する方法

・KubernetesのNetworkPolicyリソースによる制御(利用可否はCNI(Container Network Ineterface)に依存)(今回の範囲)
・CNI独自の機能・応用による制御(PodへのAWSのセキュリティグループ適用など)(今回は割愛)
・別の機構による制御(3rd Party製品の機能など)(今回は割愛)

その他のコンテナ通信の制御方法

・コンテナと外部との通信の制御(コンテナ⇔外部の通信の仕組みは今回の範囲)
・サービスメッシュによるL7での制御(今回は割愛)

結論として、KubernetesではPod間で通信が可能になっており、Pod侵害時の横展開・攻撃拡大が起こりやすい状態です。
そのため、NetworkPolicyなどによってPod間通信の制御を実施して、攻撃拡大を防ぐことがセキュリティの観点では重要になります。


以下、上記詳細の解説やK8sのネットワークについて、ざっくり理解できるようにまとめました。

2.Kubernetes関連用語のおさらい

Kubernetesは、コンテナの展開、スケーリング、管理などを実施するオーケストレーションツールです。
様々な機能の提供があり、それに伴って関連用語がたくさん出てきます。
今回は、Kubernetesについて、以降の説明に必要な最低限のおさらいをします。(ほんとうに最小限)

Kubernetes Master/Nodes
Master(Control Plane):管理系コンポーネントを集約したホスト群
Node:実際のコンテナが稼働するコンテナホスト群
Kubernetesはこれら2種類のホスト群で構成される分散システムです。
KubernetesのMaster/Nodeで構成される一連の環境はクラスタという単位で扱われます。

Kubernetes コンポーネント
Master/Node上で動く様々なコンポーネントが存在する
API Serverコンポーネントを中心に複数のコンポーネントが相互作用してKubernetesシステムを構成している(下図の通り)
※ユーザからのCLI操作(kubectlコマンド)によるKubernetes APIの実行をAPI Serverコンポーネントで待ち受ける。

図:Kubernetesコンポーネント(公式Kubernetesドキュメントより)

図:Kubernetesコンポーネント(公式Kubernetesドキュメントより)

③Kubernetes リソース/オブジェクト:
リソース:Kubernetes上で構築されるオブジェクトの概念。
オブジェクト:実際にリソースがデプロイされて永続化したエンティティ、実体。
※例えばPodは「Kubernetes上でコンテナを扱う最小単位」のリソースであり(概念)、デプロイされたPodはオブジェクト(実体)である。
(リソースがクラス、オブジェクトがインスタンスのようなもの、と言えばピンとくる人もいるかも)

Kubernetes APIによってオブジェクトの操作(作成、削除など)がなされる。
※kubectlコマンドやyaml形式/JSON形式によるマニフェストファイルで定義したものを展開することでオブジェクトをクラスタに生成。

オブジェクトには、リソース固有の名前、クラスタ全体で一意のUID、ユーザによる一意でない識別子としてのラベルなどがある。
※ラベルはキーとバリューのペアで、例として"environment":"dev" など任意にユーザが定義可能。

リソースにも様々な種類が存在します(すごく、たくさんある・・・)

画像:コミュニティによるKubernetesのアイコン(Readme)のキャプチャ

Kubernetes コントローラ
何かしらのリソースを監視して必要に応じてリソースの追加や削除、修正を依頼。
Controller Managerコンポーネントによってコントローラの実行が管理される。

3.コンテナネットワークの課題と解決にあたって

さて、話はコンテナネットワークに戻って、まず、コンテナの特性から伺えるネットワーク的な課題を見ていきます。
コンテナは、ホスト上の隔離された空間でアプリケーションを実行させる仮想化技術です。

【課題】
コンテナ(アプリ)がコンテナ外部と通信をさせたい
【解決にあたって】
⇒コンテナ用にネットワーク名前空間を確保(コンテナ自身でIPアドレスやルーティング情報を持てるようにする)
⇒コンテナに仮想NICおよびIPアドレスを付与
(仮想ネットワーク上で利用できるIPレンジのアドレスを持つ)
⇒仮想スイッチなどでコンテナのNICとホストのNICを紐付ける(コンテナがホストを超えて通信をするために利用)

【課題】
コンテナはエフェメラル(短命)なので、IPアドレスがコロコロ変わってしまう
【解決にあたって】
⇒仮想NICに割り振るIPアドレス管理の仕組みが必要

【課題】
コンテナがホストを意識せずに疎通を可能にしたい
【解決にあたって】
⇒ホストを透過的にコンテナ間で通信するためのネットワークの仕組みが重要(オーバレイネットワークなど)

【課題】
コンテナをイミュータブル(不変)にするためには、IPアドレスの指定でなく、コンテナ名やサービス名などで指定したい
【解決にあたって】
⇒サービスディスカバリの仕組みが必要(DNSなど)

これらの課題と解決にあたって必要なことをKubernetesでどのように解決しているか、続いてみていきます。

4.Kubernetes標準のネットワーク

Kubernetes標準のネットワークを見ていくにあたり、以下①~⑨のように、たくさんの要素に触れる必要があります。
実際、こちらをベースに5章の話や、今回詳細は触れないサービスメッシュに繋がっていくので、ここが基礎部分となります。

①Kubernetes標準のネットワークにおけるトラフィックの流れ
②3つのネットワーク(外部(Node Network)、内部(Pod Network、Service Network))
③3種類のServiceリソース(ClusterIP、NodePort、LoadBalancer)とIngressリソース
④kube-proxyコンポーネントとiptables
⑤CNIの役割(Kubernetes内外を繋ぐネットワークの仕組み作り、Podへの仮想NICおよびIPアドレスの付与)
⑥クラウドプロバイダとの関連
⑦ClusterとNamespaceリソース
⑧(おまけ)CoreDNSコンポーネント
⑨(おまけ)Pod内の通信

まず、①でこの章で扱うネットワークの全体像をおさえます。(②~⑨で詳しく説明します)

①Kubernetes標準のネットワークにおけるトラフィックの流れ

既存のシステムのように複数ノードに負荷分散をさせるロードバランサ(LB)があるように、Kubernetes環境においても、外部との境界にロードバランサが配置されることがよくあります。
ロードバランサを介した外部からコンテナ(アクセス対象Pod)への通信の流れを見ていきます。

上記の図の通信の流れを解説します。
1. 外部からKubernetesで構成されるシステムへのアクセスが行われる(公開されているLBのアドレス宛)
2. LBが負荷状況などをもとにノードに通信を振り分ける
3. ノードのkube-proxyにより発行された、Serviceオブジェクトが定義したルールに従い、
ホストの通信制御(iptablesなど)が自身の配下にアクセスすべきPodグループがいるか、
Podグループ内の負荷状況を見て別ノードのPodに振り分けるべきかを確認
4. Podグループがノード配下に存在しない、または、別ノードのPodへ通信となった場合、
アクセスすべきPodがいるノードに通信を転送する
5. 転送された通信を受けたノードを経由して、該当のPodへ通信が届く

大きく、Kubernetes外部と内部の2か所で負荷分散の仕組みが確認できましたでしょうか?(2. と3. の箇所)
この流れを作るための仕組みを、以下②~⑧で解説していきます。

②3つのネットワーク(外部(Node Network)、内部(Pod Network、Service Network))

Kubernetesにおいては、次の3つのネットワークが大きく存在します。

・外部ネットワーク(Node Network
・内部ネットワーク(Pod Network、Service Network

Node Networkは、Kubernetesのノードが接続される外部ネットワークとなります。
コンテナホストのNICが接続するネットワークで、クラウド環境ではVPCなどのネットワークを指します。

Pod Networkは、Podが接続するKubernetes内部の仮想ネットワークとなります。
PodはKubernetesにおいてコンテナの最小単位となり、Pod間の通信はPod Networkにおいて可能になります。
コンテナホストを超えてPod間が通信を透過的に行うためには、オーバレイネットワークの仕組みが必要です。

Service Networkは、ClusterIPなどのServiceリソース間の通信で使うためのネットワークです。
Serviceリソースを利用することでPod宛トラフィックのロードバランシングやサービスディスカバリなどが可能となります。
Pod(コンテナ)は揮発性の高いものなので、それらをServiceとして扱うことで柔軟性が増します。

③3種類のServiceリソース(ClusterIP、NodePort、LoadBalancer)とIngressリソース

複数のPod(Podグループ)に対して柔軟にアクセスを管理する仕組みとして、ここでは3つのServiceリソースを扱います。 また、併せて、ややこしいIngressリソースについても扱います。
ClusterIP
Podグループ宛の通信をKubernetesクラスタ内でロードバランシングするリソース
ClusterIPのIPアドレス(Service Network)と配下のPodグループ(Pod Network)の各PodのIPアドレスの対応付けを行う

NodePort
ノードのIPアドレスにPodグループ宛のポート番号を割り当ててクラスタ外部からアクセス可能にするリソース
ノードのIP+ポート番号(30000番~)(Node Network)で外部からの通信を待ち受ける
外部から単一ノードのIPアドレスの公開はあまり現実的でないため、LoadBalancerリソースの裏側で使われるのが通例

LoadBalancer
Kubernetesクラスタ外部のロードバランサを使用して、クラスタ外部からのアクセスを可能にするリソース。
Kubernetesクラスタ外部のロードバランサが、LoadBalancerリソースを作成することで割り当てられる。
ロードバランスされる先はNodePortリソース(Node Network)であることが一般的。

上記3種類のServiceリソースで基本的な外部とのコンテナ通信が可能となります。

別のロードバランシングを提供するリソースとしてIngressを紹介します。
Ingress
L7ロードバランシングを提供するリソース(上記のServiceリソースはL4ロードバランシングを提供)
Ingressは実装によってアーキテクチャに種類がある ← このあたりがややこしさの要因かも
(L7負荷分散ではパスルーティングを行うが)バックエンドはNodePortリソースを通る
※パスルーティングの例:「https://xxxxx.com/path1」と「https://xxxxx.com/path2」で異なるPodグループに割り当てる等
⇒ /path1:Service1(Podグループ1)⇒NodePort1、/path2:Service2(Podグループ2)⇒NodePort2

④kube-proxyコンポーネントとiptables

ここでは、kube-proxyコンポーネントとiptables、また、それらの代替案となっているものを併せて紹介します。
kube-proxy
Kubernetes Nodeの各ホストで動作するコンポーネント。
Serviceリソースが作られた際に、ClusterIPやNodePort宛のトラフィックがPodに転送されるようにする。
転送方式としてiptables(デフォルト)/ ipvsのモードがある。

iptables
Linuxの機能でファイアウォールやNAT・トラフィックのフォワーディング機能などを搭載。
Kubernetesにおいて通信を実際に転送させる仕組みとして、もともとあるLinuxの技術が採用されている形。
Kubernetesにおいて、kube-proxyコンポーネントによりServiceオブジェクトのルールに従い、iptablesに経路情報が設定される。
ロードバランシングを行う用途で作られたものでないため、Podのスケール時にパフォーマンス低下

これらについては、代替案として、ネットワークのレイテンシを抑えるなどを目的として、そもそもkube-proxyコンポーネントに頼らないOVN-KubernetesやeBPFを活用したケース(CNI)も出てきています(詳細は割愛)

CNIの役割(Kubernetes内外を繋ぐネットワークの仕組み作り、Podへの仮想NICおよびIPアドレスの付与)

CNI(Container Network Interface)は、Kubernetesにおけるネットワーク機能を抽象化してインタフェース仕様として切り出したもの。
つまり、CNIプラグインが選択できるようになり、CNIプラグインによって、環境に合わせたネットワーク実装が可能になります。

CNIの主な役割は以下の通りです。
・Kubernetes内外を繋ぐネットワークの仕組み作り
⇒ Kubernetesの内部ネットワーク(ホストを超えた透過的なPod間通信)の実現(オーバレイ、経路制御、アンダーレイなど(詳細は割愛))
⇒ Kubernetesの内部と外部ネットワークの疎通性の確保。
・Podへの仮想NICの付与
・Kubernetes内部ネットワークで利用するIPアドレスの管理
⇒ Podの仮想NICへのIPアドレス割り当て・IPアドレス管理。(IP address Management、IPAM)
CNIプラグインにはたくさんの種類があります。環境や用途に応じて選択が可能です。

画像:CNCF(Cloud Native Computing Foundation)Cloud Native Interactive Landscapeよりキャプチャ

Flannel
VXLANによるL2ベースのオーバレイネットワークを実現
Calico
BGPによるL3ベースの経路制御を用いたネットワーキングの実現
Cillium
eBPFを利用した高パフォーマンスなネットワーク通信を実現

最近ではCalicoもeBPFモードを利用可能になっているため、選択時にはどれがマッチしているか最新情報を見直してみてください。
また、クラウド環境においては、各クラウドベンダが用意しているCNIを使うことが最も効率的です。
その場合、クラウドベンダのCNIが何をベースにしているか/選択できるかという点も重要です。
例えば、Amazon VPC CNI pluginでは、Amazon VPCで管理しているクラウド上のIPアドレスなども参照できる等。

⑥クラウドプロバイダとの関連

各パブリッククラウドではKubernetesマネージドサービスを提供しています。
AWSではAmazon EKS(Amazon Elastic Kubernetes Service)。
Amazon EKSにおいて、Kubernetes Nodeの実装がAmazon EC2(Amazon Elastic Compute Cloud)であったり、LoadBalancerリソースによって作成・割り当てられる外部ロードバランサがELB(Elastic Load Balancing)であったり、AWSクラウド上のリソースを使うことになります。
こうしたKubernetesにより使用されるクラウド上のリソースの作成・管理は、KubernetesのCloud Controller Managerコンポーネントによって可能としています。
Cloud Controller Managerがプラグイン機構を用いて、異なるクラウドプロバイダとK8sとを結合させています。

図:Kubernetesコンポーネント(公式Kubernetesドキュメントより)

図:Kubernetesコンポーネント(公式Kubernetesドキュメントより)(赤枠部分がCloud Controller Managerとクラウドプロバイダとの接点)

ClusterとNamespaceリソース

Namespace
Kubernetesクラスタを仮想的に分離することができるリソース。
初期状態で3つが存在(kube-system / kube-public / default)。
自分で作成することも可能。
リソースのクォータ設定(使用量の制限)や認可を行うRBAC(Role Based Access Control)などの単位に利用可能。
コンテナにおいて名前空間(Namespace)があるので、少しややこしい。
クラスタ内において、NamespaceをまたいでPod間の通信が可能。

(おまけ)CoreDNSコンポーネント

今回の話の中ではメインで取り扱いませんが、サービスディスカバリの仕組みのひとつとして、Kubernetes内部で利用可能なDNSサービスを紹介します。
CoreDNS
Kubernetesにおいて、クラスタ内部の名前解決やサービスディスカバリに利用されるコンポーネント。
Kubernetesコンポーネントとしてアドオンの立ち位置だが、この役割をするコンポーネントはほぼ必須。
例えばあるServiceに対して「 [Service名].[Namespace名].svc.cluster.local 」の指定でアクセスできるようになる。
同一Namespace内であれば、Service名でのアクセスも可能。
Pod生成時にCoreDNSでクラスタ内部の通信の名前解決するように設定がなされる。

(おまけ)Pod内の通信

KubernetesにおいてPodがWorkloads系リソースの最小単位となります。
基本的に『1Pod 1コンテナ』ですが、1Podの中に複数のコンテナを内包するケースもあります。
その場合の、Pod内のコンテナ間通信は、localhost宛で通信することで互いに通信が可能です。
コンテナごとでなく、Pod内でネットワーク名前空間が共有され、Pod単位でIPアドレスが割り当てられるためです。
(ネットワークだけでなく、Pod内のコンテナはデータ領域なども共有されます。)

以上が、コンテナ標準のネットワークの仕組みの概要的な部分でした。たくさんの用語・技術が出てきましたね。
実際、それらの技術がどのように動いているかまで、取り扱おうとするとさらに膨大になるので、今回はあくまでも概念的にふんわりと理解いただければと思います。

5.コンテナネイティブ・ロードバランシング

さて、4章で触れたKubernetes標準のネットワークには、実は課題がありました。

外部のロードバランサからPodへの通信があった際に、無駄なホップが発生する可能性がある⇒遅延や無駄な帯域消費
原因:外部のロードバランサがKubernetesクラスタ内部ネットワークを把握できていないため。

本来はこうしたい。。。

それを解消する方法として、コンテナネイティブのロードバランシングが生まれました。

外部のロードバランサからPodへの通信を、直接該当のPodに届けるための仕組み
Q: どうやって?
A: Kubernetesクラスタ内部ネットワークの範囲を、クラスタ外部で管理&参照させるようにできれば実現できそう
⇒CNIがその役割に貢献

コンテナネイティブ・ロードバランシングのAWSにおける実装例を以下に挙げます。
下図では、ロードバランサに入ってきた通信が、該当するPodグループに対して直接、負荷分散してトラフィックを転送します。

図:EKS Best Practice Guideより

上記を実現する仕組みは以下の通りです。
AWS VPC CNI pluginを使うことで、Amazon VPCの持つCIDRブロックを用いてKubernetesクラスタ内部ネットワーク用(Service NetworkとPod Networkの範囲)サブネットを用意
⇒クラスタ外部でIP管理。

②AWS VPC CNIの持つIPAMがPodに割り当てるIPアドレスを、EC2のENI(Elastic Network Interface)のセカンダリアドレスプールに割り当て
⇒コンテナホストのEC2のENIで、ホスト上で稼働しているPodのIPアドレス群を管理、クラスタ外部でPodのNW情報を参照可能に。
※ENIではセカンダリアドレスプールに複数のIPアドレスを登録可能

AWS ALB(Application Load Balancer)またはAWS NLB(Network Load Balancer)のIPモードの利用により、
上記のアドレスを参照して直接Podに通信可能
⇒AWS Load Balancer Controllerという拡張モジュールをEKSにデプロイすることで実現
※EKSにおいてIngressリソースを作成するとき、ALBがプロビジョニングされる

ここでのトラフィックの流れは、ALB/NLB→Target Group→ENI (Pod IP)→Podという流れになります。

他の一部のクラウドプロバイダにおいても同じような仕組みを取ることで、コンテナネイティブロードバランシングを実現しています。

6.コンテナ間通信の制御&まとめ

さて、ここまでで、K8s標準のネットワークとコンテナに特化した負荷分散のネットワークの仕組みを見てきました。
最後に、改めて、1章でお伝えした結論をおさらい&補足します。

Pod間の通信は可能なのか?に対するアンサー:
Kubernetesクラスタ内において、通常、Namespaceを超えてPod間の通信が可能(デフォルトでは制限なし)制御する方法は以下の通り

Pod間の通信を制御する方法

KubernetesのNetworkPolicyリソースによる制御(利用可否はCNI(Container Network Ineterface)に依存)(今回の範囲
・CNI独自の機能・応用による制御(PodへのAWSのセキュリティグループ適用など)(今回は割愛)
・別の機構による制御(3rd Party製品の機能など)(今回は割愛)

その他のコンテナ通信の制御方法

・コンテナと外部との通信の制御(コンテナ⇔外部の通信の仕組みは今回の範囲
・サービスメッシュによるL7での制御(今回は割愛)

NetworkPolicy
Kubernetesクラスタ内部ネットワークにおいて、ラベルやNamespaceなどによりPod間の通信を制御することができるリソース。
NetworkPolicyリソースが利用できるかはCNIに依存(Flannelでは不可、Calicoでは可能など)
NetworkPolicyはNamespaceごとに作成する必要がある。

以上のように、Network Policyにより、コンテナ間通信の制御が可能です。

結論として、KubernetesではPod間で通信が可能になっており、Pod侵害時の横展開・攻撃拡大が起こりやすい状態です。
そのため、NetworkPolicyなどによってPod間通信の制御を実施して、攻撃拡大を防ぐことがセキュリティの観点では重要になります。

一方で、クラスタ外部のネットワークについてもきちんと制御をかけることが必要となります。
他にも、そもそも同一クラスタ内で全く異なる用途のコンテナ群を稼働させない、正規の通信先が侵害されている場合の考慮、認証認可、通信の暗号化やアクセスログの取得・分析など、ネットワーク周りで様々な考慮点があります。
Kubernetesにおいてネットワークセキュリティ周りのチェックポイントは、公式のSecurity Checklist(日本語版が無い…)でも確認できます。

また、感染経路となる口(不必要な外部公開や脆弱性など)が無いか、出口対策として何か対処できないかなど、全体感の意識を忘れずに、多層防御の観点でセキュリティ対策を検討いただければと思います。

弊社では、お客様のクラウドネットワークの入口・出口対策として、Trend Micro Cloud One - Network Security™を提供しております。
Network Securityにより、外部からコンテナ環境への脆弱性を突いた通信を防ぎ、また、侵害コンテナによる外部C2サーバとの不正通信を捉えます。
また、侵害されたコンテナによる攻撃拡大の動作を捉える対策として、Trend Micro Cloud One - Container Security™を提供しております。
Container SecurityのRuntime Security機能により、コンテナの不審な挙動(Pod内からのK8sリソース探索など)を検出して環境を保護します。

主な参考情報
Kubernetesドキュメント

AWS EKS Best Practice Guides
CNCF Cloud Native Interactive Landscape

本ブログシリーズでは、コンテナセキュリティについて、捉えづらい部分をスッキリ、理解の点と点を繋げて、全体像を捉えられるようにすることをテーマとしています。
皆さんがコンテナ分野を『苦手』から『面白い≒得意』にできるようなコンテンツをお届けしていきます!
※本ブログの内容はエンジニア個人の見解であり、弊社全体としての見解ではない点をご了承ください。

ブログシリーズ『スッキリ、繋げて、コンテナセキュリティを得意分野に!』

また、弊社ではコンテナ領域を含むクラウド向けセキュリティ対策製品群としてTrend Micro Cloud One™を提供しています。

30日間の無料トライアルもご用意しておりますので、以下も併せてご参照の上、ぜひ体験いただければと思います。

トレンドマイクロ株式会社

セキュリティエキスパート本部 セールスエンジニアリング部
サーバセキュリティチーム ソリューションアーキテクト

野村 達広

お問い合わせ一覧

Copyright © 2024 Trend Micro Incorporated. All rights reserved.