이쿠의 슬기로운 개발생활

함께 성장하기 위한 보안 개발자 EverNote 내용 공유

클라우드/Kubernetes

38. Kubernetes Network Policy

이쿠우우 2020. 11. 7. 12:23
반응형

 

 

 

 

Kubernetes Network Policy

 

 

Network Policy 란?

 

Kubernetest에서 제공하는 일종의 방화벽 정책으로,

Pod가 서로 통신할 때 인바운드(Inbound traffic), 아웃바운드(Outbound traffic)에 대한 

설정을 할 수 있도록 해주는 정책임.

즉 Pod 방화벽 설정이라고 이해하면 됨.

 

Network Policy 는 

Inbound 정책에 해당하는 ingress 설정과

Outbound 정책에 해당하는 Egress 설정이 있음.

 

 

Network Policy Ingress 설정

Network Inbound 즉

외부에서 특정 Pod 내부로 들어오는 트래픽에 대한 방화벽 설정으로

어떠한 트래픽이 Pod로 들어오는 것을 허용할 것인지 설정함.

 

ipBlock 

특정 IP 대역만 트래픽이 Inbound 될 수 있도록 허용할 수 있음.

ipBlock에 설정된 대역만 허용이고 

그 외는 모두 차단. (except 옵션을 사용하면 차단 IP대역도 따로 설정가능)

IP대역 설정은 CIDR IP 대역으로 설정되야함.

 

[사이더(CIDR)란?]

사이더(Classless Inter-Domain Routing, CIDR)는

클래스 없는 도메인 간 라우팅 기법으로

1993년 도입되기 시작한, 최신의 IP 주소 할당 방법.

기존의 IP 주소 할당 방식이었던 A, B, C, D 4개의 Network Class를 대체함.

사이더는 IP 주소의 영역을 여러 네트워크 영역으로 나눌 때

기존의 Network Class 방식에 비해 유연성을 더해주어

Domain간 라우팅에 사용되는 인터넷 주소를 더욱 능동적으로 할당할 수 있게 됨.

 

podSelector

Pod에 설정되는 label을 이용한 설정.

특정 label을 가지고 있는 Pod들에서 들어오는 트래픽만 허용할 수 있음.

예를 들어 etcd Pod의 경우에는 kube-apiserver Pod로 부터 들어오는 

트래픽만 받는것과 같은 정책 정의가 가능함.

 

namespaceSelector 

namespace를 이용한 설정.

특정 namespace로 부터 들어오는 트래픽만 허용할 수 있음. 

 

Protocol & Port

특정 Protocol 또는 port로 설정된 트래픽만 들어오는 것을 허용할 수 있음.

 

 

 

Network Policy Egress 설정

Network Outbound 즉

특 Pod에서 밖으로 나가는 트래픽에 대한 방화벽 설정으로

어떠한 트래픽이 Pod로 부터 나가는 것을 허용할 것인지 설정함.

 

ipBlock 

특정 IP 대역만 트래픽이 Outbound 될 수 있도록 허용할 수 있음.

ipBlock에 설정된 대역만 허용이고 

그 외는 모두 차단.

IP대역 설정은 CIDR IP 대역으로 설정되야함.

 

Protocol & Port

특정 Protocol 또는 port로 설정된 트래픽만 나가는 것을 허용할 수 있음.

 

 

 

 

 


 

 

 

주의 : 사용중인 CNI가 Network Policy를 지원하지 않으면 사용불가.

 

오류 발생

Test환경에서는 Flannel CNI를 사용하고 있었음.

Flannel 환경에서 아무리 Network Policy를 설정해도 

Network Policy가 동작되지 않았음.

 

 

원인

선택한 네트워킹 솔루션(CNI)이 Network Policy 기능을 지원하지 않으면 ,

Cluster의 kube-apiserver에 Network Policy를 생성해도 아무 효과가 없다고 함.

 

결과

Test 환경은 Flannel CNI를 사용하고 있어서

Flannel CNI에서 해당 내용 확인했음

참고: https://github.com/coreos/flannel

