こんにちは!インフラやセキュリティの世界へようこそ。
初めてKubernetes(K8s)やクラウドネイティブな開発に触れるとき、次から次へと出てくる専門用語に圧倒されてしまいますよね。「Pod?」「マイクロセグメンテーション?」「ラテラルムーブメントって何だか物騒な名前…」と感じるのも無理はありません。
でも、安心してください。セキュリティの根底にある考え方は、私たちが普段暮らしている現実世界の「防犯」と全く同じなんです。
今回は、Kubernetesにおける通信の番人である「Network Policies(ネットワークポリシー)」をテーマに、なぜこれが私たちのシステムを守る最強の盾になるのか、身近な例えを交えながら一歩ずつ優しく紐解いていきましょう!
—
1. 現実世界の防犯に例える「ラテラルムーブメント」と「マイクロセグメンテーション」
まずは、セキュリティ用語の怖そうな名前を日常の風景に翻訳してみますね。
家全体のセキュリティ、本当に安心ですか?
想像してみてください。あなたは一戸建てのマイホームを買いました。
玄関の鍵を頑丈にして、ピッキング対策もバッチリ。「これで泥棒は入れまい!」と安心していますよね。
でも、もし万が一、裏手の小さな窓の鍵が空いていて、泥棒がリビングに侵入してしまったらどうなるでしょうか?
リビングに入れてしまった泥棒が、家の中を自由に歩き回れる状態だったら……寝室にあるタンスの金庫も、子供部屋のプライベートな荷物も、すべて荒らされてしまいますよね。
これが、セキュリティの世界で言う「ラテラルムーブメント(横展開)」です。
外からの侵入を1回許した途端、システムの中を縦横無尽に動き回られて被害が拡大してしまう最悪のシナリオです。
部屋ごとに鍵をかける「マイクロセグメンテーション」
このラテラルムーブメントを防ぐために、現代の防犯ではどう考えるでしょうか?
「リビングから廊下に出るドア」「廊下から寝室に入るドア」のすべてに個別の鍵をかけ、たとえリビングに侵入されても、他の部屋には絶対に移動できないようにしますよね。
この「家の中を細かく区切って(マイクロ)、それぞれの部屋ごとに通行許可証(セグメント)を発行する」という考え方こそが、マイクロセグメンテーションです。
Kubernetesの世界では、この「部屋」が Pod という単位になり、部屋と部屋の間のドアに鍵をかける仕組みが Network Policies というわけです。
—
2. デフォルトのKubernetesは「お隣さんウェルカム」な状態
Kubernetesをインストールした初期状態のままだと、実は家の中のセキュリティはガバガバ(?)です。
標準のKubernetesクラスターでは、どのような状態になっているかというと、
- クラスター内にあるすべての
Podは、他のどのPodから話しかけられても「どうぞどうぞ!」と返事をしてしまいます。 - フロントエンド(Web画面)を担当する
Podから、バックエンドの顧客情報が入ったデータベースPodへも、制限なく直接アクセスできてしまうのです。
もし、Webアプリの脆弱性を突かれてフロントエンドの Pod が乗っ取られたらどうなるでしょうか?
そのまま背後にあるデータベースまで一直線に侵入され、大切なデータがすべて抜き取られてしまいます。これは非常に危険ですよね。
そこで登場するのが、「原則としてすべての通信を禁止し、許可したものだけを通す(ホワイトリスト方式)」というアプローチです。
—
3. Kubernetes Network Policiesでホワイトリストを作ろう
それでは、実際にKubernetesのネットワークポリシーを書いてみましょう!
今回は、「フロントエンドからの通信だけを受け付け、それ以外の怪しいやつからの通信はすべてシャットアウトするデータベースの要塞」を作ってみます。
以下のYAMLファイルを見てください。難しそうに見えますが、日本語のコメントを読めば何をやっているかすぐに分かりますよ。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-security-policy # このネットワークポリシーの名前です
namespace: production # 適用するお部屋(ネームスペース)を指定します
spec:
podSelector:
matchLabels:
app: database # このポリシーを「データベースのPod(app=database)」に対して適用します
policyTypes:
- Ingress # 今回は「入ってくる通信(Ingress)」を制限します
ingress:
- from:
- podSelector:
matchLabels:
app: frontend # 「app=frontend」というラベルを持つPodからの通信だけを許可します
ports:
- protocol: TCP
port: 5432 # データベース(PostgreSQLなど)が使っている通信ポート番号を指定します
この設定がやっていることのまとめ
1. podSelector で、このルールの対象を app: database というラベルの付いたPodに絞り込んでいます。
2. policyTypes: [Ingress] で、データベースに向かって「外から入ってくる通信」をコントロールすると宣言しています。
3. ingress の中身で、「app: frontend というラベルを持つ身分証を持った奴しか通さない!」と定めています。
4. さらに、通信する扉(ポート番号)も 5432 番だけに限定しています。
これによって、たとえ他の全く関係ない部署(例えば app: batch-job など)のPodが乗っ取られたとしても、データベースの部屋の前で「おっと、通行証を持っていませんね」とピシャリと追い返すことができるのです。
—
4. 現場のセキュリティ担当からあなたへ:実務で絶対に外せない注意点
ここまで読んだあなたは、「なんだ、Network Policiesって意外と簡単じゃん!」と思われたかもしれません。その通り、概念自体はとてもシンプルです。
しかし、実際の現場(プロダクション環境)でこれを運用するときには、いくつか泥臭い「ハマりポイント」があります。最後に、先輩エンジニアからのアドバイスをいくつか送りますね。
① CNI(Container Network Interface)プラグインを確認する
実は、Kubernetesの機能単体では、Network Policiesの定義を書いても「ただの紙切れ(無視される設定)」になってしまうことがあります。
実際に通信を遮断・制御するためには、クラスターのネットワークを管理する「CNIプラグイン」がNetwork Policiesをサポートしている必要があります。
- Calico、Cilium、Flannel(一部機能)などが有名ですね。クラスターを構築する際は、必ず「Network Policiesに対応しているCNIか?」を確認するようにしましょう。
② 最初から厳しくしすぎない(段階的な導入)
「じゃあ、今日からすべての通信を遮断するぞ!」と意気込んで全Podに厳しいポリシーを適用すると、アプリが動かなくなって社内チャットが嵐のように荒れることになります(笑)。
最初は Namespace 全体を保護するデフォルト拒否のポリシーを置き、必要な通信を一つずつホワイトリストに追加していく「インクリメンタル(段階的)なアプローチ」をとるのが、現場で嫌われない安全な進め方です。
—
おわりに
セキュリティの世界は、完璧を目指すとキリがありません。しかし、「万が一侵入されたらどうするか」という前提に立ち、被害を最小限に食い止める「防波堤(マイクロセグメンテーション)」を築いておくことは、エンジニアとしての最高の優しさであり、責任でもあります。
Kubernetes Network Policiesは、そのための心強い相棒です。
最初は小さな設定から、ぜひご自身の環境でも試してみてくださいね。一歩ずつ、安全なインフラストラクチャを一緒に作っていきましょう!
コメント