本記事は、TUNA-JP Advent Calendar 13日目の投稿です。今回は、Antrea 1.3 で導入された FQDN based filtering について紹介したいと思います。
はじめに
Antrea って何?という点については、@iwaseyusuke さんが 11日目の投稿「Antrea が OVS に書き込んでる Flow Table を読んでみよう (苦行)」で紹介されているので、今回は省略したいと思います。
Antrea は、通常の Kubernetes の Network Policy をサポートしているのですが、それだけではなく独自に拡張した Antrea Cluster Network Policy(ACNP)と呼ばれる CRD があります。 通常の Network Policy は開発者が自身のアプリケーションを保護することが目的ですが、ACNP は、管理者がクラスタ全体にセキュリティポリシーを設定できることを目的としています。そのため、ACNP が適用される順番は、Kubernetes の Network Policy の前になります。
ちなみに、Antrea Network Policy (ANP) と呼ばれる CRD も存在します。Namespace が対象である点が ACNP との違いです。ACNP と比較していくつか制限がありますが、今回試す FDQN based filtering は ANP でも使用できます。
FDQN based filtering とは、Fully Qualified Domain Name (FQDN) をもとに egress 通信を制御できる機能です。例えば、以下のように、app: test
のラベルにマッチする Pod から example.com
への通信をドロップするルールを作成することができます。
apiVersion: crd.antrea.io/v1alpha1
kind: ClusterNetworkPolicy
metadata:
name: acnp-fqdn-drop-example
spec:
priority: 1
appliedTo:
- podSelector:
matchLabels:
app: test
egress:
- action: Drop
to:
- fqdn: "example.com"
通信を制御するためには、最終的には IP アドレスを知る必要がありますが、Antrea ではどうやって実装しているのか気になってので、今回調べてみました。
環境
今回、検証用に作成した環境は以下になります。
・ノード OS: Ubuntu 18.04
・Open vSwitch: 2.13.5
・Kubernetes: 1.22
・Antrea: 1.4
FQDN based filtering を試す
FQDN based filtering を試すために、まずは busybox の Pod をデプロイします。
apiVersion: v1
kind: Pod
metadata:
name: busybox
labels:
app: busybox
spec:
containers:
- image: busybox
command:
- sleep
- "36000"
imagePullPolicy: IfNotPresent
name: busybox
restartPolicy: Always
デプロイ後、busybox の Pod から google.com への ping が通ることを確認します。
$ kubectl exec -it busybox -- ping google.com
PING google.com (74.125.68.102): 56 data bytes
64 bytes from 74.125.68.102: seq=0 ttl=99 time=43.156 ms
64 bytes from 74.125.68.102: seq=1 ttl=100 time=41.788 ms
64 bytes from 74.125.68.102: seq=2 ttl=100 time=42.376 ms
次に、以下の ACNP を作成します。app: busybox
のラベルにマッチする Pod から google.com
への通信をドロップするルールになっています。
apiVersion: crd.antrea.io/v1alpha1
kind: ClusterNetworkPolicy
metadata:
name: acnp-fqdn-drop-google
spec:
priority: 1
appliedTo:
- podSelector:
matchLabels:
app: busybox
egress:
- action: Drop
to:
- fqdn: "google.com"
上記 ACNP の作成後、google.com への ping が失敗するようになりました。ちゃんと、作成したポリシーが動作していることが分かります。
$ kubectl exec -it busybox -- ping google.com
PING google.com (74.125.68.102): 56 data bytes
^C
--- google.com ping statistics ---
30 packets transmitted, 0 packets received, 100% packet loss
command terminated with exit code 1
どうやって FQDN based filtering を実現しているのか?
さて、どうやって FQDN based filtering を実現しているのか?という話ですが、busybox Pod が動作しているノード上の Antrea Agent が CoreDNS に問い合わせを行って名前解決を行い、取得した IP アドレスをもとに Flow を作成しています。
Antrea Agent のログを見ると分かりやすいのですが、ACNP が作成されたら、名前解決を行って、得られた IP アドレスをもとに Flow を作成するという流れになっています。
I1212 02:30:24.487325 1 networkpolicy_controller.go:192] NetworkPolicy AntreaClusterNetworkPolicy:acnp-fqdn-drop-google applied to Pods on this Node
I1212 02:30:24.489093 1 fqdn.go:682] "Making DNS request" fqdn="google.com" dnsServer="10.96.0.10:53"
I1212 02:30:24.493767 1 fqdn.go:603] "Received DNS Packet with valid Answer" IPs=map[74.125.68.100:74.125.68.100 74.125.68.101:74.125.68.101 74.125.68.102:74.125.68.102 74.125.68.113:74.125.68.113 74.125.68.138:74.125.68.138 74.125.68.139:74.125.68.139] TTL=2
I1212 02:30:24.493902 1 fqdn.go:483] "Reconciling dirty rule" ruleID="5c0eef29c581d662"
I1212 02:30:24.499606 1 networkpolicy_controller.go:542] "Rule realization was done" ruleID="5c0eef29c581d662"
名前解決の処理は ACNP を作成した1回だけでなく定期的に行われるので、IP アドレスに変更があった場合も変更を検知して新しい Flow が作成されます。
antctl
コマンドを使って Flow Table を確認すると、以下のように egress 通信用の Flow が作成されていることが分かります。
# antctl get ovsflows
~~ snip ~~
table=AntreaPolicyEgressRule, n_packets=11, n_bytes=1078, priority=14900,conj_id=3 actions=load:0x3->NXM_NX_REG3[],load:0x1->NXM_NX_REG0[20],goto_table:EgressMetric
table=AntreaPolicyEgressRule, n_packets=0, n_bytes=0, priority=14900,ip,nw_src=192.168.1.2 actions=conjunction(3,1/2)
table=AntreaPolicyEgressRule, n_packets=0, n_bytes=0, priority=14900,ip,nw_dst=74.125.68.101 actions=conjunction(3,2/2)
table=AntreaPolicyEgressRule, n_packets=0, n_bytes=0, priority=14900,ip,nw_dst=74.125.68.139 actions=conjunction(3,2/2)
table=AntreaPolicyEgressRule, n_packets=0, n_bytes=0, priority=14900,ip,nw_dst=74.125.68.113 actions=conjunction(3,2/2)
table=AntreaPolicyEgressRule, n_packets=0, n_bytes=0, priority=14900,ip,nw_dst=74.125.68.100 actions=conjunction(3,2/2)
table=AntreaPolicyEgressRule, n_packets=0, n_bytes=0, priority=14900,ip,nw_dst=74.125.68.102 actions=conjunction(3,2/2)
table=AntreaPolicyEgressRule, n_packets=0, n_bytes=0, priority=14900,ip,nw_dst=74.125.68.138 actions=conjunction(3,2/2)
※ Flow Table の詳細は、@iwaseyusuke さんの投稿 で解説されています!!
FQDN 周りの処理は主に fqdn.go で実装されているので、より詳細が知りたい方はこのあたりのコードを確認いただければと思います。
おわりに
今回は Antrea の FQDN based filtering について調べてみました。FQDN から Flow を作成するまでの処理を見て、ルール数が増えると CoreDNS に負荷がかかるんじゃないかなと思いましたが、FQDN ベースのルールはそんなにたくさん作らないですかね...? 機会があれば、大量に作成したときのパフォーマンスについて調べてみようと思います。