Flannel is focused on networking. For network policy, other projects such as Calico can be used.

 

즉 Flannel은 Networking 중점의 CNI Addon임. Network Policy를 지원하지 않음.

CNI 중에 Networking과 Network Policy 이 2가지를 모두 지원하는 CNI를 사용해야함.

 

 

Networking 과 Network Policy 를 지원하는 CNI 찾음.

 

특정 CNI는 Network Policy를 지원해도 Ingress 또는 Egress 둘 둥 하나만 지원하는 경우가 있음

사용 편의를 위해서는 Network Policy 를 지원하더라도 Ingress, Egress 를 모두 지원하는 CNI를 사용하는것이 좋음.

그림참고 :  https://itnext.io/benchmark-results-of-kubernetes-network-plugins-cni-over-10gbit-s-network-36475925a560

 

그림에 나와있는바와같이 Flannel의 경우 Network Policy 를 지원하지 않는다.

 

Networking을 지원하면서 Ingress, Egree Network Policy를 지원하는 CNI로는 Calico, Canal, Cilum 이 있음.

 

Test에는 해당 목록 중 Calico 를 선택함.

Public Cloud 환경에서 kubernetes를 사용할 시 

AWS, GCE, Azure에서 제공하는 Networking 솔루션을 사용해야함.

각각의 Public Cloud 환경에서 제공하는 Networking 솔루션도 Network Policy 기능을 ON 설정해서 

Network Policy 기능을 사용할 수도 있지만 

성능 또는 환경에 따라서 Networking은 Public Cloud에서 제공하는 것으로 사용하고

Network Policy의 경우 별도의 Addon을 사용해야하는 경우가 있음.

 

Calico의 경우 Networking은 별도의 CNI를 사용하고 

Network Policy 기능만 Calico를 사용할 수 있도록 설정할 수 있음.

 

Test 환경의 경우 Flannel을 사용하고 있는데 

Networking 은 Flannel로 사용하고 

Network Policy은 Calico로 사용할 수 있음.

위와 같이 Flannel도 사용하고 Calico도 사용하는 방법을

Canal이라는 Addon을 제공하고 있음.

 

[Flannel 과 Calico 의 차이점 및  Canal 분석 글 참고]

https://neuvector.com/network-security/advanced-kubernetes-networking/

 

 


 

 

 

 

Canal 설치

 

Install Calico for policy and flannel (aka Canal) for networking

 

Canal은 Flannel과 Calico를 통합하여 Networking및 Network Policy를 제공함.

Canel = Flannel + Calico

 

1. 기존의 Flannel 삭제

 

기존의 Flannel을 유지한 상태로 Canal을 설치 시도 했지만

다양한 오류가 발생해서

일단은 Flannel을 삭제하고 진행함.

예상으로는 기존에 사용하던 Flannel version이 낮아서 문제가 발생한것 같기도함.

 

[명령어]

kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

 

 

2. 모든 kubernetes Node docker restart

 

master node 를 포함한 모든 worker node의

docker를  restart 해줘야함

[명령어]

service docker restart

 

 

 

3. DataStore 종류 선택.

 

Calico 설치 방법은 Datastore에 종류에 따라서 etcd, kubernetes API Datastore 2가지로 나누어 짐.

Canal 설치 시에서도 DataStore를 선택해줘야함.

 

etcd 

for direct connection to an etcd cluster

 

[장점]

1. 추가 DataStore가 필요하지 않으므로 관리가 더 간단함.

2. Kubernetes RBAC를 사용하여 Calico 리소스에 대한 액세스를 제어 할 수 있음.

3. Kubernetes audit logging을 사용하여 Calico 리소스 변경에 대한 audit logging를 생성 할 수 있음.

 

 

kubernetes API Datastore

for connection to a Kubernetes API server

 

[장점]

1. 비 Kubernetes 플랫폼 (예 : OpenStack)에서 Calico를 실행할 수 있음.

2. Kubernetes와 Calico 리소스 간의 문제를 분리 할 수 있음

3. Calico Cluster를 실행할 수 있음.

 

