Cloud/Kubernetes

Kubernetes NetworkPolicy 란?

Taemy 2020. 12. 26. 16:31

이번 포스팅은 아래 Docs의 내용을 간단하게 정리해보았다.

kubernetes.io/docs/concepts/services-networking/network-policies/

 

Network Policies

If you want to control traffic flow at the IP address or port level (OSI layer 3 or 4), then you might consider using Kubernetes NetworkPolicies for particular applications in your cluster. NetworkPolicies are an application-centric construct which allow y

kubernetes.io

NetworkPolicy란

 Kubernetes 구성 자체가 쉽지 않기 때문에 아무래도 마지막에 건드리게 되면서 제일 신경 많이 써야할 것이 Security 부분이 아닐까 한다.

 Security 관련해서 포스팅하면 1편으로 끝나지 않기 때문에 각설하고, 신경쓸 수 있는 항목을 잘 꼽아보면 Pod에 접근할 수 있는 다른 Pod나 Host 목록을 관리하는 것도 하나의 Security 측면의 제어가 될 수 있다.

 

이 NetworkPolicy는 이름 그대로 Pod 내부로 들어오거나(Ingress) 외부로 나가는(Egress) 트래픽을 허용하고 거부하는  정책을 설정할 수 있는 오브젝트다. 

 

 NetworkPolicy는 기본적으로 Whitelist 형식이다. 따라서 설정되는 순간 명시해놓은 목록에 있는 Pod나 Host(다른 노드일 수도 있고 다른 IP를 가진 Source일 수도 있고) 외에는 이 Pod에 트래픽을 보낼 수가 없다. 

 

 트래픽 제어 부분이기 때문에 당연히 CNI 를 사용하는 것을 전제로 한다(물론 CNI를 사용안하는 플랫폼이 있는지는 의문이지만). 없이도 설정되지만 효과는 없다.

 

특징

1) NetworkPolicy는 namespace 단위 자원이다. 따라서 kubectl get networkpolicy 명령을 치면 Namespace별로 자원이 출력되고, 적용도 Namespace 내에 있는 Pod에만 된다. 여러 Namespace에 걸져 Pod가 있다면 여러 NetworkPolicy를 적용해줘야 한다.

$ kubectl get networkpolicy 
No resources found in default namespace. 

2) 여러 개가 존재하면 중복 적용된다. whitelist 구성이기 때문에 당연한 소리처럼 들릴 수 있겠지만, 192.168.1.2를 허용하는 NetworkPolicy와 192.168.1.3을 허용하는 NetworkPolicy가 한 Pod에 적용된다면 둘 중 하나만 적용하는 것이 아니라 192.168.1.2, 192.168.1.3을 모두 허용하게 된다. 

 아무리 NetworkPolicy 하나가 기가 막히게 트래픽을 통제해도 다른 NetworkPolicy에 헛점이 있다면 무용지물이 된다. 따라서 NetworkPolicy는 항상 최소한의 Pod 혹은 Host 만 트래픽을 흘릴 수 있도록 작성해야 한다. 물론 테스트가 다 끝나고 어떤 Pod들과 통신하는지 사전 논의가 충분히 된 상태에서 (혹은 테스트가 끝난 상태에서) 사용해야 함을 잊지 말자.

 

3) sctp 를 지원한다. 1.19버전이후로는 Default로 sctp support 옵션으로 들어가있기 때문에 상관할 필요가 없고, 이전 버전이라면 FeatureGate 옵션을 켜줘야 한다.

 

예시

아래 공식 문서 예시를 보자.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

 ingress와 egress 항목 아래에 있는 내용들이 통신가능한 객체(이하 entity)들이다. Pod, Namespace, IPBlock의 3가지 타입으로 제어가 가능하다.

 

podSelector

 이 NetworkPolicy가 적용될 파드를 선택한다. 예시에서는 matchLabels로 role:db를 가진 파드들에 이 NetworkPolicy가 적용도되록 했다. 이 항목을 {}로 비우면 Namespace내의 모든 파드에 적용된다.

 

policyTypes

 적용될 트래픽 방향을 설정한다. 기본이 Ingress이고 안적어놓더라도 아래 egress 항목을 작성하면 자동으로 Egress도 추가된다. 이 항목이 굳이 있는 이유는 Ingress나 Egress를 안적어 놓으면 모든 트래픽을 거부할 수 있기 때문이다.

반대로 Ingress나 Egress에 {}로 비워놓으면, 모든 트래픽을 허용할 수 있기 때문이다. 

 

ingress, egress

 들어올 수 있는 Source를 제한하거나 나갈 수 있는 Destination을 제한한다. 각각 from과 to로 구별된다.

 

 ipBlock: 들어올 수 있는 ip블록을 제한한다. cidr항목에 제한할 대역을 작성하고, 예외가 있다면 except로 제한한다. 위에서는 172.17.0.0/16대역을 제한하고 172.17.1.0/24을 제한했다.

 따라서 172.17.2.4, 172.17.100.6 등은 트래픽이 들어올 수 있고 172.17.1.5 같은 ip를 가진 entity는 못들어온다.

 

 namespaceSelector, podSelector: 각각 Namespace와 Pod에 대해서 Label 기반으로 들어올 수 있는 Pod나 Namespace를 제어한다. 예를 들어 위에서는 project: myproject로 되어있는데, 심플하게

$ kubectl get ns --show-labels
NAME                          STATUS   AGE   LABELS
namespaceA                    Active   24d   <none>
namespaceB                    Active   24d   project=myproject

namespaceB에 있는 Pod에서 온 트래픽은 받고 namespaceA에 있는 Pod에서 트래픽은 안받는다.

$ kubectl get po --show-labels
NAME                        READY   STATUS    RESTARTS   AGE   LABELS
pod-a                       1/1     Running   0          24d   role=frontend
pod-b                       1/1     Running   0          24d   role=backend

pod-a에서 온 트래픽은 받고  pod-b에서 온 트래픽은 안받는다.

 

중요한 것은 이 두개가 AND 조건으로 적용될 수 있다. 따라서 특정 Namespace의 특정 Pod에서 온 트래픽만 받을 수도 있다. 구별 하는건 -가 있느냐 없느냐다.

 

이 경우는 OR 조건이다.

    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend

 

이 경우는 AND 조건이다.

    - namespaceSelector:
        matchLabels:
          project: myproject
      podSelector:
        matchLabels:
          role: frontend

 

 ports: 위에서 제어한 Source나 Destination이 어떤 Port로 나가고 들어올 수 있는지 정의하는 항목이다.

 

 

제한 사항

NetworkPolicy는 아직 완벽하지는 않고 아직 여러 제약이 많은 기능이다. 감안하고 사용하자.

 

1) TLS 관련 기능이 없다.

2) 노드 단위 설정이 안된다.

3) 한번에 여러 포트 설정이 안된다.

4) Blacklist 기반으로 설정 변경

5) Audit 관련 기능은 없음 - 이 부분은 falco 같은 다른 툴셋으로 해결하자 

 

'Cloud > Kubernetes' 카테고리의 다른 글

Admission Control  (0) 2021.07.27
Istio를 알아보자 - 1. 기본 항목 구성  (0) 2020.12.13
Pod 라우팅과 ExternalTrafficPolicy 옵션  (3) 2020.11.23