- はじめに
- Kubernetes NetworkPolicyの基本構造
- Calico Network Policyの詳細
- Cilium Network PolicyとeBPF
- CalicoとCiliumの比較分析
- 本番運用ガイド
- 失敗事例と復旧手順
- 運用時の注意点
- おわりに
- 参考資料

はじめに
Kubernetesクラスタはデフォルトで すべてのPod間通信が許可されたflat network として動作する。これは開発の利便性という面では利点だが、セキュリティの観点では致命的な弱点だ。1つのPodが侵害されると、攻撃者は別途のファイアウォールなしにクラスタ内のすべてのサービスへ自由にアクセスできる。これを lateral movement(横方向の移動) 攻撃と呼び、コンテナ環境で最も頻繁に発生するセキュリティインシデントの類型の1つだ。
Red Hatの2024 State of Kubernetes Securityレポートによると、調査対象組織の約90%がコンテナまたはKubernetes環境でセキュリティインシデントを経験 したと回答した。このうち相当数は、ネットワークレベルの隔離がなかったために被害が拡大した事例だった。特にマイクロサービスアーキテクチャではサービス間の通信経路が爆発的に増加するため、従来の境界ベースのセキュリティ(perimeter security)だけでは内部の脅威を遮断できない。
マイクロセグメンテーション(Microsegmentation)はこの問題に対する答えだ。ネットワークをワークロード単位に細分化し、各サービスが明示的に許可された通信のみを行うよう制限する戦略だ。KubernetesではNetworkPolicy APIとCalico、CiliumのようなCNIプラグインを通じてこれを実装する。本記事では、基本的なNetworkPolicyのスペックから始めて、CalicoのGlobalNetworkPolicy、CiliumのL7ポリシーとeBPFベースのenforcementまで、本番環境でZero-Trustネットワークを構築する全体のプロセスを扱う。
Kubernetes NetworkPolicyの基本構造
NetworkPolicy API v1スペックの分析
Kubernetes NetworkPolicyは networking.k8s.io/v1 APIグループに属するネームスペーススコープのリソースだ。Podに対するインバウンド(Ingress)とアウトバウンド(Egress)のトラフィックを制御し、ポリシーが1つでも適用されたPodは そのポリシーに明記されたトラフィックのみが許可される ホワイトリスト方式で動作する。
主な構成要素は以下の通りだ。
- podSelector: ポリシーを適用する対象のPodをlabelで選択する。空のセレクタはネームスペース内のすべてのPodを意味する。
- policyTypes: Ingress、Egress、またはその両方を指定する。省略時はIngressのみが適用され、egressルールがあればEgressも自動的に含まれる。
- ingress/egressルール: 許可するトラフィックの送信元または宛先を定義する。各ルールは
from/to(ピア選択)とports(ポート選択)で構成される。 - ピアセレクタ:
podSelector、namespaceSelector、ipBlockの3つの方式でトラフィックの相手を指定する。
重要な点は、NetworkPolicyが additive(累積式)だということだ。複数のポリシーが同じPodに適用されると、各ポリシーで許可されるトラフィックの和集合が最終的な許可範囲になる。ポリシー間の衝突や優先順位という概念はない。
Default-Denyポリシーによる基本的なセキュリティの確保
Zero-Trustの第一段階は すべてのトラフィックをデフォルトで遮断する ことだ。ネームスペースごとにdefault-denyポリシーを適用したうえで、必要な通信だけを明示的に許可する方式だ。
# default-deny-all.yaml
# ネームスペース内のすべてのIngress/Egressトラフィックを遮断
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
このポリシーを適用すると、production ネームスペースのすべてのPodはインバウンド/アウトバウンドのトラフィックがすべて遮断される。DNSクエリも遮断されるためサービスディスカバリが動作しない。したがってDNSトラフィックを許可するポリシーを必ず一緒に適用しなければならない。
# allow-dns.yaml
# kube-systemネームスペースのDNSサービスへのegressを許可
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
ネームスペース間の通信を許可するポリシー
マイクロサービス環境では、異なるネームスペースのサービス間の通信が必要になる。たとえば frontend ネームスペースのWebサーバーが backend ネームスペースのAPIサーバーにアクセスする必要があるケースをYAMLで定義すると以下の通りだ。
# allow-frontend-to-backend.yaml
# frontendネームスペースからbackend APIサーバーへのIngressを許可
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-api
namespace: backend
spec:
podSelector:
matchLabels:
app: api-server
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: frontend
podSelector:
matchLabels:
app: web
ports:
- protocol: TCP
port: 8080
このポリシーは backend ネームスペースの app: api-server labelを持つPodに対して、frontend ネームスペースの app: web PodからのTCP 8080ポートへのアクセスのみを許可する。namespaceSelector と podSelector を同じ from 項目の中に入れるとAND条件として動作し、別々の from 項目に分けるとOR条件になる点に注意が必要だ。
Calico Network Policyの詳細
Calicoと標準NetworkPolicyの比較
CalicoはKubernetes標準のNetworkPolicy APIを完全にサポートしながら、追加の機能を提供するCNIプラグインだ。主な違いは以下の通りだ。
| 機能 | Kubernetes NetworkPolicy | Calico NetworkPolicy |
|---|---|---|
| ポリシースコープ | ネームスペース単位 | ネームスペース + クラスタ全体(Global) |
| ポリシー順序(Order) | なし(additive) | 明示的なorderフィールドをサポート |
| ポリシーティア(Tier) | なし | 多段のティア階層構造 |
| Denyルール | 明示的なDenyなし | 明示的なDeny actionをサポート |
| Log action | 非対応 | ポリシーマッチ時にロギング可能 |
| Staged Policy | 非対応 | 本番適用前のシミュレーション |
| Host Endpoint | 非対応 | ノードレベルのファイアウォールポリシー |
| FQDN/DNSポリシー | 非対応 | DNS名ベースのegress制御 |
| L7ポリシー | 非対応 | Calico Enterpriseでサポート |
GlobalNetworkPolicyによるクラスタ全体のDefault-Deny
標準のNetworkPolicyはネームスペース単位でしか適用されないため、新しいネームスペースが作成されるたびにdefault-denyポリシーを手動で追加しなければならない。Calicoの GlobalNetworkPolicy はクラスタ全体へ一度に適用され、この問題を解決する。
# calico-global-default-deny.yaml
# クラスタ全体のdefault-deny(kube-systemを除く)
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: default-deny
spec:
tier: default
order: 1000
selector: all()
namespaceSelector: '!kubernetes.io/metadata.name == "kube-system"'
types:
- Ingress
- Egress
このポリシーは kube-system を除くすべてのネームスペースにデフォルトの遮断を適用する。order: 1000 は低い優先順位を意味し、より具体的な許可ポリシーが先に評価される。Calicoでは order の値が低いほど優先順位が高い。
ポリシーティアリング(Tier)アーキテクチャ
Calicoの ティア(Tier) システムは、ポリシーを階層的に管理する強力なメカニズムだ。各ティアは独立したポリシー評価パイプラインを形成し、上位ティアで明示的にAllowまたはDenyされなかったトラフィックは次のティアへ渡される(Pass)。
一般的には次のように3~4個のティアで運用する。
- SecurityOpsティア: セキュリティチームが管理。悪意あるIPの遮断、規制遵守ポリシーなど最優先のルール
- Platformティア: プラットフォームチームが管理。DNSの許可、監視エージェントの通信、共通インフラのポリシー
- Applicationティア: 開発チームが管理。アプリケーションごとのサービス間通信ルール
- Defaultティア: 基本のdefault-denyポリシー
# tier-setup.yaml
# SecurityOpsティアの作成 - セキュリティチーム専用の最優先ポリシー階層
apiVersion: projectcalico.org/v3
kind: Tier
metadata:
name: security-ops
spec:
order: 100
---
# Platformティアの作成 - インフラ共通のポリシー階層
apiVersion: projectcalico.org/v3
kind: Tier
metadata:
name: platform
spec:
order: 200
---
# Applicationティアの作成 - 開発チームのサービスポリシー階層
apiVersion: projectcalico.org/v3
kind: Tier
metadata:
name: application
spec:
order: 300
---
# Platformティア: DNSおよび監視トラフィックを許可するポリシー
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: platform.allow-dns-and-monitoring
spec:
tier: platform
order: 100
selector: all()
types:
- Egress
egress:
# DNSトラフィックを許可
- action: Allow
protocol: UDP
destination:
ports:
- 53
- action: Allow
protocol: TCP
destination:
ports:
- 53
# Prometheusメトリクスの収集を許可
- action: Allow
protocol: TCP
destination:
selector: app == "prometheus"
ports:
- 9090
# 残りのトラフィックは次のティアへ渡す
- action: Pass
この構造の利点は 関心事の分離(Separation of Concerns)だ。セキュリティチームはSecurityOpsティアでコンプライアンスポリシーを、プラットフォームチームはPlatformティアでインフラポリシーを、開発チームはApplicationティアでサービスごとのポリシーを、それぞれ独立して管理できる。
Staged Policyによる安全な本番ロールアウト
新しいネットワークポリシーを本番へそのまま適用すると、予期しないサービス停止が発生しうる。Calicoの Staged Policy はポリシーを実際には適用せずシミュレーションモードで実行し、どのトラフィックが影響を受けるかを事前に確認できるようにしてくれる。
Staged Policyはリソースタイプを StagedGlobalNetworkPolicy または StagedNetworkPolicy に変更すればよい。該当するポリシーはトラフィックを実際に遮断したり許可したりしないが、Calicoのログに、このトラフィックがポリシーにマッチしたという記録を生成する。
本番ロールアウトの手順は以下の通りだ。
StagedGlobalNetworkPolicyとしてポリシーをデプロイ- Calico Enterpriseまたはログで影響を分析(最低24~48時間)
- 想定外の遮断トラフィックがないことを確認
- リソースタイプを
GlobalNetworkPolicyへ変更して実際に適用 - 適用後の監視と、異常時の即時ロールバック
Cilium Network PolicyとeBPF
Cilium CiliumNetworkPolicy CRD
CiliumはeBPF(extended Berkeley Packet Filter)技術をベースにした高性能なCNIプラグインだ。標準のKubernetes NetworkPolicyをサポートしながら、CiliumNetworkPolicy と CiliumClusterwideNetworkPolicy のCRDを通じてL3/L4/L7レベルの細かなポリシーを定義できる。
Ciliumの最大の差別化要素は eBPFベースのデータプレーン だ。従来のiptablesベースの実装とは異なり、eBPFプログラムがカーネルレベルでパケットを処理するため、ポリシールールの数が増えても性能低下がほとんどない。iptablesはルールが線形のチェーンとして評価されるためルール数に比例して遅延が増加するが、eBPFはハッシュマップベースの参照でO(1)に近い性能を維持する。
L3/L4/L7ポリシーのEnforcementアーキテクチャ
Ciliumのポリシーは3つのレイヤーで動作する。
- L3 (Network Layer): IPアドレス、CIDR、Kubernetes labelベースのトラフィック制御
- L4 (Transport Layer): TCP/UDPポートベースの制御
- L7 (Application Layer): HTTPメソッド/パス、gRPCサービス、Kafkaトピック、DNSドメインなどアプリケーションプロトコルレベルの制御
L7ポリシーはCiliumが内蔵するEnvoyプロキシを通じて処理される。これにより「特定のPodはGET /api/v1/usersリクエストのみを許可し、POST /api/v1/adminリクエストは遮断する」といった細かな制御が可能になる。
# cilium-l7-http-policy.yaml
# L7 HTTPポリシー: APIサーバーへのメソッド/パスベースのアクセス制御
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: api-server-l7-policy
namespace: backend
spec:
endpointSelector:
matchLabels:
app: api-server
ingress:
- fromEndpoints:
- matchLabels:
app: web-frontend
toPorts:
- ports:
- port: '8080'
protocol: TCP
rules:
http:
# ユーザー照会APIのみ許可
- method: GET
path: '/api/v1/users.*'
# ユーザー作成APIを許可
- method: POST
path: '/api/v1/users'
# ヘルスチェックエンドポイントを許可
- method: GET
path: '/healthz'
- fromEndpoints:
- matchLabels:
app: admin-dashboard
toPorts:
- ports:
- port: '8080'
protocol: TCP
rules:
http:
# 管理者ダッシュボードはすべてのメソッドを許可
- method: '.*'
path: '/api/v1/.*'
このポリシーは web-frontend からはユーザー関連の読み取り/書き込みAPIとヘルスチェックのみを許可し、admin-dashboard からはすべてのAPIエンドポイントへアクセスできるように設定する。L7ポリシー違反時にはHTTP 403レスポンスが返され、Hubbleを通じて遮断されたリクエストの詳細情報を確認できる。
DNSベースのFQDNポリシーによる外部アクセス制御
本番環境では、Podが外部API(決済ゲートウェイ、サードパーティサービスなど)にアクセスしなければならない場合が多い。IPベースのegressポリシーは外部サービスのIPが変更されると壊れるという問題がある。Ciliumの FQDNベースのポリシー はDNS名で外部アクセスを制御し、この問題を解決する。
# cilium-fqdn-egress-policy.yaml
# DNSベースのegressポリシー: 許可された外部ドメインのみアクセス可能
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: payment-service-egress
namespace: production
spec:
endpointSelector:
matchLabels:
app: payment-service
egress:
# DNSクエリを許可(FQDNポリシーの動作に必須)
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: '53'
protocol: ANY
rules:
dns:
- matchPattern: '*'
# 決済ゲートウェイAPIのみ許可
- toFQDNs:
- matchName: api.stripe.com
- matchName: api.paypal.com
toPorts:
- ports:
- port: '443'
protocol: TCP
# 内部データベースへのアクセスを許可
- toEndpoints:
- matchLabels:
app: postgresql
role: primary
toPorts:
- ports:
- port: '5432'
protocol: TCP
このポリシーは payment-service Podが外部へ出るトラフィックを、api.stripe.com と api.paypal.com の443ポート、そして内部PostgreSQLデータベースの5432ポートのみに制限する。DNSクエリを許可するルールが必ず含まれていなければFQDNポリシーは正常に動作しない。CiliumはDNSレスポンスを傍受してドメインに対するIPマッピングを学習し、以後そのIPへのトラフィックのみを許可する。
Identity-Basedセキュリティモデル
Ciliumのセキュリティモデルは、従来のIPベースのファイアウォールとは根本的に異なる。各Podまたはエンドポイントに セキュリティ識別子(Security Identity)を付与し、パケットの送信元IPではなく識別子をもとにポリシーを評価する。
このアプローチの利点は以下の通りだ。
- Podの再起動やスケーリング時にもポリシーが即時適用される: IPが変更されてもlabelベースのidentityは維持される。
- ポリシー評価性能の向上: IP範囲のマッチングの代わりにidentityのハッシュ参照でO(1)の性能を達成する。
- クラスタメッシュ環境のサポート: マルチクラスタ環境でもidentityが伝播され、一貫したポリシー適用が可能だ。
CalicoとCiliumの比較分析
詳細比較表
両ソリューションの主な違いを次の表にまとめる。
| 比較項目 | Calico | Cilium |
|---|---|---|
| データプレーン | iptables(デフォルト)/ eBPF(オプション) | eBPF(デフォルト) |
| L3/L4ポリシー | 完全サポート | 完全サポート |
| L7ポリシー | Enterprise版でサポート | オープンソースで標準サポート |
| FQDNポリシー | サポート(DNS Policy) | サポート(toFQDNs) |
| ポリシーティア | サポート(Tier CRD) | 非対応(単一階層) |
| Globalポリシー | GlobalNetworkPolicy | CiliumClusterwideNetworkPolicy |
| Staged Policy | サポート | 非対応(policy-audit-modeで代替) |
| 観測性(Observability) | Calico Enterprise Flow Logs | Hubble(オープンソース、標準内蔵) |
| サービスメッシュ | 別途の構成が必要 | Cilium Service Meshを内蔵 |
| マルチクラスタ | Calico Federation | Cluster Mesh |
| 暗号化 | WireGuard | WireGuard / IPsec |
| 性能(大規模ポリシー) | iptables時はルール数に比例した遅延 | eBPFハッシュマップでO(1)参照 |
| 成熟度 | 非常に高い(2016~) | 高い(2018~) |
| 学習曲線 | 普通 | 高い(eBPFの概念理解が必要) |
選択基準と運用環境ごとの推奨
Calicoを選択すべきケース
- すでにiptablesベースのネットワーキングに慣れている運用チーム
- ポリシーティアリングによるマルチチームのポリシー管理が必要な大規模組織
- Staged Policyによる安全な本番ロールアウトが重要な金融/医療環境
- BGPベースのネットワーク統合が必要なオンプレミス環境
- 既存のCalicoクラスタから段階的にeBPFへ移行しようとする場合
Ciliumを選択すべきケース
- L7レベルの細かなポリシー制御が必要なAPIゲートウェイ環境
- Hubbleによるネットワーク観測性が重要なDevSecOps組織
- 大規模なポリシー(数千個以上)を運用し、eBPFの性能が必要な環境
- サービスメッシュをサイドカーなしで実装したい場合
- Kubernetes Gateway APIとの統合が重要な最新アーキテクチャ
実務では両ソリューションとも本番での検証が十分に行われているため、チームの技術スタックと運用要件に応じて選択すればよい。重要なのは どのソリューションを選んでもdefault-denyポリシーを必ず適用すること であり、ポリシー変更時に影響分析のプロセスを備えることだ。
本番運用ガイド
Zero-Trustネットワーク実装チェックリスト
本番環境でZero-Trustネットワークを実装する際は、次のチェックリストを順に進める。
- ネームスペースのラベリング標準化: すべてのネームスペースとPodに一貫したlabel体系を適用する。
app、env、team、tierなどの標準labelを定義する。 - 現在のトラフィックパターンの分析: HubbleやCalico Flow Logsで既存の通信パターンを最低1週間収集する。
- Default-Denyポリシーの適用: まずaudit/stagedモードで適用し、影響分析のうえenforcementモードへ切り替える。
- DNSおよび必須インフラ通信の許可: kube-dns、監視エージェント、ログ収集器などインフラサービスへのegressを許可する。
- サービスごとの許可ポリシーの作成: 収集したトラフィックパターンをもとに、各サービスに必要な最小限の通信だけを許可するポリシーを作成する。
- ポリシーのテストと検証: CI/CDパイプラインでポリシーのlintとシミュレーションを自動化する。
- 段階的なロールアウト: 開発環境 - ステージング環境 - 本番カナリア - 本番全体の順に適用する。
- 継続的なモニタリング: ポリシー違反、遮断されたトラフィック、新しい通信パターンをリアルタイムで監視する。
ポリシーのテストとシミュレーション戦略
ネットワークポリシーを本番に適用する前には必ずテストしなければならない。次の3つのレベルのテストを推奨する。
第1段階: 静的解析(Static Analysis)
kubectl とポリシーのlintツールを使ってYAML構文エラーやセレクタの誤りを検証する。kube-linter や conftest で組織のポリシー標準への準拠可否も自動で検証できる。
第2段階: シミュレーション(Dry-Run)
CalicoのStaged PolicyまたはCiliumの policy-audit-mode を使用する。Ciliumでは次のようにエージェント設定で監査モードを有効化できる。
# cilium-config.yaml
# Ciliumエージェント設定: ポリシー監査モードの有効化
apiVersion: v1
kind: ConfigMap
metadata:
name: cilium-config
namespace: kube-system
data:
enable-policy: 'default'
policy-audit-mode: 'true'
monitor-aggregation: 'medium'
hubble-metrics-server: ':9965'
hubble-metrics: 'dns,drop,tcp,flow,port-distribution,icmp,httpV2'
監査モードでは、ポリシー違反のトラフィックが遮断されず、代わりにHubbleのログに action: audit イベントが記録される。これを分析してポリシーの正確性を確認したうえで監査モードを解除すればよい。
第3段階: 統合テスト(Integration Test)
実環境と同一構成のテストクラスタで、サービス間の通信が正常に行われるかE2Eテストを実施する。curl、netcat、nmap などのツールを使って許可と遮断の可否を具体的に検証する。
HubbleとCalico Enterpriseによるポリシー監視
Hubble (Cilium)
HubbleはCiliumに内蔵された観測性プラットフォームで、ネットワークフローをリアルタイムで可視化する。hubble observe コマンドでポリシーによって遮断または許可されたトラフィックを確認できる。
主な監視指標は以下の通りだ。
hubble_flows_processed_total: 処理された総フロー数hubble_drop_total: ポリシーによって遮断されたパケット数hubble_policy_verdict: ポリシー評価の結果(allowed/denied/audited)cilium_policy_endpoint_enforcement_status: エンドポイントごとのポリシー適用状態
Calico Enterprise Flow Logs
Calico Enterpriseは、すべての許可/遮断トラフィックに対する詳細なフローログを提供する。ElasticsearchやSplunkへ送信してダッシュボードを構成でき、ポリシー変更前後のトラフィックパターンの変化を比較分析するのに有用だ。
トラブルシューティング: ポリシー未適用と通信遮断のデバッグ
本番でよく発生するネットワークポリシーの問題とデバッグ方法を整理する。
問題1: ポリシーを適用したのにトラフィックが遮断されない
- CNIプラグインがNetworkPolicyをサポートしているか確認する。FlannelはデフォルトではNetworkPolicyをサポートしない。
kubectl get networkpolicy -Aでポリシーが正しいネームスペースにあるか確認する。podSelectorが対象Podのlabelと正確に一致するか検証する。
問題2: 正常なトラフィックが遮断される
- default-deny適用後に必要な許可ポリシーが漏れていないか確認する。
namespaceSelectorとpodSelectorのAND/OR条件の適用を確認する。- DNS egressの許可が漏れるとサービスディスカバリが失敗するため、必ず確認する。
問題3: 断続的な通信障害
- Podが再起動して新しいIPが割り当てられる際に、ポリシー反映の遅延が発生することがある。
- Ciliumの場合は
cilium endpoint listでendpointのポリシー状態を確認する。 - Calicoの場合は
calicoctl get workloadendpointでエンドポイントのマッピングを確認する。
失敗事例と復旧手順
事例1: Default-Denyなしで運用してLateral Movement攻撃を受けたケース
状況: あるEコマースプラットフォームで、公開Webサービスの脆弱性を通じて攻撃者が1つのPodに侵入した。ネットワークポリシーがまったく適用されていなかったため、攻撃者はRedisキャッシュ、内部APIサーバー、さらにはデータベースまで自由にアクセスし、顧客データを流出させた。
原因分析:
- すべてのネームスペースにNetworkPolicyがないdefault-allow状態
- データベースが別のネットワークセグメントなしに同じクラスタで運用されていた
- Pod Security Standardも未適用でコンテナエスケープが可能だった
復旧と改善:
- ただちに侵害されたPodを隔離し、影響を受けたサービスを再デプロイ
- 全ネームスペースにdefault-denyポリシーを段階的に適用
- データベースへのアクセスは
app: api-serverlabelを持つPodからのみ許可 - 外部egressは明示的に許可されたドメインのみ可能になるようFQDNポリシーを適用
- 定期的なネットワークスキャンによる未許可の通信経路の検出を自動化
事例2: 誤ったポリシー順序によるサービス障害
状況: セキュリティチームがCalicoのティアに新しい遮断ポリシーを追加したが、orderの値を誤って設定したため、PlatformティアのDNS許可ポリシーより高い優先順位で適用された。その結果、クラスタ全体でDNSクエリが失敗し、すべてのサービス間通信が停止した。
原因分析:
- SecurityOpsティアの新しいポリシーのorderが、PlatformティアのDNS許可ポリシーより低い値(高い優先順位)だった
- 該当ポリシーがすべてのUDP 53トラフィックをDenyとして処理していた
- Staged Policyを経ずに直接本番へ適用した
復旧手順:
calicoctl delete gnpコマンドで問題のポリシーを即座に削除- DNSサービスの正常化を確認(約30秒以内に復旧)
- ポリシーを
StagedGlobalNetworkPolicyとして書き直しシミュレーションを実施 - ポリシーのorder値の体系を文書化: SecurityOps(100~199)、Platform(200~299)、Application(300~399)
- ティア間のorder値の衝突を防ぐためのCI/CD検証ゲートを追加
教訓: DNS、kube-apiserver、監視など中核インフラの通信は最上位ティアで保護すべきであり、新しい遮断ポリシーは必ずStagedモードを経なければならない。
ロールバック戦略
ネットワークポリシーによる障害が発生した際は、迅速なロールバックが必須だ。次の3つのレベルのロールバックを準備しておく。
- 個別ポリシーのロールバック: 特定のポリシーだけを以前のバージョンへ戻す。GitOpsで管理している場合はgit revert後に自動で同期される。
- ネームスペース単位のロールバック: 該当ネームスペースのすべてのNetworkPolicyを削除してdefault-allow状態に復元する。サービス復旧後にポリシーを順次再適用する。
- クラスタ単位の緊急ロールバック: すべてのNetworkPolicyとCalico/Ciliumのポリシーを削除する。最後の手段であり、セキュリティリスクを承知でサービス可用性を優先すべき緊急時にのみ使用する。
運用時の注意点
ネームスペースのラベリング戦略
ネットワークポリシーの効果は、ラベリング体系の一貫性にかかっている。次のような標準labelスキーマを推奨する。
| Labelキー | 説明 | 例の値 |
|---|---|---|
app | アプリケーション名 | api-server, web-frontend |
version | デプロイバージョン | v1, v2 |
env | 環境の区分 | production, staging, dev |
team | 担当チーム | platform, backend, data |
tier | アーキテクチャティア | frontend, backend, database |
compliance | 規制遵守レベル | pci-dss, hipaa, sox |
ネームスペースにもlabelを必ず適用しなければならない。namespaceSelector はネームスペースのlabelを基準にマッチングするためだ。Kubernetes 1.22以上では kubernetes.io/metadata.name labelが自動的に追加され名前ベースの選択が可能だが、追加の分類labelを明示的に管理するのがよい。
ポリシー変更時の影響範囲の評価
ネットワークポリシーを変更する際は、次のプロセスに従う。
- 変更影響の分析: ポリシーが適用されるPod数、影響を受けるサービス間の通信経路を事前に把握する。
- ピアレビュー: セキュリティチームとサービス運用チームが一緒にポリシー変更をレビューする。
- カナリア適用: まず1つのネームスペースや一部のPodにのみ適用して影響を確認する。
- 監視の強化: 変更後は最低30分間、遮断されたトラフィックのログを集中的に監視する。
- 自動ロールバック条件: 遮断されたトラフィックが閾値を超えたら自動的に以前のポリシーへロールバックするメカニズムを構成する。
CI/CDパイプラインでのポリシー検証の自動化
ネットワークポリシーもコードとして管理するため、CI/CDパイプラインで自動検証が可能だ。次のステップをパイプラインに統合する。
Lintステップ: kubeval または kubeconform でYAMLスキーマ検証を行う。Calico/CiliumのCRDスキーマも併せて検証する。
Policyステップ: conftest とOPA Regoポリシーで組織標準への準拠可否を確認する。たとえば、すべてのネームスペースにdefault-denyポリシーがあるか、egressポリシーにワイルドカードCIDR(0.0.0.0/0)がないか、といった点を検証する。
Simulationステップ: テストクラスタにポリシーを適用し、E2Eテストでサービス通信を検証する。
Approvalステップ: 本番適用前にセキュリティチームによる手動承認ゲートを置く。
# github-actions-network-policy-ci.yaml
# GitHub Actions: ネットワークポリシー検証パイプライン
name: Network Policy Validation
on:
pull_request:
paths:
- 'k8s/network-policies/**'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: YAML Lint
run: |
yamllint k8s/network-policies/
- name: Schema Validation
run: |
kubeconform \
-schema-location default \
-schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json' \
k8s/network-policies/*.yaml
- name: Policy Compliance Check
uses: open-policy-agent/conftest-action@v2
with:
files: k8s/network-policies/
policy: policies/network/
- name: Integration Test
run: |
kind create cluster --config test/kind-config.yaml
kubectl apply -f k8s/network-policies/
./test/verify-connectivity.sh
このパイプラインは、ネットワークポリシーファイルが変更されるたびに自動でYAML lint、スキーマ検証、コンプライアンス検査、統合テストを実施し、安全なポリシーデプロイを保証する。
おわりに
Kubernetesのネットワークセキュリティは選択ではなく必須だ。基本のNetworkPolicy APIだけでも十分に意味のあるマイクロセグメンテーションを実装でき、CalicoのティアリングアーキテクチャとStaged Policy、CiliumのL7ポリシーとeBPFの性能は、本番環境でさらに強力なセキュリティ体系を提供する。
最も重要なのは 始めること だ。完璧なポリシー設計を目標にすると、かえって何も適用できなくなる。まずdefault-denyを適用し、トラフィックパターンを観察しながら、段階的にポリシーを細かく整えていく反復的なアプローチが現実的で効果的だ。
Zero-Trustネットワークは単一のツールやポリシーで達成されるものではなく、継続的な観察、分析、改善という運用文化から生まれる。本記事で扱った技術的な方法論をもとに、組織のセキュリティ要件に合ったネットワークポリシー戦略を策定し実行してほしい。