예제 환경에서는 kubernetes API Datastore으로 설치해보겠음.

 

 

4. Kube-Controller 모듈 Flag 설정

 

설정을 해야하지만 kubernetes 로컬 설치 과정에서 이미 했기 때문에 생략함.

참고 : 03. Kubernetes 로컬설치, 환경 예제 (Master Node 클러스터 구성 부분)

 

[명령어]

kubeadm init --pod-network-cidr=<your-pod-cidr>

 

5. Canal 설치 용 yaml파일을 Download

[명령어]

curl https://docs.projectcalico.org/manifests/canal.yaml -O

 

 

6. Canal 설치

[명령어]

kubectl apply -f canal.yaml

 

 

 

7. Flannel 설치

[명령어]

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

 

8. 모든 kubernetes Node docker restart

 

master node 를 포함한 모든 worker node의

docker를  restart 해줘야함

[명령어]

service docker restart

 

 

9. Canal 설치 확인

결과를 확인해보면 기존에 설치되어있던 Flannel 이 그대로 있으면서

Calico 가 추가된 것을 확인 할 수 있음.

 

[명령어]

kubectl get all -n kube-system

 

 

 

 


 

 

 

Network Policy 실습

 

 

참고) 환경

 

Master Node server

 OS = CentOS 7

 리눅스 커널 버전 : Linux 3.10.0-1062.el7.x86_64

 docker version : 1.13.1

 api verison : 1.26

 

Worker Node server

 OS = CentOS 7

 리눅스 커널 버전 : Linux 3.10.0-1062.el7.x86_64

 docker version : 1.13.1

 api verison : 1.26

 

Kubernetes version

 1.18

 

 


 

 

 

0. Test에 사용할 Pod, Service 생성

 

[Test에 사용한 Tomcat Pod]

apiVersion: v1

kind: Pod

metadata:

  name: iksoon-pod-tomcat

  labels:

    app: tomcat

    network: iksoon-policy

spec:

  containers:

  - name: iksoon-tomcat

    image: peksoon/iksoon_tomcat:1.0.6

    ports:

    - containerPort: 8080

 

 

[Test에 사용한 MySQL Pod]

apiVersion: v1

kind: Pod

metadata:

  name: iksoon-pod-mysql

  labels:

    app: mysql

spec:

  containers:

  - name: iksoon-mysql

    image: peksoon/iksoon_mysql:1.0.2

    ports:

    - containerPort: 3306

 

 

 

 


 

1. Ingress ipBlock 설정 Test

 

상황 예제 

cidr 10.244.0.0/24 대역만 Tomcat Pod에 접근 가능

 

 

Network Policy 적용 전 상태.

Mysql Pod에서 Tomcat Pod로 curl 요청 시 정상적으로 Page를 받아옴.

 

 

Network Policy 적용

예제 networkPolicy.yaml ]

apiVersion: networking.k8s.io/v1

kind: NetworkPolicy

metadata:

  name: test-network-policy

spec:

  podSelector:

    matchLabels:

      network: iksoon-policy

  policyTypes:

  - Ingress

  ingress:

  - from:

    - ipBlock:

        cidr: 10.244.0.0/24

 

 

Network Policy 적용 후 결과

MySQL Pod는 10.244.1.0/24 대역이여서

Network policy에 설정된 10.244.0.0/24 대역에 일치하지 않음.

MySQL Pod에서 Tomcat Pod로 curl 요청 시 Tomcat Pod에 접근하지 못해서

결과를 받아오지 못함.

 

ipBlock 을 10.244.1.0/24로 설정하면

MySQL Pod에서 Tomcat Pod로 curl 요청 가능해짐.

 

 

 

 

 


 

 

 

2. Ingress PodSelector 설정 Test

상황 예제 

app: mysqltest Label을 가지고 있는 pod 만 Tomcat Pod에 접근 가능

 

 

Network Policy 적용 전 상태.

 

Mysql Pod에서 Tomcat Pod로 curl 요청 시 정상적으로 Page를 받아옴.

 

 

Network Policy 적용

예제 networkPolicy.yaml ]

apiVersion: networking.k8s.io/v1

