前回の記事では、ファイアウォールポリシールール内のFQDNオブジェクトを使い、GCPで完全修飾ドメイン名(FQDN)によるEgressフィルタリングを実現する方法を紹介しました。ファイアウォールポリシールールはVPCネットワークに適用され、すべてのworkloadsに対してEgressフィルタリングが適用されます。
先日、Google Kubernetes Engine(GKE)チームは、GKE Dataplane V2でFQDNによるEgressフィルタリングをサポートすると発表しました。この機能を使えば、Pod全体または一部とGKEクラスター外部のリソースとのEgress通信を、FQDN単位で柔軟に制御できます。
本記事では、新しいFQDN Network Policyを使い、PodとGKEクラスター外部リソースの間のEgress通信を制御する方法を解説します。
FQDN Network PolicyはGKE専用のGoogle独自実装です。Kubernetesプロジェクトが標準仕様を策定した場合に実装がどう変わるかについては、Googleからの情報はまだ公開されていません。
要件と制限事項
- FQDN Network Policyは現時点では、GKE Dataplane V2を使うstandardクラスターに限りプレビュー提供されています。
- プレビュー期間中は、GCPによるSLAおよびテクニカルサポートの保証はありません。
- FQDN network policyは有償機能ですが、プレビュー期間中の課金はありません。料金モデルに関する情報はGCPからまだ公開されておらず、GA発表を待つ必要があります。
- GKEクラスターのバージョンは1.26.4-gke.500または1.27.1-gke.400以降である必要があります。
- クラスターはDNSプロバイダーとしてkube-dnsまたはCloud DNSを使用している必要があります。
- WindowsノードプールおよびAnthos Service Meshには対応していません。
FQDNNetworkPolicyでは、ClusterIPやHeadless ServiceをEgressの宛先とするトラフィックは許可されません。GKEはNetwork Policyルールを評価する前に、サービスの仮想IPアドレス(VIP)をバックエンドのPod IPアドレスに変換するためです。- GKEのポリシー適用モジュールでは、CNAMEを使ってIPアドレスを登録することはできません。代わりに、CNAMEが参照しているA/AAAAレコードをポリシー内で直接指定してください。
最新の制限事項の一覧は、公式ドキュメントをご確認ください。
GKEクラスターのセットアップ
Dataplane v2とFQDN network policyを有効化したGKE standardクラスターを新規作成します。
gcloud beta container clusters create fqdn-network-policy-demo-cluster \
--region us-central1 \
--enable-fqdn-network-policy \
--cluster-version=1.26.5-gke.1200 \
--enable-dataplane-v2
GKE Dataplane V2はCiliumで実装されており、GKE Dataplane V2を有効にしたクラスターではKubernetes NetworkPolicyが常時オンになります。Calicoのようなサードパーティ製アドオンを別途導入・運用する必要はありません。
**サンプルアプリケーションのデプロイ**
defaultネームスペースに、サンプルとしてnginxとcurlのアプリケーションをデプロイします。
#create nginx deployment
kubectl create deployment nginx --image nginx
#Expose the nginx deployment
kubectl expose deployment nginx --port 80 --target-port 80
#create curl test pod
kubectl run curl --image curlimages/curl --command sleep 3600

curl Podから内部エンドポイントとインターネット上のエンドポイントへの接続を確認します。

結果から、curl Podが内部のnginx ClusterIPサービスとインターネット上のエンドポイントの両方にアクセスできていることがわかります。
FQDN Network Policyのセットアップ
FQDNによるEgressフィルタリングは、FQDNNetworkPolicy CRDで設定します。
workloadsを対象としたFQDNNetworkPolicyがアクティブな状態でも、workloadsからDNSリクエストを発行する動作には影響しません。nslookupやdigといったコマンドはポリシーの影響を受けず、任意のドメインに対して動作します。ただし、許可リストに含まれないドメインを解決した先のIPアドレスへのリクエストは、その後ドロップされます。
curl Pod向けに、www.doit.comへのEgressリクエストのみを許可する以下のサンプルポリシーをデプロイします。
cat <<EOF | kubectl apply -f -
---
apiVersion: networking.gke.io/v1alpha1
kind: FQDNNetworkPolicy
metadata:
name: allow-out-fqdnnp
spec:
podSelector:
matchLabels:
run: curl #labels assigned to the pod
egress:
- matches:
- name: "www.doit.com" #The fully qualified domain name. IP addresses provided by the nameserver associated with www.doit.com are allowed. You must specify either name or pattern, or both.
ports:
- protocol: "TCP" #optional field to allow only https traffic
port: 443
EOF
ネットワークポリシーが意図したworkloadに適用されているかを確認します。

curl Podから内部および外部のエンドポイントへの接続をテストします。

結果から、許可されているのはhttps://www.doit.comへのリクエストだけで、ClusterIPサービスを含むその他のドメインへのリクエストはブロックされていることがわかります。したがって、ClusterIPやPod IP宛てのEgressリクエストを許可したい場合は、KubernetesのラベルベースNetworkPolicyを併用する必要があります。
同じPodにFQDNNetworkPolicyとNetworkPolicyの両方が適用されている場合、いずれかのポリシーに合致すればEgressトラフィックは許可されます。Egress IPアドレス/ラベルベースのポリシーとFQDNネットワークポリシーの間に優先順位はありません。
ClusterIPサービスへのEgressリクエストを許可するため、以下のラベルベースNetworkPolicyをデプロイします。
cat <<EOF | kubectl apply -f -
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-internal-service-calls
spec:
podSelector:
matchLabels:
run: curl #source pod label
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: nginx #target pod label
ports:
- protocol: TCP
port: 80
- to:
ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53
EOF
curl Podから内部および外部への接続を再度確認します。

結果から、FQDNNetworkPolicyとNetworkPolicyを組み合わせることで、PodのEgress通信を効率的に管理できることが確認できます。
GKE Dataplane V2のFQDN Egressフィルタリング機能は、管理者が外向き通信のポリシーを明確に定義できるようにし、ネットワークセキュリティとガバナンスを強化します。これにより、より安全でコンプライアンスに適合したKubernetes環境を実現できます。
プレビュー機能はテスト環境での利用が前提です。GAのアナウンスについてはGKEリリースノートをご確認ください。