Kubernetes node ports에 Calico 정책 적용하기
Calico Open Source GlobalNetworkPolicy를 호스트 엔드포인트에 적용해 Kubernetes NodePort 서비스에 대한 접근을 제한하는 방법을 안내해요.
출처: 문서
본문
큰 그림
node port에 대한 접근을 특정 외부 클라이언트로 제한해요.
가치
node port를 사용해 외부 클라이언트에 서비스를 노출하는 것은 표준 Kubernetes 기능이에요. 하지만 node port에 대한 접근을 특정 외부 클라이언트로 제한하려면 Calico 글로벌 네트워크 정책을 사용해야 해요.
개념
preDNAT 필드가 있는 네트워크 정책
Kubernetes 클러스터에서 kube-proxy는 노드의 포트와 IP 주소로 들어온 요청을 서비스를 뒷받침하는 파드 중 하나로 DNAT해요. Calico 글로벌 네트워크 정책이 정상적인 ingress 클러스터 트래픽은 허용하면서 다른 일반 ingress 트래픽은 거부하려면, DNAT 이전에 적용되어야 해요. 이를 위해 Calico 글로벌 네트워크 정책에 preDNAT 필드를 추가하기만 하면 돼요. preDNAT 필드는:
- DNAT 이전에 적용돼요
- ingress 규칙에만 적용돼요
- 목적지에 관계없이 모든 ingress 트래픽을 호스트 엔드포인트를 통해 적용해요. 목적지는 로컬에서 호스팅되는 파드, 다른 노드의 파드, 또는 호스트에서 실행 중인 프로세스일 수 있어요.
시작하기 전에...
외부 클라이언트에 노출하려는 서비스는 유형이 NodePort인 Kubernetes 서비스로 구성하세요.
방법
Kubernetes 서비스를 외부 클라이언트에 안전하게 노출하려면 다음 단계를 모두 구현해야 해요.
- 클러스터 ingress 트래픽은 허용하고 일반 ingress 트래픽은 거부하기
- 로컬 호스트 egress 트래픽 허용하기
- 적절한 네트워크 정책으로 호스트 엔드포인트 만들기
- 특정 node ports로의 ingress 트래픽 허용하기
클러스터 ingress 트래픽은 허용하고 일반 ingress 트래픽은 거부하기
다음 예시에서는 클러스터 ingress 트래픽을 허용하는 글로벌 네트워크 정책(allow-cluster-internal-ingress)을 만들어요: 노드 IP 주소(1.2.3.4/16)와 Kubernetes가 할당한 파드 IP 주소(100.100.100.0/16)를 대상으로 해요. preDNAT 필드를 추가하면 Calico 글로벌 네트워크 정책이 Kubernetes 클러스터의 일반 DNAT보다 먼저 적용돼요.
이 예시에서는 **selector: has(kubernetes-host)**를 사용해 kubernetes-host 라벨이 있는 엔드포인트에 정책이 적용되도록 해요 (특정 노드를 지정하는 것도 쉽게 할 수 있어요).
마지막으로 preDNAT 필드를 지정할 때는 applyOnForward: true 필드도 함께 추가해야 해요.
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: allow-cluster-internal-ingress-only
spec:
order: 20
preDNAT: true
applyOnForward: true
ingress:
- action: Allow
source:
nets: [1.2.3.4/16, 100.100.100.0/16]
- action: Deny
selector: has(kubernetes-host)
로컬 호스트 egress 트래픽 허용하기
각 노드의 외부 인터페이스를 통과하는 egress 트래픽을 허용하는 글로벌 네트워크 정책도 필요해요. 그렇지 않으면 해당 인터페이스에 호스트 엔드포인트를 정의했을 때 로컬 프로세스의 egress 트래픽이 전혀 허용되지 않아요 (Failsafe 규칙이 허용하는 트래픽 제외).
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: allow-outbound-external
spec:
order: 10
egress:
- action: Allow
selector: has(kubernetes-host)
적절한 네트워크 정책으로 호스트 엔드포인트 만들기
이 예시에서는 클러스터에 적합한 네트워크 정책과 함께 Calico 호스트 엔드포인트를 이미 정의했다고 가정해요. (예를 들어 "이 호스트를 드나드는 모든 트래픽 기본 거부" 네트워크 정책을 가진 호스트 엔드포인트는 특정 트래픽을 허용/거부한다는 목표에 어긋나기 때문에 원하지 않을 거예요.) 도움이 필요하면 호스트 엔드포인트를 참고하세요.
앞서 정의한 모든 글로벌 네트워크 정책은 kubernetes-host 라벨이 있는 엔드포인트에 적용되는 셀렉터를 갖고 있어요. 그래서 정의에 그 라벨을 포함할 거예요. 예를 들어 node1의 eth0을 위한 정의예요.
apiVersion: projectcalico.org/v3
kind: HostEndpoint
metadata:
name: node1-eth0
labels:
kubernetes-host: ingress
spec:
interfaceName: eth0
node: node1
expectedIPs:
- INSERT_IP_HERE
호스트 엔드포인트를 만들 때 INSERT_IP_HERE를 eth0의 IP 주소로 교체하세요. ingress나 egress 규칙의 셀렉터가 호스트 엔드포인트를 제대로 매칭하려면 expectedIPs 필드가 필요해요.
특정 node ports로의 ingress 트래픽 허용하기
이제 preDNAT 필드가 있는 글로벌 네트워크 정책을 만들어 node port에 대한 외부 접근을 허용할 수 있어요. 이 예시에서는 port: 31852가 있는 모든 호스트 엔드포인트에 대해 ingress 트래픽이 허용돼요.
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: allow-nodeport
spec:
preDNAT: true
applyOnForward: true
order: 10
ingress:
- action: Allow
protocol: TCP
destination:
selector: has(kubernetes-host)
ports: [31852]
selector: has(kubernetes-host)
NodePort를 특정 노드를 통해서만 접근 가능하게 만들려면 노드에 특정 라벨을 붙이세요. 예를 들면:
nodeport-external-ingress: true
그다음 has(kubernetes-host) 대신 nodeport-external-ingress: true를 allow-nodeport 정책의 셀렉터로 사용해요.
추가 리소스
더 알아보기 (Learn more)
핵심은 preDNAT 필드예요. kube-proxy의 DNAT 이전에 정책을 적용해야 node port로 들어오는 트래픽을 원본 목적지 기준으로 제어할 수 있고, 이때 applyOnForward: true가 항상 짝으로 필요해요. 일반 ingress 차단 정책과 특정 nodePort 허용 정책의 순서(order) 조합도 기억하세요.