kind: NetworkPolicy

metadata:

  name: test-network-policy

spec:

  podSelector:

    matchLabels:

      network: iksoon-policy

  policyTypes:

  - Ingress

  ingress:

  - from:

    - podSelector:

        matchLabels:

          app: mysqltest

 

 

Network Policy 적용 후 결과

MySQL Pod에 app: mysqltest Label이 없음으로

MySQL Pod에서 Tomcat Pod로 curl 요청 시 Tomcat Pod에 접근하지 못해서

결과를 받아오지 못함.

 

 

 


 

 

 

 

3. Ingress namespaceSelector 설정 Test

 

상황 예제 

app: namespace-selector-test Label을 가지고있는 namespace에 생성된 pod 만 Tomcat Pod에 접근 가능

 

환경 구성

 

[namespace 생성]

kubectl create namespace test-ns

kubectl label namespace/test-ns app=namespace-selector-test

 

[test-ns namespace에 Pod 생성]

 

[Test에 사용한 MySQL Pod]

apiVersion: v1

kind: Pod

metadata:

  name: iksoon-pod-mysql-nstest

  namespace: test-ns

  labels:

    app: mysql

spec:

  containers:

  - name: iksoon-mysql

    image: peksoon/iksoon_mysql:1.0.2

    ports:

    - containerPort: 3306

 

 

 

Network Policy 적용 전 상태.

default namespace에 생성되어있는 

Mysql Pod에서 Tomcat Pod로 curl 요청 시 정상적으로 Page를 받아옴.

 

test-ns namespace에 생성되어있는 

Mysql Pod에서 Tomcat Pod로 curl 요청 시 정상적으로 Page를 받아옴.

 

Network Policy 적용

 

예제 networkPolicy.yaml ]

apiVersion: networking.k8s.io/v1

kind: NetworkPolicy

metadata:

  name: test-network-policy

spec:

  podSelector:

    matchLabels:

      network: iksoon-policy

  policyTypes:

  - Ingress

  ingress:

  - from:

    - namespaceSelector:

        matchLabels:

          app: namespace-selector-test

 

 

 

Network Policy 적용 후 결과

 

default namespace에 생성되어있는

MySQL Pod에서는 Tomcat Pod로 curl 요청 시 

default namespace에 app: namespace-selector-test 설정이 안되어 있어서

결과를 받아오지 못함.

 

test-ns namespace에 생성되어있는

MySQL Pod에서는 Tomcat Pod로 curl 요청 시 

test-ns namespace에 app: namespace-selector-test 설정이 되어있어서

tomcat pod에 접근할 수 있음

 


 

4. Ingress Protocol, Port 설정 Test

 

상황 예제 

Tomcat Pod는 8080으로 접근이 가능한데

network policy로 8081만 접근 가능하도록 설정하면

접근이 안되는지 확인

 

 

Network Policy 적용 전 상태.

Mysql Pod에서 Tomcat Pod로 curl 요청 시 8080 port로 Page를 받아옴.

 

 

Network Policy 적용

 

예제 networkPolicy.yaml ]

apiVersion: networking.k8s.io/v1

kind: NetworkPolicy

metadata:

  name: test-network-policy

spec:

  podSelector:

    matchLabels:

      network: iksoon-policy

  policyTypes:

  - Ingress

  ingress:

  - ports:

    - protocol: TCP

       port: 8081

 

 

 

Network Policy 적용 후 결과

Tomcat Pod에 8081 Port로만 접근이 가능해서 

MySQL Pod에서 Tomcat Pod로 8080 port curl 요청 시 Tomcat Pod에 접근하지 못해서

결과를 받아오지 못함.

Port설정을 8080으로 하면 정상적으로 받아옴.

 

 


 

 

 

5. Egress ipBlock 설정 Test

 

상황 예제 

MySQL Pod에 cidr 10.244.0.0/24 대역로만 트래픽을 보낼 수 있도록 설정하면

10.244.1.0/24로 설정되어 있는 Tomcat Pod 트래픽을 못보내는지 확인

 

 

