この記事は Kubernetes道場 Advent Calendar 2018 16日目の記事です。
今回はNetworkPolicyについて。
NetworkPolicy
NetworkPolicyの概要
NetworkPolicyはPodに対してPod間の通信や外部のエンドポイントへの通信を制御するためのリソースだ。
ラベルを利用してPodを選択し、選択されたPodのトラフィックのルールを定義していく。
今回はNetworkPolicyの要素を見ていくと同時にフィールドの説明を入れていく。
また、Manifestがあったほうが理解が進むかと思うので先にManifestの例を載せておこう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-np
spec:
podSelector:
matchLabels:
role: app
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 10.2.0.0/16
except:
- 10.2.1.0/24
- namespaceSelector:
matchLabels:
project: test-app
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 8080
egress:
- to:
- ipBlock:
cidr: 172.31.0.0/16
ports:
- protocol: TCP
port: 80
|
podSelector
このフィールドでNetworkPolicyを適用するPodを選択する。
記述の方法はLabelSelectorなので、Deploymentなどで使用していたものと同様のものだ。(なので指定方法は省略させてもらう)
このフィールドは必須なのだが、空の指定をすることが出来る。
その場合は、NetworkPolicyの属するNamespace上の全てのPodが対象となる。
policyTypes
このフィールドでNetworkPolicyがIngress(受信側)のポリシーか、Egress(送信側)のポリシーか、または両方なのかを指定する。
指定できる値は Ingress
と Egress
でリストで指定する。
省略すると Ingress
がセットされ、Egressのルールが設定されている場合は Egress
もセットされる。
ingress / egress
フィールド名の通り、受信ルールと送信ルールを指定する。
リストで指定するため、複数のルールを記述することが可能だ。
ルールの記述について掘り下げてみていこう。
from / to
このフィールドに受信元や送信先のルールをリストで指定する。
このフィールドを省略したり空で指定した場合は全てのトラフィックが対象となる。また、複数指定があった場合はORを取って組み合わされる。
受信元、送信先のルールの記述について見てみよう。
ipBlock
CIDR表記を使って部分的なIPアドレスの範囲に対しての指定をする。指定できるフィールドは以下の通り。
cidr
: CIDR表記でIPアドレスの範囲を指定
except
: cidr
で指定した範囲内から除きたい範囲をCIDRで指定。 cidr
で指定した範囲の外部を指定すると拒否される
最初に出したManifestの例では以下の部分で使用されている。
1
2
3
4
|
ipBlock:
cidr: 10.2.0.0/16
except:
- 10.2.1.0/24
|
namespaceSelector
Namespaceに対してのLabelSelectorでNamespaceを選択する。指定方法はDeploymentなどのLabelSelectorと同様だ。
このフィールドが与えられたが空だった場合、全てのNamespaceが選択される。
最初に出したManifestの例では以下の部分で使用されている。
1
2
3
|
namespaceSelector:
matchLabels:
project: test-app
|
podSelector
Podに対してのLabelSelectorでPodを選択する。指定方法はDeploymentなどのLabelSelectorと同様だ。
このフィールドが与えられたが空だった場合、NetworkPolicyが属しているNamespaceの全てのPodが選択される。
最初に出したManifestの例では以下の部分で使用されている。
1
2
3
|
podSelector:
matchLabels:
role: frontend
|
namespaceSelectorとpodSelectorを組み合わせた指定
実は namespaceSelector
と podSelector
を組み合わせた指定が可能だ。(普通にAPIリファレンス追ってるだけだと気づけない)
通常通り記述すると以下のようになるはずだ。
1
2
3
4
5
6
|
- namespaceSelector:
matchLabels:
project: test-app
- podSelector:
matchLabels:
role: frontend
|
この設定は project=test-app
とマッチするNamespaceにある全てのPodとNetworkPolicyが属しているNamespaceのPodで role=frontend
とマッチするものが選択される。
しかし、このフィールドは一部のフィールドの組み合わせが許可されており、以下のような指定が可能だ。
1
2
3
4
5
6
|
- namespaceSelector:
matchLabels:
project: test-app
podSelector:
matchLabels:
role: frontend
|
なんとも分かりづらいが、 podSelector
のハイフンが消えて、1要素になっている。
この設定は project=test-app
とマッチするNamespaceにあるPodで role=frontend
とマッチするものが対象になる。
要はこの記述でNamespaceとPodを同時に指定できる。
ports
このフィールドに受信元や送信先についてのポート番号を指定する。
このフィールドを省略したり空で指定した場合は全てのポートが対象となる。また、複数指定があった場合はORを取って組み合わされる。
指定できるフィールドは以下の通り。
port
: ポートを指定。ポート名か番号で指定する。省略した場合は全てのポート名と番号が選択される
protocol
: プロトコルを指定。 TCP
/ UDP
/ SCTP
から指定する。デフォルトは TCP
だ。
基本的なポリシー
通常、NetworkPolicyは作成されていないため、全てのトラフィックが許可されている。
ここではNamespaceに対するネットワークのデフォルトポリシーとして使える基本的なNetworkPolicyの定義を見ていこう。
全ての受信トラフィックを拒否
全ての受信トラフィックを拒否するには以下のようなManifestになる。
1
2
3
4
5
6
7
8
|
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress
|
全ての受信トラフィックを許可
全ての受信トラフィックを許可するには以下のようなManifestになる。
1
2
3
4
5
6
7
8
|
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
spec:
podSelector: {}
ingress:
- {}
|
全ての送信トラフィックを拒否
全ての送信トラフィックを拒否するには以下のようなManifestになる。
1
2
3
4
5
6
7
8
|
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Egress
|
全ての送信トラフィックを許可
全ての送信トラフィックを許可するには以下のようなManifestになる。
1
2
3
4
5
6
7
8
9
10
|
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
spec:
podSelector: {}
egress:
- {}
policyTypes:
- Egress
|
全ての送受信トラフィックを拒否
全ての送受信トラフィックを拒否するには以下のようなManifestになる。
1
2
3
4
5
6
7
8
9
|
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
|
NetworkPolicyを使ってみる。
前準備
NetworkPolicyを使ってみる前に。実は今使用しているminikubeではNetworkPolicyが動作しない。
なぜ動作しないかは根深い話になるので割愛する。一旦現状の環境を作り直してNetworkPolicyが動くようにしよう。
以下のコマンドを実行し、minikubeの環境を削除する。
次に以下のコマンドを順に実行し、minikubeの環境を作成する。適宜CPUやMemoryの指定をしてほしい。(こちらを参照)
1
2
3
|
minikube start --network-plugin=cni --extra-config kubelet.network-plugin=cni --kubernetes-version v1.12.3
kubectl apply -f https://docs.projectcalico.org/v3.4/getting-started/kubernetes/installation/hosted/etcd.yaml
kubectl apply -f https://docs.projectcalico.org/v3.4/getting-started/kubernetes/installation/hosted/calico.yaml
|
完了したら実際にNetworkPolicyを使ってみよう。
NetworkPolicyを使う
さて、今回は通常でIngressを拒否するPolicyをあててみよう。
以下のManifestを適用する。
1
2
3
4
5
6
7
8
|
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress
|
1
2
|
$ kubectl apply -f default-deny.yaml
networkpolicy.networking.k8s.io/default-deny created
|
それではさくっとnginxのDeploymentと対応するService、それと別のターミナルで接続するためのAlpineのPodを実行しよう。
1
2
3
4
|
$ kubectl create deploy --image nginx nginx
deployment.apps/nginx created
$ kubectl expose deploy nginx --port 80
service/nginx exposed
|
1
2
3
|
$ kubectl run -it --rm alpine --image alpine --generator=run-pod/v1 ash
If you don't see a command prompt, try pressing enter.
/ #
|
起動したAlpineのPodからnginxにアクセスしてみよう。
デフォルトでIngressのトラフィックを拒否するルールを設定したため、接続できないはずだ。
1
2
3
|
/ # wget -T 1 -O - nginx
Connecting to nginx (10.108.165.92:80)
wget: download timed out
|
それでは今立ち上げているAlpineのコンテナからのアクセスを許可しよう。以下のようなManifestを作成する。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-alpine-to-nginx
spec:
podSelector:
matchLabels:
app: nginx
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
run: alpine
|
上記のManifestを適用してみる。
1
2
|
$ kubectl apply -f allow-alpine-to-nginx.yaml
networkpolicy.networking.k8s.io/allow-alpine-to-nginx created
|
さて、再度リクエストを飛ばしてみよう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
/ # wget -T 1 -O - nginx
Connecting to nginx (10.108.165.92:80)
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
- 100% |***************************************| 612 0:00:00 ETA
|
正しく接続することが出来た。試しに別のNamespaceを作成してそこのPodからリクエストを送ってみよう。
1
2
3
4
5
6
7
|
$ kubectl create ns network-policy-test
namespace/network-policy-test created
$ kubectl run -n network-policy-test -it --rm --image alpine --generator=run-pod/v1 alpine ash
If you don't see a command prompt, try pressing enter.
/ # wget -T 1 -O - nginx.default
Connecting to nginx.default (10.108.165.92:80)
wget: download timed out
|
接続できないことが分かる。それではこのコンテナから接続できるNetworkPolicyを作成してみよう。
以下のManifestを作成した。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-ns-alpine-to-nginx
spec:
podSelector:
matchLabels:
app: nginx
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
ns: network-policy-test
podSelector:
matchLabels:
run: alpine
|
そして先程作成したNamespaceにLabelを追加する。でないと namespaceSelector
で選択できないからだ。
以下のコマンドでLabelを追加することが出来る。
1
2
|
$ kubectl label ns network-policy-test ns=network-policy-test
namespace/network-policy-test labeled
|
それでは上記のManifestを適用しよう。
1
2
|
$ kubectl apply -f allow-from-ns-alpine-to-nginx.yaml
networkpolicy.networking.k8s.io/allow-from-ns-alpine-to-nginx created
|
さて、先程起動していた network-policy-test
のAlpineのPodから再度リクエストを飛ばしてみよう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
/ # wget -T 1 -O - nginx.default
Connecting to nginx.default (10.108.165.92:80)
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
- 100% |***************************************| 612 0:00:00 ETA
|
接続できるようになった 🎉
この様にNetworkPolicyでPodに対してのトラフィックを制御することが出来る。
というわけで今回はここまで。
次回はLabel / NodeSelector / Annotationについて見ていこう。
それでは。