8.4.5 [실습] 특정 네임스페이스/파드 간의 통신 제한 설정
이론으로 네트워크 폴리시(Network Policy)의 필요성과 동작 원리, 그리고 규칙을 정의하는 방법을 자세히 살펴보았습니다. 이제는 직접 네트워크 폴리시를 생성하고 적용하여, 파드(Pod) 간의 통신을 실제로 제어해보는 실습을 진행할 차례입니다! 이번 실습에서는 먼저 특정 네임스페이스에 “기본적으로 모든 트래픽을 차단하는(Default Deny)” 정책을 설정한 후, 이어서 특정 레이블을 가진 파드에서만 다른 특정 파드로의 접근을 선택적으로 허용하는 정책을 추가로 생성해 볼 것입니다. 그리고 마지막으로 간단한 통신 테스트를 통해 우리가 정의한 네트워크 폴리시가 의도한 대로 잘 적용되어 통신이 차단되거나 허용되는지를 눈으로 직접 확인할 것입니다.
본 실습을 진행하기 위해서는 이전 실습들과 마찬가지로 쿠버네티스 클러스터와 kubectl CLI가 준비되어 있어야 합니다. 가장 중요한 전제 조건은, 현재 사용 중인 쿠버네티스 클러스터에 네트워크 폴리시 기능을 지원하는 CNI(Container Network Interface) 플러그인(예: Calico, Cilium, Weave Net 등)이 반드시 설치되고 활성화되어 있어야 한다는 점입니다. 만약 K3s를 기본 설정으로 사용 중이라면 Flannel CNI가 설치되어 있어 네트워크 폴리시가 동작하지 않을 수 있으므로, Calico와 같은 CNI로 변경하거나 네트워크 폴리시를 지원하는 환경을 별도로 준비해야 합니다. (일부 K3s 버전이나 설정에서는 Flannel과 함께 Canal 등을 통해 제한적인 폴리시 지원이 있을 수도 있으나, 확실한 테스트를 위해서는 Calico 사용을 권장합니다.)
자, 그럼 쿠버네티스 네트워크의 문지기, 네트워크 폴리시를 직접 설정하여 우리 클러스터의 보안을 한층 강화해 볼까요?
8.4.5.1 기본 Deny 정책 설정
네트워크 보안의 가장 좋은 출발점 중 하나는 “최소 권한의 원칙”에 따라, “기본적으로 모든 것을 차단하고, 필요한 것만 명시적으로 허용”하는 것입니다. 네트워크 폴리시를 사용하여 이러한 “기본 거부(Default Deny)” 전략을 특정 네임스페이스에 적용해 보겠습니다.
1단계: 테스트용 네임스페이스 생성
2단계: 테스트용 애플리케이션 배포 (서버 및 클라이언트 역할)
이 네임스페이스 안에 간단한 웹 서버 역할을 할 Nginx 파드(서버 역할)와, 이 서버에 접속을 시도할 유틸리티 파드(클라이언트 역할, 예: busybox)를 각각 디플로이먼트를 통해 배포하겠습니다.
nginx-server-deployment.yaml (서버 역할):
busybox-client-deployment.yaml (클라이언트 역할):
터미널에서 다음 명령어로 배포합니다.
잠시 후 kubectl get pods -n network-policy-test 명령으로 두 파드가 모두 Running 상태인지 확인합니다. 또한, nginx-server 파드의 IP 주소를 확인해 둡니다 (예: kubectl get pods -n network-policy-test -o wide).
3단계: 초기 통신 테스트 (네트워크 폴리시 적용 전)
아직 아무런 네트워크 폴리시도 적용하지 않았으므로, busybox-client 파드에서 nginx-server 파드로 자유롭게 접속할 수 있어야 합니다. kubectl exec를 사용하여 busybox-client 파드 내부에서 nginx-server 파드의 IP 주소로 wget 또는 curl을 시도해 봅시다. (아래 <nginx-server-pod-ip> 부분은 실제 IP로 대체하세요.)
성공적으로 접속되어 Nginx의 환영 페이지 HTML 내용이 출력될 것입니다. 이는 현재 아무런 통신 제한이 없음을 의미합니다.
4단계: 기본 Deny 정책 YAML 파일 작성 및 적용
이제 network-policy-test 네임스페이스에 있는 모든 파드에 대해 들어오고(Ingress) 나가는(Egress) 모든 트래픽을 기본적으로 차단하는 네트워크 폴리시를 생성합니다.
default-deny-all.yaml:
이 정책은 podSelector: {}를 사용하여 network-policy-test 네임스페이스 내의 모든 파드를 대상으로 합니다. policyTypes에 Ingress와 Egress를 모두 지정하고, 구체적인 ingress나 egress 허용 규칙을 정의하지 않았으므로, 이 네임스페이스 내의 모든 파드는 이제 어떠한 수신 또는 송신 트래픽도 허용하지 않게 됩니다.
터미널에서 다음 명령어로 이 정책을 적용합니다.
5단계: 통신 재테스트 (기본 Deny 정책 적용 후)
이제 다시 busybox-client 파드에서 nginx-server 파드로 접속을 시도해 봅시다. (네트워크 폴리시가 적용되는 데 약간의 시간이 걸릴 수 있습니다.)
이번에는 접속이 실패하고 타임아웃이 발생하거나, 연결 거부(connection refused)와 유사한 오류가 발생해야 합니다. 이는 default-deny-all 정책에 의해 nginx-server 파드로의 모든 수신 트래픽이 차단되었고, 동시에 busybox-client 파드에서의 모든 송신 트래픽도 차단되었기 때문입니다 (DNS 조회조차 실패할 수 있습니다).
이처럼 “기본 Deny” 정책은 네트워크 보안의 출발점으로 매우 중요하며, 이후 필요한 통신만을 선택적으로 허용하는 “화이트리스트” 기반의 정책을 구축하는 기초가 됩니다.
8.4.5.2 특정 레이블을 가진 파드에서만 접근 허용 정책 생성
이제 “기본 Deny” 상태에서, 특정 조건을 만족하는 경우에만 통신을 허용하는 네트워크 폴리시를 추가로 생성해 보겠습니다. 이번에는 app: busybox-client 레이블을 가진 파드에서 app: nginx-server 레이블을 가진 파드의 80번 포트로만 접근을 허용하는 Ingress 정책을 nginx-server 파드에 적용해 보겠습니다.
allow-nginx-from-busybox.yaml:
이 정책은 app: nginx-server 레이블을 가진 파드(우리의 Nginx 서버)를 대상으로 하며, ingress 규칙을 통해 app: busybox-client 레이블을 가진 파드(우리의 BusyBox 클라이언트)로부터 오는 80번 TCP 포트로의 수신 트래픽만을 명시적으로 허용합니다. “기본 Deny” 정책이 이미 적용되어 있는 상태에서 이 정책이 추가되면, 이 규칙에 해당하지 않는 다른 모든 수신 트래픽은 여전히 차단됩니다. (주의: 이 정책은 nginx-server로 들어오는 트래픽만 허용합니다. busybox-client가 nginx-server로 나가는 트래픽을 허용하는 Egress 정책은 아직 없으므로, 실제 통신을 위해서는 busybox-client에 대한 Egress 허용 정책도 필요할 수 있습니다. 하지만 우선은 Ingress 정책의 효과만 확인해 보겠습니다.)
터미널에서 다음 명령어로 이 정책을 적용합니다.
8.4.5.3 통신 테스트를 통해 정책 적용 확인
이제 두 개의 네트워크 폴리시(“기본 Deny” 정책과 “특정 Ingress 허용” 정책)가 모두 적용된 상태입니다. 이 상태에서 다시 통신 테스트를 수행하여 정책이 의도한 대로 동작하는지 확인해 보겠습니다.
1단계: busybox-client에서 nginx-server로의 통신 확인 (Ingress 허용)
먼저, allow-nginx-ingress-from-busybox 정책에 의해 허용되어야 하는 통신, 즉 busybox-client 파드에서 nginx-server 파드의 80번 포트로의 접속을 시도합니다.
이론적으로는 nginx-server 입장에서 busybox-client로부터의 80번 포트 접근은 허용되었습니다. 하지만 여전히 접속이 실패하고 타임아웃이 발생할 가능성이 높습니다. 왜 그럴까요?
바로 “기본 Deny” 정책이 busybox-client 파드의 Egress(송신) 트래픽도 모두 차단하고 있기 때문입니다! nginx-server가 문을 열어주었지만, busybox-client가 집 밖으로 나갈 수 없는 상황인 것입니다.
2단계: busybox-client의 Egress 허용 정책 추가 (선택 사항, 완전한 테스트를 위해)
따라서 완전한 통신 테스트를 위해서는 busybox-client 파드가 nginx-server 파드의 80번 포트로 나가는 트래픽을 허용하는 Egress 정책도 추가해야 합니다.
allow-busybox-egress-to-nginx.yaml:
2단계: busybox-client의 Egress 허용 정책 추가 (선택 사항, 완전한 테스트를 위해)
따라서 완전한 통신 테스트를 위해서는 busybox-client 파드가 nginx-server 파드의 80번 포트로 나가는 트래픽을 허용하는 Egress 정책도 추가해야 합니다.
allow-busybox-egress-to-nginx.yaml:
위 Egress 정책을 적용합니다.
3단계: 최종 통신 테스트 (모든 허용 정책 적용 후)
이제 nginx-server로의 Ingress가 허용되었고, busybox-client에서 nginx-server로의 Egress도 허용되었으므로, 다시 통신을 시도합니다.
이번에는 성공적으로 Nginx의 환영 페이지 HTML 내용이 출력되어야 합니다!
4단계: 허용되지 않은 통신 시도 (다른 포트 또는 다른 파드)
만약 nginx-server 파드에 80번 포트가 아닌 다른 포트(예: 81번)로 접속을 시도하거나, busybox-client가 아닌 다른 파드(만약 있다면)에서 nginx-server로 접속을 시도하면, 해당 통신은 여전히 차단되어야 합니다. 이는 우리가 정의한 네트워크 폴리시가 정확히 의도한 대로 동작하고 있음을 보여줍니다.
예를 들어, busybox-client에서 nginx-server의 81번 포트로 접속 시도 (실패해야 함):
kubectl exec -n network-policy-test <busybox-client-파드이름> — wget -q -O – -T 5 http://<nginx-server-pod-ip>:81
이 실습을 통해 우리는 먼저 “기본 Deny” 정책을 통해 모든 통신을 차단한 후, 필요한 통신만을 Ingress 및 Egress 규칙을 통해 선택적으로 허용하는 방식으로 네트워크 폴리시를 구성하고 테스트했습니다. 이러한 단계적인 접근 방식은 쿠버네티스 클러스터의 네트워크 보안을 체계적으로 강화하는 데 매우 효과적입니다. 실제 운영 환경에서는 애플리케이션의 통신 요구사항을 면밀히 분석하여, 각 파드 그룹에 대해 최소한의 필요한 통신만을 허용하는 정교한 네트워크 폴리시를 수립하는 것이 중요합니다.