근묵자흑
Kubernetes Pattern: Network Segmentation 본문
애플리케이션 레벨 방화벽 구현
1. 개요
Kubernetes 클러스터는 기본적으로 플랫 네트워크(Flat Network) 구조를 사용합니다. 이 구조에서는 클러스터 내 모든 Pod가 네임스페이스와 관계없이 서로 통신할 수 있습니다. 개발 환경에서는 편리하지만, 프로덕션 환경에서는 보안 문제를 야기할 수 있습니다.
Network Segmentation 패턴은 NetworkPolicy와 같은 Kubernetes 리소스를 활용하여 Pod 간 통신을 제어하는 방법을 제시합니다. 이를 통해 보안 침해 시 피해 범위(blast radius)를 제한하고, 워크로드 간 격리를 구현할 수 있습니다.
이 글에서는 Calico와 Cilium 두 가지 CNI 환경에서 직접 테스트한 결과를 바탕으로 Network Segmentation 패턴의 구현 방법에 대해 설명합니다.
2. 문제 상황
2.1 Kubernetes 기본 네트워크의 보안 문제
flowchart TB
subgraph cluster["Kubernetes Cluster - 기본 설정"]
direction TB
A[Frontend Pod] <--> B[Backend Pod]
A <--> C[Database Pod]
B <--> C
A <--> D[다른 팀의 Pod]
B <--> D
C <--> D
end
style A fill:#90EE90
style B fill:#87CEEB
style C fill:#FFB6C1
style D fill:#FFA500
기본 설정에서 발생하는 보안 문제는 다음과 같습니다.
수평 이동(Lateral Movement) 가능: 공격자가 하나의 Pod를 탈취하면 클러스터 내 다른 모든 Pod로 이동할 수 있습니다. 예를 들어 Frontend Pod가 침해되면 Database Pod에 직접 접근이 가능합니다.
민감한 데이터 노출: Database와 같은 백엔드 서비스가 불필요한 클라이언트에게 노출됩니다. 모든 Pod가 Database에 접근할 수 있으므로 데이터 유출 위험이 높아집니다.
멀티테넌시 격리 부재: 서로 다른 팀이나 애플리케이션의 워크로드가 의도치 않게 상호작용할 수 있습니다.
2.2 실제 테스트 결과: 기본 네트워크 상태
minikube 환경에서 NetworkPolicy 없이 테스트한 결과, 모든 Pod 간 통신이 허용되었습니다.
| 출발지 | 목적지 | 포트 | 결과 |
|---|---|---|---|
| curl-client | random-generator | 8080 | 성공 |
| curl-client | frontend | 80 | 성공 |
| curl-client | database | 5432 | 성공 |
| frontend | random-generator | 8080 | 성공 |
이 결과는 NetworkPolicy가 없는 상태에서 Kubernetes가 기본적으로 모든 트래픽을 허용함을 보여줍니다. 보안 관점에서 이는 심각한 문제이며, Network Segmentation 패턴을 통해 해결해야 합니다.
3. 해결 방법
Network Segmentation은 OSI 계층에 따라 다른 도구를 사용하여 구현합니다.
flowchart LR
subgraph L3L4["L3/L4 계층"]
NP[NetworkPolicy]
end
subgraph L7["L7 계층"]
AP[AuthorizationPolicy]
CNP[CiliumNetworkPolicy]
end
REQ[네트워크 요청] --> NP
NP -->|IP/Port 검증| AP
AP -->|HTTP Method/Path 검증| POD[대상 Pod]
NP -->|IP/Port 검증| CNP
CNP -->|L7 규칙 검증| POD
| 도구 | 계층 | 기능 | CNI 요구사항 |
|---|---|---|---|
| NetworkPolicy | L3/L4 | IP, Port 기반 제어 | Calico, Cilium, Weave 등 |
| AuthorizationPolicy | L7 | HTTP Method, Path, Header 제어 | Istio 필요 |
| CiliumNetworkPolicy | L3-L7 | 통합 정책, DNS 기반 제어 | Cilium 필요 |
4. NetworkPolicy: L3/L4 네트워크 세그멘테이션
4.1 CNI 플러그인 지원 현황
NetworkPolicy를 사용하려면 이를 지원하는 CNI(Container Network Interface) 플러그인이 필요합니다. CNI 플러그인은 Kubernetes의 네트워크 구현을 담당하는 핵심 컴포넌트로, Pod에 IP를 할당하고 Pod 간 통신을 가능하게 합니다.
| CNI 플러그인 | NetworkPolicy 지원 | 특징 |
|---|---|---|
| Calico | 지원 | 가장 널리 사용됨, eBPF 옵션 제공, GlobalNetworkPolicy 지원 |
| Cilium | 지원 | eBPF 기반, L7 정책 지원, Hubble 관찰성 도구 제공 |
| Weave Net | 지원 | 자동 암호화, 간단한 설정 |
| Antrea | 지원 | VMware 지원, Windows 노드 지원 강점 |
| Flannel | 미지원 | Calico와 조합하여 사용 가능 |
지원 여부는 다음 명령어로 확인할 수 있습니다.
kubectl api-resources | grep networkpolicies
# 출력 예시: networkpolicies netpol networking.k8s.io/v1 true NetworkPolicy
4.2 Deny-All 기본 정책
Zero Trust 보안 모델의 핵심은 "기본적으로 모든 것을 차단하고, 필요한 것만 허용"하는 것입니다. NetworkPolicy가 없으면 모든 트래픽이 허용되므로, deny-all 정책을 먼저 적용해야 합니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
namespace: production
spec:
podSelector: {} # 빈 셀렉터 = 모든 Pod 선택
policyTypes:
- Ingress
ingress: [] # 빈 배열 = 모든 Ingress 차단
여기서 주의해야 할 중요한 문법적 차이가 있습니다. 빈 배열 []과 빈 객체를 포함한 배열 [{}]는 완전히 다르게 동작합니다.
| 설정 | 동작 |
|---|---|
ingress: [] |
모든 Ingress 트래픽 차단 |
ingress: [{}] |
모든 Ingress 트래픽 허용 |
이 차이를 이해하지 못하면 의도와 반대되는 정책이 적용될 수 있으므로 주의가 필요합니다.
테스트 결과: Deny-All 정책 적용 후
Calico CNI 환경에서 deny-all 정책을 적용한 후 테스트한 결과는 다음과 같습니다.
| 출발지 | 목적지 | 결과 | 설명 |
|---|---|---|---|
| curl-client | random-generator | 차단됨 | timeout (exit code 28) |
| curl-client | frontend | 차단됨 | timeout (exit code 28) |
| curl-client | database | 차단됨 | Operation timed out |
deny-all 정책 적용 후 모든 Ingress 트래픽이 차단되었습니다. 이로써 Zero Trust의 첫 번째 단계인 "기본 차단"이 구현되었습니다.
4.3 레이블 기반 허용 정책
deny-all 정책을 적용한 후에는 필요한 통신만 선택적으로 허용해야 합니다. Kubernetes에서는 레이블(Label)을 사용하여 트래픽을 허용할 Pod를 지정합니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-access-to-random-generator
namespace: production
spec:
podSelector:
matchLabels:
app: random-generator # 이 정책이 적용될 대상 Pod
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
role: random-client # 이 레이블을 가진 Pod만 접근 허용
ports:
- protocol: TCP
port: 8080
flowchart LR
subgraph production["production namespace"]
CL[curl-client<br/>레이블 없음]
CLB[curl-client-labeled<br/>role: random-client]
FE[frontend<br/>role: random-client]
RG[random-generator<br/>app: random-generator]
end
CL -.->|"❌ 차단"| RG
CLB -->|"✅ 허용"| RG
FE -->|"✅ 허용"| RG
테스트 결과: 레이블 기반 정책
| 출발지 | 레이블 | 목적지 | 결과 |
|---|---|---|---|
| curl-client | 없음 | random-generator | 차단됨 |
| curl-client-labeled | role=random-client | random-generator | 성공 |
| frontend | role=random-client | random-generator | 성공 |
테스트 결과, role=random-client 레이블을 가진 Pod만 random-generator에 접근할 수 있었습니다. 레이블이 없는 curl-client는 접근이 차단되었습니다. 이처럼 레이블 기반 접근 제어를 통해 필요한 통신만 선택적으로 허용할 수 있습니다.
4.4 podSelector와 namespaceSelector 조합
실제 환경에서는 같은 네임스페이스 내의 Pod뿐만 아니라 다른 네임스페이스의 Pod도 접근을 허용해야 하는 경우가 있습니다. 예를 들어 monitoring 네임스페이스의 Prometheus가 production 네임스페이스의 애플리케이션 메트릭을 수집해야 하는 경우입니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-monitoring-access
namespace: production
spec:
podSelector:
matchLabels:
app: myapp
policyTypes:
- Ingress
ingress:
# 규칙 1: monitoring 네임스페이스의 prometheus Pod만 허용
- from:
- namespaceSelector:
matchLabels:
name: monitoring
podSelector:
matchLabels:
app: prometheus
ports:
- protocol: TCP
port: 9090
# 규칙 2: 같은 네임스페이스 내 모든 Pod 허용
- from:
- podSelector: {}
namespaceSelector와 podSelector를 조합하는 방식에 따라 동작이 달라집니다. 두 셀렉터가 같은 from 항목 내에 있으면 AND 조건으로 동작하고, 별도의 from 항목으로 분리되면 OR 조건으로 동작합니다.
| podSelector | namespaceSelector | 동작 |
|---|---|---|
{} |
{} |
모든 네임스페이스의 모든 Pod |
{app: x} |
{} |
모든 네임스페이스에서 app=x인 Pod |
{} |
{name: y} |
name=y 네임스페이스의 모든 Pod |
{app: x} |
{name: y} |
name=y 네임스페이스에서 app=x인 Pod |
{app: x} |
미설정 | 현재 네임스페이스에서만 app=x인 Pod |
마지막 행이 특히 중요합니다. namespaceSelector를 설정하지 않으면 현재 NetworkPolicy가 위치한 네임스페이스 내에서만 Pod를 선택합니다.
4.5 Egress 정책
Egress 정책은 Pod에서 나가는 트래픽을 제어합니다. 실용적인 접근법은 클러스터 내부 통신은 허용하고, 외부 인터넷 접근만 제한하는 것입니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-internal-egress-only
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress # 반드시 Egress만 명시해야 합니다
egress:
- to:
- namespaceSelector: {} # 모든 네임스페이스로의 통신 허용
flowchart TB
subgraph cluster["Kubernetes Cluster"]
subgraph ns1["production namespace"]
P1[Pod A]
P2[Pod B]
end
subgraph ns2["other namespace"]
P3[Pod C]
end
end
EXT[외부 서비스<br/>인터넷]
P1 <-->|"✅ 허용"| P2
P1 <-->|"✅ 허용"| P3
P1 -.->|"❌ 차단"| EXT
이 정책을 통해 클러스터 내부의 Pod 간 통신은 허용하면서, 외부 인터넷으로의 무분별한 데이터 유출을 방지할 수 있습니다.
4.6 DNS 허용 정책
Egress를 제한할 때 반드시 고려해야 할 사항이 있습니다. DNS 접근을 차단하면 Service Discovery가 동작하지 않아 Pod 간 통신이 전체적으로 실패합니다. 이는 Kubernetes에서 Service 이름으로 통신할 때 내부적으로 DNS 조회가 발생하기 때문입니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
DNS는 주로 UDP 53번 포트를 사용하지만, 응답이 512바이트를 초과하는 경우 TCP로 폴백하므로 TCP 53번 포트도 함께 허용하는 것이 좋습니다.
4.7 policyTypes 동작 이해
policyTypes 필드는 NetworkPolicy가 어떤 방향의 트래픽에 적용되는지 결정합니다. 이 필드의 동작 방식을 정확히 이해하지 못하면 의도치 않은 트래픽 차단이 발생할 수 있습니다.
| 상황 | 동작 |
|---|---|
| policyTypes 미지정 + ingress 섹션 있음 | Ingress만 적용 |
| policyTypes 미지정 + egress 섹션 있음 | Ingress와 Egress 모두 적용 |
| policyTypes: [Egress] 명시 | Egress만 적용 |
두 번째 행이 특히 주의가 필요합니다. Egress 섹션만 정의했는데 policyTypes를 명시하지 않으면, Ingress 정책도 함께 적용되어 모든 인입 트래픽이 차단됩니다.
# 잘못된 예시: Egress만 제어하려 했으나 Ingress도 차단됨
spec:
podSelector: {}
egress:
- to:
- namespaceSelector: {}
# policyTypes 미지정 시 [Ingress, Egress]로 동작하여 Ingress도 차단
---
# 올바른 예시: Egress만 제어
spec:
podSelector: {}
policyTypes:
- Egress # 명시적으로 Egress만 지정
egress:
- to:
- namespaceSelector: {}
4.8 ipBlock을 활용한 외부 IP 제어
특정 외부 IP 대역에 대한 접근을 제어해야 하는 경우 ipBlock을 사용합니다. 이는 클러스터 외부의 서비스(예: 외부 API 서버, SaaS 서비스)에 대한 접근을 제어할 때 유용합니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-specific-external
namespace: production
spec:
podSelector:
matchLabels:
needs-external-access: "true"
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0 # 모든 IP 허용
except:
- 10.0.0.0/8 # 내부 네트워크 제외
- 172.16.0.0/12 # 내부 네트워크 제외
- 192.168.0.0/16 # 내부 네트워크 제외
5. 3-Tier 아키텍처 네트워크 세그멘테이션 실습
5.1 아키텍처 설계
일반적인 3-Tier 웹 애플리케이션의 네트워크 세그멘테이션을 구현합니다. 이 실습에서는 Frontend, Backend(random-generator), Database로 구성된 환경에서 각 계층 간 통신을 제어합니다.
flowchart TB
subgraph internet["Internet"]
USER[사용자]
end
subgraph cluster["Kubernetes Cluster"]
subgraph ing["Ingress Layer"]
INGRESS[Ingress Controller]
end
subgraph app["production namespace"]
FE[Frontend<br/>tier: frontend]
BE[Backend<br/>tier: backend]
DB[(Database<br/>tier: database)]
end
end
USER --> INGRESS
INGRESS -->|port 80| FE
FE -->|port 8080| BE
BE -->|port 5432| DB
5.2 트래픽 매트릭스
보안 요구사항에 따른 허용/차단 트래픽 매트릭스입니다.
| 출발지 | Frontend | Backend | Database | 외부 |
|---|---|---|---|---|
| Ingress | 허용 | 차단 | 차단 | - |
| Frontend | - | 허용 | 차단 | 차단 |
| Backend | 차단 | - | 허용 | 차단 |
| Database | 차단 | 차단 | - | 차단 |
5.3 정책 구현
기본 Deny-All 정책
먼저 모든 트래픽을 차단하는 기본 정책을 적용합니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
DNS 허용 정책
Service Discovery를 위해 DNS 접근을 허용합니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
Frontend 정책
Frontend는 외부에서 접근을 받고, Backend로만 요청을 보낼 수 있습니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: frontend-policy
namespace: production
spec:
podSelector:
matchLabels:
tier: frontend
policyTypes:
- Ingress
- Egress
ingress:
- ports:
- protocol: TCP
port: 80
egress:
- to:
- podSelector:
matchLabels:
tier: backend
ports:
- protocol: TCP
port: 8080
Backend 정책
Backend는 Frontend로부터 요청을 받고, Database로만 요청을 보낼 수 있습니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-policy
namespace: production
spec:
podSelector:
matchLabels:
tier: backend
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
tier: frontend
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
tier: database
ports:
- protocol: TCP
port: 5432
Database 정책
Database는 Backend로부터만 접근을 받고, 외부로 나가는 트래픽은 없습니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database-policy
namespace: production
spec:
podSelector:
matchLabels:
tier: database
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
tier: backend
ports:
- protocol: TCP
port: 5432
egress: [] # 외부 연결 불필요
5.4 테스트 결과
3-Tier 아키텍처에 NetworkPolicy를 적용한 후 테스트한 결과입니다.
허용된 경로
| 출발지 | 목적지 | 결과 |
|---|---|---|
| frontend | random-generator (backend) | 성공 |
| curl-client-labeled (role=random-client) | random-generator | 성공 |
차단된 경로
| 출발지 | 목적지 | 결과 |
|---|---|---|
| curl-client (레이블 없음) | random-generator | 차단됨 |
| frontend | database (직접 접근) | 차단됨 |
| curl-client | database | 차단됨 |
| curl-client | frontend | 차단됨 |
테스트 결과, 설계한 트래픽 매트릭스대로 네트워크 세그멘테이션이 정상 동작함을 확인했습니다. Frontend는 Database에 직접 접근할 수 없고, 반드시 Backend를 통해서만 데이터에 접근할 수 있습니다.
6. CiliumNetworkPolicy: L7 정책
6.1 Cilium 개요
Cilium은 eBPF(Extended Berkeley Packet Filter) 기술을 활용하여 커널 레벨에서 네트워크 정책을 적용합니다. 표준 NetworkPolicy를 지원하면서 추가로 L7(애플리케이션) 레벨의 정책을 제공합니다.
eBPF는 Linux 커널 내에서 샌드박스 프로그램을 실행할 수 있게 하는 기술입니다. 전통적인 iptables 방식과 비교했을 때, eBPF는 커널 공간에서 직접 패킷을 처리하므로 성능이 우수하고 더 세밀한 제어가 가능합니다.
flowchart TB
subgraph traditional["기존 방식 (iptables)"]
U1[사용자 공간] --> K1[커널: iptables 규칙]
K1 --> N1[네트워크 인터페이스]
end
subgraph ebpf["eBPF 방식 (Cilium)"]
U2[사용자 공간]
K2[커널: eBPF 프로그램] --> N2[네트워크 인터페이스]
end
style K1 fill:#FFB6C1
style K2 fill:#90EE90
6.2 L7 HTTP 정책
CiliumNetworkPolicy의 가장 강력한 기능은 HTTP 메서드와 경로 기반으로 트래픽을 제어할 수 있다는 점입니다. 이 기능은 표준 NetworkPolicy로는 구현할 수 없습니다.
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: random-generator-l7-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: random-generator
ingress:
- fromEndpoints:
- matchLabels:
role: random-client
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
- method: GET
path: "/.*"
이 정책은 role=random-client 레이블을 가진 Pod에서 random-generator로의 GET 요청만 허용하고, POST, PUT, DELETE 등의 요청은 차단합니다.
테스트 결과: L7 HTTP 정책
Cilium CNI 환경에서 L7 HTTP 정책을 적용한 후 테스트한 결과입니다.
| HTTP Method | 결과 | 응답 |
|---|---|---|
| GET | 성공 | {"random":-1632411309,...} |
| POST | 차단됨 | Access denied |
| DELETE | 차단됨 | Access denied |
L7 정책이 HTTP 메서드 레벨에서 트래픽을 필터링함을 확인했습니다. 이는 RESTful API에서 읽기 전용 접근만 허용하고 수정/삭제 작업을 차단해야 하는 경우에 유용합니다.
6.3 DNS 기반 Egress 정책
Cilium은 FQDN(Fully Qualified Domain Name) 기반의 Egress 제어를 지원합니다. 표준 NetworkPolicy의 ipBlock은 IP 주소를 알아야 하지만, Cilium의 toFQDNs는 도메인 이름으로 외부 접근을 제어할 수 있습니다.
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: dns-based-egress
namespace: production
spec:
endpointSelector:
matchLabels:
app: random-generator
egress:
# DNS 조회 허용
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: UDP
rules:
dns:
- matchPattern: "*"
# 특정 도메인만 허용
- toFQDNs:
- matchName: "api.github.com"
- matchPattern: "*.googleapis.com"
toPorts:
- ports:
- port: "443"
protocol: TCP
테스트 결과: DNS 기반 Egress
| 대상 도메인 | 정책 설정 | 결과 |
|---|---|---|
| api.github.com | matchName으로 허용 | 성공 (HTTP 200) |
| example.com | 미등록 | 차단됨 (timeout) |
DNS 기반 Egress 정책이 도메인 레벨에서 외부 접근을 제어함을 확인했습니다. 이 기능은 특정 외부 API만 호출하도록 제한해야 하는 경우에 유용합니다.
6.4 Hubble을 통한 관찰성
Cilium은 Hubble이라는 네트워크 관찰성 도구를 제공합니다. Hubble을 사용하면 실시간으로 네트워크 흐름을 모니터링하고, 정책 적용 결과를 확인할 수 있습니다.
# 실시간 네트워크 흐름 관찰
hubble observe --namespace production
# 차단된 트래픽만 필터링
hubble observe --namespace production --verdict DROPPED
# 특정 Pod 관련 트래픽
hubble observe --namespace production --to-pod random-generator
# Hubble UI 실행
cilium hubble ui
Hubble UI를 통해 서비스 간 의존성 그래프를 시각적으로 확인할 수 있으며, 어떤 트래픽이 허용되고 차단되었는지 실시간으로 모니터링할 수 있습니다.
7. Calico vs Cilium 비교
minikube 환경에서 Calico와 Cilium 두 CNI를 테스트한 결과를 비교합니다.
7.1 기능 비교
| 기능 | Calico | Cilium |
|---|---|---|
| 표준 NetworkPolicy | 지원 | 지원 |
| Deny-All 정책 | 동작 확인 | 동작 확인 |
| 레이블 기반 접근 제어 | 동작 확인 | 동작 확인 |
| namespaceSelector | 동작 확인 | 동작 확인 |
| L7 HTTP 메서드 필터링 | 미지원 | 지원 (CiliumNetworkPolicy) |
| L7 경로 기반 정책 | 미지원 | 지원 (CiliumNetworkPolicy) |
| DNS 기반 Egress | 미지원 | 지원 (toFQDNs) |
| 네트워크 관찰성 | 제한적 | Hubble 제공 |
| 클러스터 전역 정책 | GlobalNetworkPolicy | CiliumClusterwideNetworkPolicy |
8. 테스트 환경 구성
8.1 minikube + Calico 설정
# Calico CNI로 클러스터 생성
minikube start --cni=calico --memory=4096 --cpus=2
# Calico 준비 대기
kubectl wait --for=condition=Ready pods -l k8s-app=calico-node \
-n kube-system --timeout=300s
# NetworkPolicy API 지원 확인
kubectl api-resources | grep networkpolicies
8.2 minikube + Cilium 설정
# Cilium CNI로 클러스터 생성
minikube start --cni=cilium --memory=4096 --cpus=2
# Cilium 준비 대기
kubectl wait --for=condition=Ready pods -l k8s-app=cilium \
-n kube-system --timeout=300s
# CiliumNetworkPolicy API 지원 확인
kubectl api-resources | grep ciliumnetworkpolicies
8.3 테스트 애플리케이션 배포
# 네임스페이스 생성 및 레이블링
kubectl create namespace production
kubectl label namespace production name=production
# 테스트 애플리케이션 배포
kubectl apply -f deployment.yaml
8.4 연결 테스트 명령어
# Pod 간 HTTP 통신 테스트
kubectl exec -n production deploy/curl-client -- \
curl -s --connect-timeout 3 http://random-generator:8080/
# TCP 포트 연결 테스트
kubectl exec -n production deploy/curl-client -- \
nc -zv -w 3 database 5432
# 정책 확인
kubectl get networkpolicies -n production
# Cilium 정책 확인 (Cilium 환경에서)
kubectl get ciliumnetworkpolicies -n production
8.5 디버깅 명령어
# NetworkPolicy 상세 확인
kubectl describe networkpolicy frontend-policy -n production
# Pod 레이블 확인
kubectl get pods -n production --show-labels
# 네임스페이스 레이블 확인
kubectl get namespaces --show-labels
# Cilium 엔드포인트 상태 확인 (Cilium 환경에서)
kubectl -n kube-system exec -ti ds/cilium -- cilium endpoint list
9. 실무 적용 시 주의 사항
- CNI 플러그인 확인: NetworkPolicy 적용 전에 사용 중인 CNI가 이를 지원하는지 확인해야 합니다. Flannel은 기본적으로 NetworkPolicy를 지원하지 않으며, Calico와 조합하여 사용해야 합니다.
- 클러스터 전역 정책의 부재: NetworkPolicy는 네임스페이스 범위(namespace-scoped) 리소스입니다. 클러스터 전역 정책이 필요하면 Calico의 GlobalNetworkPolicy나 Cilium의 CiliumClusterwideNetworkPolicy를 사용합니다.
- L7 정책의 성능 오버헤드: Cilium의 L7 정책은 Envoy 프록시를 통해 동작하므로 추가적인 리소스 사용과 지연이 발생할 수 있습니다. 성능이 중요한 환경에서는 L7 정책의 영향을 사전에 테스트해야 합니다.
- policyTypes 주의: policyTypes 필드를 명시하지 않으면 예상과 다르게 동작할 수 있습니다. 특히 Egress만 제어하려면 반드시 policyTypes: [Egress]를 명시해야 합니다.
정책 문서화
NetworkPolicy의 목적과 허용되는 트래픽 패턴을 annotation으로 기록하여 유지보수성을 높입니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-policy
namespace: production
annotations:
description: "Backend 서비스의 네트워크 정책"
allowed-ingress: "frontend(8080), prometheus(9090)"
allowed-egress: "database(5432), dns(53)"
owner: "platform-team"
last-reviewed: "2026-01-10"
spec:
# ...
10. 참고 자료
'k8s > kubernetes-pattern' 카테고리의 다른 글
| Kubernetes Pattern: Access Control (0) | 2026.01.24 |
|---|---|
| Kubernetes Pattern: Secure Configuration (0) | 2026.01.17 |
| Kubernetes Pattern: Process Containment (0) | 2026.01.03 |
| Kubernetes Pattern: Configuration Template (0) | 2025.12.27 |
| Kubernetes Pattern: Immutable Configuration & Kubernetes Churn (0) | 2025.12.27 |