Network Policy 적용 전 상태.

 

Mysql Pod에서 Tomcat Pod로 curl 요청 시 정상적으로 Page를 받아옴.

 

 

Network Policy 적용

 

Mysql Pod에 network policy를 적용하도록 설정.

예제 networkPolicy.yaml ]

apiVersion: networking.k8s.io/v1

kind: NetworkPolicy

metadata:

  name: test-network-policy

spec:

  podSelector:

    matchLabels:

      app: mysql

  policyTypes:

  - Egress

  egress:

  - to:

    - ipBlock:

        cidr: 10.244.0.0/24

 

 

 

Network Policy 적용 후 결과

 

MySQL Pod에 cidr 10.244.0.0/24 대역로만 트래픽을 보낼 수 있도록 설정하면

10.244.1.0/24로 설정되어 있는 Tomcat Pod로 트팩을 보낼 수 없음

Mysql Pod는 Tomcat Pod로 curl 요청을 하지 못함.

 

 

 

 


 

 

6. Egress Protocol, Port 설정 Test

 

상황 예제 

Tomcat Pod는 8080으로 접근이 가능.

MySQL Pod에 Egress network policy로 8081 Port만 트래픽이 나갈 수 있도록 설정하면

Tomcat Pod로 curl 요청이 가능한지 확인

 

 

Network Policy 적용 전 상태.

Mysql Pod에서 Tomcat Pod로 curl 요청 시 8080 port로 Page를 받아옴.

 

 

Network Policy 적용

Mysql Pod에 network policy를 적용하도록 설정.

예제 networkPolicy.yaml ]

apiVersion: networking.k8s.io/v1

kind: NetworkPolicy

metadata:

  name: test-network-policy

spec:

  podSelector:

    matchLabels:

      app: mysql

  policyTypes:

  - Egress

  egress:

  - ports:

    - protocol: TCP

      port: 8081

 

 

 

Network Policy 적용 후 결과

MySQL Pod에 Egress network policy로 8081 Port만 트래픽이 나갈 수 있도록 설정되어서

Tomcat Pod 8080 Port로 curl 요청이 불가능함.

 

Port설정을 8080으로 하면 정상적으로 받아옴.

 

 

 

 

 

 

 

 

 


 

7. Network Policy 전체 스키마 (참고용)

 

예제 networkPolicy.yaml ]

apiVersion: networking.k8s.io/v1

kind: NetworkPolicy

metadata:

  name: test-network-policy

  namespace: default

spec:

  podSelector:

    matchLabels:

      network: iksoon-policy

  policyTypes:

  - Ingress

  - Egress

  ingress:

  - from:

    - ipBlock:

        cidr: 172.17.0.0/16

        except:

        - 172.17.1.0/24

    - namespaceSelector:

        matchLabels:

          project: myproject

    - podSelector:

        matchLabels:

          app: mysql

    ports:

    - protocol: TCP

      port: 8080

  egress:

  - to:

    - ipBlock:

        cidr: 10.0.0.0/24

    ports:

    - protocol: TCP

      port: 5978

 

 

 

 


제 글을 복사할 시 출처를 명시해주세요.
글에 오타, 오류가 있다면 댓글로 알려주세요! 바로 수정하겠습니다!


 

 

 

 

 

 

[Network policy 참고]

https://kubernetes.io/ko/docs/tasks/administer-cluster/declare-network-policy/

https://kubernetes.io/ko/docs/concepts/services-networking/network-policies/

https://docs.projectcalico.org/security/kubernetes-network-policy

https://bcho.tistory.com/1274

 

[Network policy 예제 참고]

https://github.com/ahmetb/kubernetes-network-policy-recipes

 

 

[Calico 참고]

https://docs.projectcalico.org/getting-started/kubernetes/

https://docs.projectcalico.org/getting-started/kubernetes/hardway/the-calico-datastore

 

 

 

[각 종 CNI Addon 비교]

https://itnext.io/benchmark-results-of-kubernetes-network-plugins-cni-over-10gbit-s-network-36475925a560

 

 

 

 

 

 

 

 

반응형