Antrea とは
Antrea とは、オープンソースの Kubernetes CNI で、L3/4 のネットワーキングの機能とセキュリティを Kubernetes クラスターに提供するものです。オープンな仮想スイッチとして長い実績を誇る Open vSwitch をデータプレーンに利用しています。
Antrea では標準的な Kubernetes クラスターネットワーキングを拡張する様々な機能の実装が試みられています。NetwotkPolicy を拡張する機能として Antrea Cluster Network Policy (ACNP) があります。Antrea は標準的な NetworkPolicy もサポートしていますが、ACNP ではクラスター管理者の要求によりよく答えれるように以下のような機能を提供しています。
- ポリシーの階層化(Tier)と優先度設定(Priority)、Tier レベルの RBAC
- Namespace に限定されない、クラスターレベルのセキュリティ設定
- アクションルールのサポート: Allow, Drop, Reject のアクションを指定可能
- FQDN フィルタのサポート
- L7 プロトコルレベルのフィルタのサポート
本記事では、Antrea Cluster Network Policy に注目して機能の確認をしていきたいと思います。
Antrea クラスターの準備
Kubernetes クラスタへの Antrea のインストールおよび antctl
コマンドのインストールについては、以下の記事に例を記載しておりますのでご参照下さい。
https://qiita.com/ynakaoku/items/449b15d06a661fb83e91
本記事は Antrea 1.12.1 の利用を前提に記載しています。
設定の確認
Antrea を展開した段階で、Antrea の Configmap が作成されています。現在の設定状態を antrea-config
で確認してみます。
kubectl get configmap antrea-config -n kube-system -o yaml
ここでは AntreaPolicy
の設定を確認してみます。antrea-agent.conf
および antrea-controller.conf
設定の中に AntreaPolicy: True
で設定されていますが、コメントアウトされています。Antrea 1.0 からデフォルトで Antrea Network Policy が enable になっているので、この状態ですでに有効になっています。
apiVersion: v1
data:
antrea-agent.conf: |
# FeatureGates is a map of feature names to bools that enable or disable experimental features.
featureGates:
# AllAlpha is a global toggle for alpha features. Per-feature key values override the default set by AllAlpha.
# AllAlpha: false
# AllBeta is a global toggle for beta features. Per-feature key values override the default set by AllBeta.
# AllBeta: false
# Enable AntreaProxy which provides ServiceLB for in-cluster Services in antrea-agent.
# It should be enabled on Windows, otherwise NetworkPolicy will not take effect on
# Service traffic.
# AntreaProxy: true
# Enable EndpointSlice support in AntreaProxy. Don't enable this feature unless that EndpointSlice
# API version v1 is supported and set as enabled in Kubernetes. If AntreaProxy is not enabled,
# this flag will not take effect.
# EndpointSlice: true
# Enable TopologyAwareHints in AntreaProxy. This requires AntreaProxy and EndpointSlice to be
# enabled, otherwise this flag will not take effect.
# TopologyAwareHints: true
# Enable traceflow which provides packet tracing feature to diagnose network issue.
# Traceflow: true
# Enable NodePortLocal feature to make the Pods reachable externally through NodePort
# NodePortLocal: true
# Enable Antrea ClusterNetworkPolicy feature to complement K8s NetworkPolicy for cluster admins
# to define security policies which apply to the entire cluster, and Antrea NetworkPolicy
# feature that supports priorities, rule actions and externalEntities in the future.
# AntreaPolicy: true
(snip...)
antrea-controller.conf: |
# FeatureGates is a map of feature names to bools that enable or disable experimental features.
featureGates:
# AllAlpha is a global toggle for alpha features. Per-feature key values override the default set by AllAlpha.
# AllAlpha: false
# AllBeta is a global toggle for beta features. Per-feature key values override the default set by AllBeta.
# AllBeta: false
# Enable traceflow which provides packet tracing feature to diagnose network issue.
# Traceflow: true
# Enable Antrea ClusterNetworkPolicy feature to complement K8s NetworkPolicy for cluster admins
# to define security policies which apply to the entire cluster, and Antrea NetworkPolicy
# feature that supports priorities, rule actions and externalEntities in the future.
# AntreaPolicy: true
(snip...)
Antrea Cluster Network Policy を試す
では実際に Antrea Cluster Network Policy を使ってみます。K8s 標準の NetworkPolicy との動作の違いも見てみたいと思います。
サンプルアプリのデプロイ
まず、動作確認のために使用するアプリケーションをデプロイします。ここではサンプルアプリとして kubernetes.io のチュートリアルに含まれている Guestbook アプリを利用します。
https://kubernetes.io/docs/tutorials/stateless-application/guestbook/
guestbook
という Namespace を作成し、以下のコマンドで Guestbook アプリを展開します。
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/application/guestbook/redis-leader-deployment.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/application/guestbook/redis-leader-service.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/application/guestbook/redis-follower-deployment.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/application/guestbook/redis-follower-service.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/application/guestbook/frontend-deployment.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/application/guestbook/frontend-service.yaml
frontend
, redis-follower
, redis-leader
の三種類の Service と Pod が作成されます。
$ kubectl get all -n guestbook
NAME READY STATUS RESTARTS AGE
pod/frontend-767747dfdd-7sl6f 1/1 Running 0 42m
pod/frontend-767747dfdd-pqvnn 1/1 Running 0 42m
pod/redis-follower-66497dbb55-4gmqc 1/1 Running 0 42m
pod/redis-follower-66497dbb55-ksjpl 1/1 Running 0 42m
pod/redis-leader-6bfcff974b-btvr5 1/1 Running 0 42m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/frontend LoadBalancer 10.103.238.3 172.19.0.212 80:32456/TCP 42m
service/redis-follower ClusterIP 10.97.241.156 <none> 6379/TCP 42m
service/redis-leader ClusterIP 10.111.203.236 <none> 6379/TCP 42m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/frontend 2/2 2 2 42m
deployment.apps/redis-follower 2/2 2 2 42m
deployment.apps/redis-leader 1/1 1 1 42m
NAME DESIRED CURRENT READY AGE
replicaset.apps/frontend-767747dfdd 2 2 2 42m
replicaset.apps/redis-follower-66497dbb55 2 2 2 42m
replicaset.apps/redis-leader-6bfcff974b 1 1 1 42m
frontend
Service はチュートリアルでは type: ClusterIP
ですが、ここでは type: LoadBalancer
タイプに修正し、外部ロードバランサを介して外部から接続できるようにしています。使用環境に合わせて設定して下さい。
設定後、構成は以下のようになっています。
以下の URL にアクセスすると Guestbook の UI が表示されます。
http://172.19.0.212/
ここで、Messages
欄にメッセージを一つ書き込んでみます。first message
と記入し Submit すると、Redis に格納されたメッセージが以下のように表示されるようになります。
ここで各 Pod のラベル設定を確認しておきます。フロントエンドの Pod である frontend
にはapp: guestbook
の、バックエンドのredis-leader
とredis-follower
にはapp: redis
のラベルが設定されています。ラベルはこのあと NetworkPolicy や Antrea Network Policy の PodSelector
設定で使用します。
$ kubectl get pod -L=app
NAME READY STATUS RESTARTS AGE APP
frontend-767747dfdd-7sl6f 1/1 Running 0 43m guestbook
frontend-767747dfdd-pqvnn 1/1 Running 0 43m guestbook
redis-follower-66497dbb55-4gmqc 1/1 Running 0 43m redis
redis-follower-66497dbb55-ksjpl 1/1 Running 0 43m redis
redis-leader-6bfcff974b-btvr5 1/1 Running 0 43m redis
NetworkPolicy
Antrea Cluster Network Policy を試す前に、標準の NetworkPolicy の動作を確認してみます。
Namespace 内のコンテナ間制御
以下のポリシーを適用します。このポリシーは app: redis
の Pod に対して同じラベルを持つ Pod との通信を許可するものですが、それ以外の通信は不許可となります。つまり Namespace 内のフロントエンドfrontend
とバックエンドredis
の通信は阻害されることになります。
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: drop-access-to-redis
spec:
policyTypes:
- Ingress
podSelector:
matchLabels:
app: redis
ingress:
- from:
- podSelector:
matchLabels:
app: redis
$ kubectl apply -f np1.yaml
networkpolicy.networking.k8s.io/drop-access-to-redis created
再度 Guestbook の URL にアクセスすると以下のようにメッセージが表示されなくなっています。
ちょっと分かりにくいですが、下の図のように Redis バックエンドへの接続ができないために記録したメッセージを読み出せなくなっているのです。
この NetworkPolicy を削除すると、再び Redis からメッセージを取得できるようになります。
$ kubectl delete -f np1.yaml
networkpolicy.networking.k8s.io "drop-access-to-redis" deleted
Namespace 外からのアクセスの制御
今度はフロントエンド guestbook
へのアクセスを禁じるポリシーを作成し適用します。
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: drop-access-to-guestbook
spec:
policyTypes:
- Ingress
podSelector:
matchLabels:
app: guestbook
ingress:
- from:
- podSelector:
matchLabels:
app: other
$ kubectl apply -f np2.yaml
networkpolicy.networking.k8s.io/drop-access-to-guestbook created
すると、以下のようにguestbook
にアクセスできなくなりました。
実際には以下のように外部から frontend
への接続が阻害されたため、外部 LB ダウンしています。
再びポリシーを削除するとフロントエンドからもアクセスできるようになります。
$ kubectl delete -f np2.yaml
networkpolicy.networking.k8s.io "drop-access-to-guestbook" deleted
Namespace 間の制御
今度は他の Namespace からのトラフィックの制御を確認してみます。このテストを行うために Namespace test
を作成し、project:test
のラベルを付けます。
$ kubectl create namespace test
namespace/test created
$ kubectl label namespace test project=test
namespace/test labeled
次にテスト用の frontend
コンテナとサービスを test
Namespace 内に作成します。
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/application/guestbook/frontend-deployment.yaml -n test
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/application/guestbook/frontend-service.yaml -n test
$ kubectl get all -n test -L=app
NAME READY STATUS RESTARTS AGE APP
pod/frontend-7cc596bb48-dsgds 1/1 Running 0 9m24s guestbook
pod/frontend-7cc596bb48-l6wsg 1/1 Running 0 9m19s guestbook
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE APP
service/frontend LoadBalancer 10.105.1.244 172.19.0.217 80:30448/TCP 9m10s guestbook
NAME READY UP-TO-DATE AVAILABLE AGE APP
deployment.apps/frontend 2/2 2 2 9m24s
NAME DESIRED CURRENT READY AGE APP
replicaset.apps/frontend-7cc596bb48 2 2 2 9m24s guestbook
frontend
Service は同じく type: LoadBalancer
に修正しています。
また frontend
Deployment の env
を変更して、guestbook
Namespace 内に作成したバックエンド Redis にアクセスするように変更してリスタートしました。以下のように編集しています。
(snip...)
- env:
- name: GET_HOSTS_FROM
value: env
- name: REDIS_FOLLOWER_SERVICE_HOST
value: redis-follower.guestbook.svc.cluster.local
- name: REDIS_LEADER_SERVICE_HOST
value: redis-leader.guestbook.svc.cluster.local
(snip...)
次に、以下のポリシーを作成して test
Namespace からのアクセスを許可します。
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: allow-access-from-other-ns
spec:
policyTypes:
- Ingress
podSelector:
matchLabels:
app: redis
ingress:
- from:
- namespaceSelector:
matchLabels:
project: test
$ kubectl apply -f np3.yaml -n guestbook
networkpolicy.networking.k8s.io/allow-access-from-other-ns created
このポリシーでは test
Namespace から guestbook
Namespace の Redis へのアクセスを許可しています。構成は以下のようになっています。
test
Namespace 側の frontend
Service にアクセスすると、先ほど書き込んだメッセージとともに Guestbook アプリが表示されます。
http://172.19.0.217/
では、今度は以下のような NetwotkPolicy を作成して、test
ネームスペース内の Pod から guestbook
Namespace 内の Redis へのアクセスを制限しようとしてみます。
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: drop-access-from-other-ns-pod
spec:
policyTypes:
- Ingress
podSelector:
matchLabels:
app: redis
ingress:
- from:
- namespaceSelector:
matchLabels:
project: test
- podSelector:
matchLabels:
app: other
$ kubectl delete -f np3.yaml
networkpolicy.networking.k8s.io "allow-access-from-other-ns" deleted
$ kubectl apply -f np4.yaml
networkpolicy.networking.k8s.io/allow-access-from-other-ns created
Namespace と Pod の組み合わせで制限したつもりでしたが、実際には以下のように Redis にアクセスできます。
このように、NetworkPolicy ではクラスターに閉じた形で Namespace 毎のアクセス制御が可能ですが、Namespace やクラスターを超えて同じルールを適用することはできません。また、ポリシーは allow ルールのみですが同時に暗黙の deny ルールが記述されます。そのため細やかな deny ルールを書くようなセキュリティの掛け方には向かないようです。
Antrea Cluster Network Policy はこれらの課題に対応します。
Antrea Cluster Network Policy (ACNP)
ではいよいよ Antrea Cluster Network Policy を設定していきます。
最近の Antrea では最初から Antrea Cluster Network Policy が enable になっていますので、すぐに設定を開始できますが、まず Antrea Cluster Network Policy 独自の Tier について確認しておきます。
Tier
Tier はポリシーを階層化して管理するための概念で、ポリシーに対して優先度をつけたい場合に有用です。初期設定では Tier は以下のように設定されています。
$ kubectl get tier --sort-by=.spec.priority
NAME PRIORITY AGE
emergency 50 37m
securityops 100 37m
networkops 150 37m
platform 200 37m
application 250 37m
baseline 253 37m
各 Tier の PRIORITY
が、実際に処理される優先度を表します。小さい数値ほど優先度が高くなります。たとえば最優先で処理させたいポリシーがある場合は emergency
に設定すれば最初に処理されるようになります。標準の NetworkPolicy で設定されたポリシーは、application
Tier の後で処理されます。
Tier は自分で作成することも可能です。ここでは新しい Tier を以下のマニフェストmytier.yaml
で作成してみます。
apiVersion: crd.antrea.io/v1alpha1
kind: Tier
metadata:
name: mytier
spec:
priority: 10
description: "my custom tier"
$ kubectl apply -f mytier.yaml
tier.crd.antrea.io/mytier created
$
$ kubectl get tiers --sort-by=.spec.priority
mytier 10 36s
emergency 50 124d
securityops 100 124d
networkops 150 124d
platform 200 124d
application 250 124d
baseline 253 124d
Antrea Cluster Network Policy の適用
では Antrea Cluster Network Policy を実際に作成していきます。まず以下のマニフェストを作成します。
apiVersion: crd.antrea.io/v1alpha1
kind: ClusterNetworkPolicy
metadata:
name: acnp-drop-access-to-redis
spec:
priority: 5
tier: securityops
appliedTo:
- podSelector:
matchLabels:
app: redis
ingress:
- action: Allow
from:
- podSelector:
matchLabels:
app: other
name: AllowFromOther
enableLogging: true
これは NetworkPolicy のところで最初に作成したnp1.yaml
によく似ていますが、実際の動作は異なります。以下のコマンドでこのマニフェストを適用します。
$ kubectl apply -f acnp1.yaml
clusternetworkpolicy.crd.antrea.io/acnp-drop-access-to-redis created
$
$ kubectl get acnp
NAME TIER PRIORITY DESIRED NODES CURRENT NODES AGE
acnp-drop-access-to-redis securityops 5 1 1 24s
この状態で Guestbook アプリにアクセスしても、バックエンドへのアクセスは阻害されないため、正常に表示されます。
NetworkPolicy ではポリシーが反映されると同時に暗黙の Deny が有効になり、対象の Pod に対して明示的に許可されないトラフィックはドロップされるようになりますが、ACNP では明示的に Drop ルールが書かれない限りトラフィックは許可されます。
なお、ACNP の kind はClusterNetworkPolicy
ですが、上のkubectl get acnp
コマンドのように、acnp
という省略形で操作を行うことも可能です。
今度は、acnp1.yaml
を修正して以下のacp11.yaml
を作成し適用してみます。明示的にソースとなる Pod をpodSelector
で指定し、 action
を Drop
に変更します。
apiVersion: crd.antrea.io/v1alpha1
kind: ClusterNetworkPolicy
metadata:
name: acnp-drop-access-to-redis
spec:
priority: 5
tier: securityops
appliedTo:
- podSelector:
matchLabels:
app: redis
ingress:
- action: Drop
from:
- podSelector:
matchLabels:
app: guestbook
name: DropFromGuestbook
enableLogging: true
これを同じく適用します。
$ kubectl apply -f acnp11.yaml
clusternetworkpolicy.crd.antrea.io/acnp-drop-access-to-redis configured
すると、今度は Redis へのアクセスが阻害されるため、以下のようにメッセージが表示されなくなりました。
上のマニフェストでは enableLogging: true
に設定しているので、条件にマッチしたトラフィックが流れると各ノードの /var/log/antrea/networkpolicy/np.log
にロギングされるようになります。ノードにログインしてこのファイルを確認すると、最後に以下のようなログが出力されていることが確認できました。
...
2023/11/01 08:02:06.424992 AntreaPolicyIngressRule AntreaClusterNetworkPolicy:acnp-drop-access-to-redis DropFromGuestbook Drop 44900 192.168.1.97 41662 192.168.1.30 6379 TCP 60 <nil>
2023/11/01 08:02:07.438157 AntreaPolicyIngressRule AntreaClusterNetworkPolicy:acnp-drop-access-to-redis DropFromGuestbook Drop 44900 192.168.1.97 41662 192.168.1.30 6379 TCP 60 <nil>
2023/11/01 08:02:09.453315 AntreaPolicyIngressRule AntreaClusterNetworkPolicy:acnp-drop-access-to-redis DropFromGuestbook Drop 44900 192.168.1.97 41662 192.168.1.30 6379 TCP 60 <nil>
DropFromGuestbook
の Drop ルールに基づいて、送信元 Pod 192.168.1.97
から宛先 Pod 192.168.1.30
、宛先ポート番号 6379
への通信がドロップされたことが分かります。
また、この ACNP では、tier
を securityops
、 priority
を 5
に指定しています。priority
は tier
の内部での処理の優先度を表します。
上述のように securityops
Tier に指定したポリシーは標準の NetworkPolicy よりも優先的に処理されます。例えば、np1.yaml
を最初に適用してバックエンドへのアクセスが阻害されている状態を作り、その上で以下のacnp12.yaml
を適用すると、ACNP の処理が優先されてバックエンドへのアクセスが許可されるようになります。
apiVersion: crd.antrea.io/v1alpha1
kind: ClusterNetworkPolicy
metadata:
name: acnp-allow-access-to-redis
spec:
priority: 5
tier: securityops
appliedTo:
- podSelector:
matchLabels:
app: redis
ingress:
- action: Allow
from:
- podSelector:
matchLabels:
app: guestbook
name: AllowFromGuestbook
enableLogging: true
$ kubectl apply -f np1.yaml
networkpolicy.networking.k8s.io/drop-access-to-redis created
$ kubectl apply -f acnp12.yaml
clusternetworkpolicy.crd.antrea.io/acnp-allow-access-to-redis created
$ kubectl get netpol
NAME POD-SELECTOR AGE
drop-access-to-redis app=redis 33s
$ kubectl get acnp
NAME TIER PRIORITY DESIRED NODES CURRENT NODES AGE
acnp-allow-access-to-redis securityops 5 1 1 18s
このように、Antrea Cluster Network Policy を使えば、標準の NetworkPolicy よりもより明確に送信元と宛先を指定したセキュリティポリシーの定義ができます。
ACNP による Namespace 間の制御
ここからは ACNP による Namespace をまたいだ制御を見ていきたいと思います。その前に、もう一度 K8s NetworkPolicy ではどのような挙動になるかを確認しておきます。上で利用した np1.yaml
コピーして、 Guestbook アプリ間のトラフィックを許可するように変更した np11.yaml
を作成し適用します。
kkind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: allow-access-from-guestbook-to-redis
spec:
policyTypes:
- Ingress
podSelector:
matchLabels:
app: redis
ingress:
- from:
- podSelector:
matchLabels:
app: guestbook
$ kubectl apply -f np11.yaml
networkpolicy.networking.k8s.io/allow-access-from-guestbook-to-redis created
現在、guestbook
とtest
の Namespace にデプロイ済みの Pod の状態は以下のようになっています。
$ kubectl get pod -L=app -n guestbook
NAME READY STATUS RESTARTS AGE APP
frontend-767747dfdd-hx7xc 1/1 Running 0 148m guestbook
frontend-767747dfdd-mngdm 1/1 Running 0 148m guestbook
redis-follower-66497dbb55-ksjpl 1/1 Running 0 4h13m redis
redis-follower-66497dbb55-vm75v 1/1 Running 0 3h16m redis
redis-leader-85f4588648-2wffl 1/1 Running 0 3h55m redis
$ kubectl get pod -L=app -n test
NAME READY STATUS RESTARTS AGE APP
frontend-7cc596bb48-dsgds 1/1 Running 0 94m guestbook
frontend-7cc596bb48-l6wsg 1/1 Running 0 94m guestbook
この状態では、test
Namespace 側の Guestbook にアクセスしても、Redis へのアクセスは許可されないので、以下のようにメッセージを取得できません。K8s NetworkPolicy では Namespace をまたいで podSelector
を利用できないからです。
では、ACNP で同じようなポリシーを作成してトライしてみましょう。
apiVersion: crd.antrea.io/v1alpha1
kind: ClusterNetworkPolicy
metadata:
name: acnp-allow-access-from-guestbook-to-redis
spec:
priority: 5
tier: securityops
appliedTo:
- podSelector:
matchLabels:
app: redis
ingress:
- action: Allow
from:
- podSelector:
matchLabels:
app: guestbook
name: AllowFromGuestbook
enableLogging: true
$ kubectl apply -f acnp2.yaml
clusternetworkpolicy.crd.antrea.io/acnp-allow-access-from-guestbook-to-redis created
np11.yaml
と同様に appliedTo
と from
の両方の podSelector
でラベル app: guestbook
を指定していますが、Namespace は特に指定していません。また、前に作成した K8s NetworkPolicy もそのままにしてあります。
$ kubectl get netpol
NAME POD-SELECTOR AGE
allow-access-from-guestbook-to-redis app=redis 11m
$
$ kubectl get acnp
NAME TIER PRIORITY DESIRED NODES CURRENT NODES AGE
acnp-allow-access-from-guestbook-to-redis securityops 5 1 1 103s
この状態で再び test
側の Guestbook にアクセスすると、以下のように許可されました。
ACNP の Allow ルールにマッチして処理されたので、以下のようなログも出力されます。
...
2023/11/01 08:15:34.431560 AntreaPolicyIngressRule AntreaClusterNetworkPolicy:acnp-allow-access-from-guestbook-to-redis AllowFromGuestbook Allow 44900 192.168.1.97 59608 192.168.1.41 6379 TCP 60 <nil>
ACNP ではこのように Namespace をまたがって PodSelector
を評価することができます。
また、ACNP では podSelector
と namespaceSelector
を併用して、namespace 毎に適用対象や送信元となる pod を明示的に指定することができます。acnp2.yaml
を編集して namespaceSelector
条件を追加した acnp21.yaml
を作成します。
apiVersion: crd.antrea.io/v1alpha1
kind: ClusterNetworkPolicy
metadata:
name: acnp-allow-access-from-guestbook-to-redis
spec:
priority: 5
tier: securityops
appliedTo:
- podSelector:
matchLabels:
app: redis
namespaceSelector:
matchLabels:
project: prod
ingress:
- action: Allow
from:
- podSelector:
matchLabels:
app: guestbook
namespaceSelector:
matchLabels:
project: test
name: AllowFromGuestbook
enableLogging: true
$ kubectl apply -f acnp21.yaml
clusternetworkpolicy.crd.antrea.io/acnp-allow-access-from-to-guestbook configured
この修正により、受信側 Namespace のラベル条件に project: prod
、送信側 namespace のラベル条件に project: test
が追加されました。受信側の Guestbook Pods は guestbook
Namespace 内にありますが、ラベルが付いていないので、この状態では test
側からはアクセスできません。
そこで guestbook
Namespace にラベルを追加します。
$ kubectl label ns guestbook project=prod
namespace/guestbook labeled
$kubectl get ns -L=project
NAME STATUS AGE PROJECT
default Active 125d
guestbook Active 6d23h prod
kube-node-lease Active 125d
kube-public Active 125d
kube-system Active 125d
test Active 23h test
すると test
Namespace 内の Guestbook から guestbook
Namespace 内の Redis にアクセスできるようになりました。
...
2023/11/01 08:28:16.723581 AntreaPolicyIngressRule AntreaClusterNetworkPolicy:acnp-allow-access-from-guestbook-to-redis AllowFromGuestbook Allow 44900 192.168.1.71 49126 192.168.1.30 6379 TCP 60 <nil>
このように、Antrea Cluster Network Policy では、Namespace に限定されないクラスターレベルのネットワークポリシーを設定することが可能です。クラスター管理者は Namespace に依存しないクラスターレベルのセキュリティポリシーを設定することができるようになります。
ClusterGroup
ClusterGroup は ACNP の特徴的な機能の一つで、エンドポイントをグルーピングするルールを NetworkPolicy の外で作成し再利用することができます。これまでに紹介した podSelector
や namespaceSelector
、おなじみの ipBlock
以外に、K8s Service を利用する serviceReference
やグルーピングのネスト構造を定義できる childGroups
といった定義を使うことが可能です。
ClusterGroup を使ったルールを作成していく前に、これまでに作成してきたすべてのポリシーをいったん削除します。
$ kubectl get networkpolicy --no-headers | awk '{print $1}'| xargs kubectl delete networkpolicy
networkpolicy.networking.k8s.io "allow-access-from-guestbook-to-redis" deleted
$
$ kubectl get acnp --no-headers | awk '{print $1}'| xargs kubectl delete acnp
clusternetworkpolicy.crd.antrea.io "acnp-allow-access-from-guestbook-to-redis" deleted
そして guestbook
Namespace 内の Pod へのすべてのトラフィックを暗黙的に不許可にするために以下の acnp-dropany.yaml
を作成し適用します。適用先の Tier として baseline
を指定しています。この場合、このルールは K8s NetworkPolicy を含むすべてのポリシールールが評価された後に適用されるようになります。
apiVersion: crd.antrea.io/v1alpha1
kind: ClusterNetworkPolicy
metadata:
name: acnp-drop-any-in-production
spec:
priority: 100
tier: baseline
appliedTo:
- podSelector: {}
namespaceSelector:
matchLabels:
project: prod
ingress:
- action: Drop
from:
- podSelector: {}
name: DropFromAny
enableLogging: true
$ kubectl apply -f acnp-dropany.yaml
clusternetworkpolicy.crd.antrea.io/acnp-drop-any-in-production created
すべての Pod 間の通信が不許可になるため、Guestbook アプリのフロントエンドと Redis バックエンド間の通信もできなくなります。
...
2023/11/01 08:31:25.542766 IngressDefaultRule AntreaClusterNetworkPolicy:acnp-drop-any-in-production DropFromAny Drop 16 192.168.1.92 44850 192.168.1.30 6379 TCP 60 <nil>
2023/11/01 08:31:26.573559 IngressDefaultRule AntreaClusterNetworkPolicy:acnp-drop-any-in-production DropFromAny Drop 16 192.168.1.92 44850 192.168.1.30 6379 TCP 60 <nil>
2023/11/01 08:31:28.589537 IngressDefaultRule AntreaClusterNetworkPolicy:acnp-drop-any-in-production DropFromAny Drop 16 192.168.1.92 44850 192.168.1.30 6379 TCP 60 <nil>
そこで、 フロントエンドとバックエンド間の通信を許可するポリシーを記載していきますが、そこで ClusterGroup を使用してみます。ここでは、Redis バックエンドサービスのグルーピングに serviceReference
と childGroups
を使ってみます。
apiVersion: crd.antrea.io/v1alpha3
kind: ClusterGroup
metadata:
name: cg-guestbook
spec:
podSelector:
matchLabels:
app: guestbook
---
apiVersion: crd.antrea.io/v1alpha3
kind: ClusterGroup
metadata:
name: cg-redis-leader
spec:
serviceReference:
name: redis-leader
namespace: guestbook
---
apiVersion: crd.antrea.io/v1alpha3
kind: ClusterGroup
metadata:
name: cg-redis-follower
spec:
serviceReference:
name: redis-follower
namespace: guestbook
---
apiVersion: crd.antrea.io/v1alpha3
kind: ClusterGroup
metadata:
name: cg-redis-nested
spec:
childGroups: [cg-redis-leader, cg-redis-follower]
$ kubectl apply -f cg1.yaml
clustergroup.crd.antrea.io/cg-guestbook created
clustergroup.crd.antrea.io/cg-redis-leader created
clustergroup.crd.antrea.io/cg-redis-follower created
clustergroup.crd.antrea.io/cg-redis-nested created
次にこれらの ClusterGroup を利用した ACNP を acnp3.yaml
として作成します。
apiVersion: crd.antrea.io/v1alpha1
kind: ClusterNetworkPolicy
metadata:
name: acnp-allow-access-to-guestbook
spec:
priority: 5
tier: securityops
appliedTo:
- group: "cg-guestbook"
ingress:
- action: Allow
from:
- group: "cg-guestbook"
name: AllowToGuestbook
enableLogging: true
---
apiVersion: crd.antrea.io/v1alpha1
kind: ClusterNetworkPolicy
metadata:
name: acnp-allow-access-to-redis
spec:
priority: 5
tier: securityops
appliedTo:
- group: "cg-redis-nested"
ingress:
- action: Allow
from:
- group: "cg-guestbook"
name: AllowFromGuestbookToRedis
enableLogging: true
---
apiVersion: crd.antrea.io/v1alpha1
kind: ClusterNetworkPolicy
metadata:
name: acnp-allow-access-to-redis-follower
spec:
priority: 5
tier: securityops
appliedTo:
- group: "cg-redis-follower"
ingress:
- action: Allow
from:
- group: "cg-redis-leader"
name: AllowToRedisFollower
enableLogging: true
$ kubectl apply -f acnp3.yaml
clusternetworkpolicy.crd.antrea.io/acnp-allow-access-to-guestbook created
clusternetworkpolicy.crd.antrea.io/acnp-allow-access-to-redis created
clusternetworkpolicy.crd.antrea.io/acnp-allow-access-to-redis-follower created
この状態でブラウザからアクセスすると、Redis バックエンドへのアクセスも許可されて正常に応答が返ってくるようになりました。
...
2023/11/01 08:33:32.281153 AntreaPolicyIngressRule AntreaClusterNetworkPolicy:acnp-allow-access-to-redis AllowFromGuestbookToRedis Allow 44900 192.168.1.92 35194 192.168.1.30 6379 TCP 60 <nil>
いかがでしたでしょうか。Antrea Cluster Network Policy では、クラスターレベルで柔軟なエンドポイントのグルーピングが可能になっていることを理解いただけたかと思います。
FQDN フィルタリング
FQDN フィルタリングは、Pod からの外向け通信において、通信先の完全修飾ドメイン名 (FQDN) を指定して特定のドメインとの通信を制御する仕組みです。ACNP の egress
ルールで使用できます。FQDN とのマッチングは完全一致とワイルドカードを用いた部分一致を使うことができます。FQDN と実際の通信で使用される IP アドレスの関連付けは、Pod からの DNS クエリーをインスペクションすることで行います。
では早速 FQDN フィルタリングを試してみます。前のステップで作成した NetworkPolicy と ACNP をすべて削除します。次に guestbook
Namespace からの出力トラフィックをすべて拒否する以下のマニフェストを作成し、適用します。
apiVersion: crd.antrea.io/v1alpha1
kind: ClusterNetworkPolicy
metadata:
name: acnp-reject-egress-in-production
spec:
priority: 100
tier: baseline
appliedTo:
- podSelector: {}
namespaceSelector:
matchLabels:
project: prod
egress:
- action: Reject
name: RejectToAny
enableLogging: true
$ kubectl apply -f acnp-reject-egress.yaml
clusternetworkpolicy.crd.antrea.io/acnp-reject-egress-in-production created
この状態で frontend
Pod から www.google.com にアクセスしようとすると、以下のように拒否されます。
$ kubectl exec frontend-767747dfdd-5896s -it -- curl -o tempfile www.google.com
curl: (7) Failed to connect to www.google.com port 80: Connection refused
command terminated with exit code 7
ここで適用したマニフェストではアクションを Reject
に設定したので、TCP 接続が Antrea により拒否され接続はすぐに失敗します。Reject したことがログに出力されます。
...
2023/11/01 10:41:36.949294 EgressDefaultRule AntreaClusterNetworkPolicy:acnp-reject-egress-in-production RejectToAny Reject 16 192.168.1.97 45020 172.217.26.228 80 TCP 60 <nil>
次に、google.com ドメインへのアクセスを許可する以下のようなマニフェストを作成して適用します。許可ルールにて fqdn: "*google.com"
と指定することで、google.com のすべてのホスト、サブドメインへのアクセスが許可されます。
apiVersion: crd.antrea.io/v1alpha1
kind: ClusterNetworkPolicy
metadata:
name: acnp-fqdn-allow-google
spec:
priority: 5
appliedTo:
- podSelector: {}
namespaceSelector:
matchLabels:
project: prod
egress:
- action: Allow
to:
- fqdn: "*google.com"
name: AllowToGoogle
enableLogging: true
$ kubectl apply -f acnp-allow-google.yaml
clusternetworkpolicy.crd.antrea.io/acnp-fqdn-allow-google created
もう一度 frontend
Pod から www.google.com にアクセスすると、以下のように許可されます。
$ kubectl exec frontend-767747dfdd-5896s -it -- curl -o tempfile www.google.com
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 19602 0 19602 0 0 98010 0 --:--:-- --:--:-- --:--:-- 98010
...
2023/11/01 10:56:56.359560 AntreaPolicyEgressRule AntreaClusterNetworkPolicy:acnp-fqdn-allow-google AllowToGoogle Allow 14500 192.168.1.97 45802 172.217.26.228 80 TCP 60 <nil>
なお、この時点で ACNP は以下のような状態になっています。
$ kubectl get acnp
NAME TIER PRIORITY DESIRED NODES CURRENT NODES AGE
acnp-fqdn-allow-google application 5 1 1 6m5s
acnp-reject-egress-in-production baseline 100 1 1 26m
Google ドメインへの接続を許可するポリシーは Reject ポリシーよりも優先度の高い application
Tier に設定されているため、先に評価されることが分かります。
次回以降、Antrea Cluster Network Policy についてより詳細な操作方法などをご紹介していければと思います。