client-server구조에서 client가 web server에 요청을 보내어 traffic이 server안으로 들어오는 것을 ingress
라고 한다.
반대로 server에서 client로 보내는 traffic을 egress
라고 한다.
kubernetes cluster는 하나의 private network망으로, 내부의 각 pod들끼리의 통신을 지향한다. 즉, 내부의 모든 pod들은 각 pod들과 통신이 가능한데, 이를 All Allow방식이라고 한다. 문제는 이를 원치않는 pod가 있을 수 있다는 것이다.
가령, database의 경우 port 3306을 통해서 요청이 들어오면 data를 전달해주는데, 특정 api pod만 받고, 다른 pod의 요청은 무시하고싶다고 하자. 이를 위해서 하나의 policy를 새우는 것인데, 우리의 경우 database pod의 3306
port로 오는 ingress중에서 api pod만을 받도록 하자고 policy를 세우는 것이다.
그럼 어떻게 이 policy를 pod에 부여할 수 있을까?? 이는 service와 pod의 방식처럼 label과 label selector를 이용한다.
pod가 다음의 label을 가진다고 하자.
labels:
role: db
network policy는 다음의 label selector로 pod를 지정할 수 있다.
podSelector:
matchLabels:
role: db
role: db
라는 라벨을 가진 pod에 해당 network policy가 적용되는 것이다.
이제 network policy를 만들어보도록 하자. network policy는 다음의 rule을 가진다.
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
name: api-pod
ports:
- protocol: TCP
port: 3306
위의 rule은 api-pod
라는 라벨을 가진 pod에 대해서만 ingress로 3306 포트만 허용하겠다는 것이다. 단, policyTypes
가 Ingress
만 있으니 ingress만 적용되고 egress에 대해서는 적용되지 않는다. 따라서, 모든 egress에 대해서는 자유롭게 통신이 가능하다. 만약 egress
역시도 추가하고 싶다면 policyTypes
에 추가하면 된다.
이제 완전한 NetworkPolicy
를 만들어보도록 하자.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-policy
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
name: api-pod
ports:
- protocol: TCP
port: 3306
단, NetworkPolicy
는 kube-router
, calico
, Romana
, Weave-net
과 같은 CNI에서는 제공하지만 Flannel
에서는 제공하지 않는다.
특정 pod뿐만 아니라 namespace
로 지정할 수도 있다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-policy
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: prod
ports:
- protocol: TCP
port: 3306
prod
namespace에서의 모든 pod들에 대해서 db
pod에 대한 3306 ingress 요청을 허용하겠다는 것이다.
ip로도 from
을 설정할 수 있는데, 다음과 같다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-policy
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
ingress:
- from:
- ipBlock:
cidr: 192.168.5.10/32
ports:
- protocol: TCP
port: 3306
192.168.5.10/32
규칙을 만족하는 pod에 대해서만 3306 port ingress를 받겠다는 것이다.
만약 위의 podSelector
, namespaceSelector
, ipBlock
을 같이 쓴다면 하나의 and조건처럼 사용된다.
참고로 ingress는 from
을 쓰지만 egress
는 to
를 쓴다. 또한, policyTypes
에 Egress
를 추가해야한다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-policy
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
name: api-pod
ports:
- protocol: TCP
port: 3306
egress:
- to:
- ipBlock:
cidr: 192.168.5.10/32
ports:
- protocol: TCP
port: 80
192.168.5.10/32
cidr를 만족하는 pod에 대해서 80 port egress를 허용한다는 것이다. 즉, db server가 192.168.5.10/32
cidr를 만족하는 pod에 대해서 80 port로 데이터를 보내는 것을 허용한다는 것이다.
마지막으로 DNS서비스를 이용하기 위해서 egress
에 kube-dns
의 port
들을 모두 열고, 다른 mysql
, payroll
pod에 egress요청을 보내는 코드를 확인해보도록 하자.
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 61m
53/UDP
, 53/TCP
이므로 DNS
서비스를 이용하기 위해 egress
network policy를 설정하도록 하자.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: internal-policy
spec:
podSelector:
matchLabels:
name: internal
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
name: mysql
ports:
- protocol: TCP
port: 3306
- to:
- podSelector:
matchLabels:
name: payroll
ports:
- protocol: TCP
port: 8080
- ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP