쿠버네티스 네트워크 — 진짜 클러스터에서 · 정책이 실제로 막는 것 · 실습
정책이 실제로 막는 것을 본다
이 실습은 진짜 쿠버네티스에서 돕니다
VM 안에 k3s 한 대가 실제로 떠 있고, NetworkPolicy 를 강제하는 컨트롤러가
돌고 있습니다. 그래서 정책을 붙이면 정말로 막힙니다. 채점기도 파일만 보지
않고 매번 실제로 접속을 시도해 확인합니다.
처음 뜨는 데 2분쯤 걸립니다.
목표
허용 목록 방식의 네트워크 정책을 한 겹씩 쌓고, 그 과정에서 **실무에서 가장
자주 나는 사고** 하나를 직접 일으켰다가 고칩니다.
왜 중요한가
쿠버네티스의 기본값은 전부 허용입니다. 어느 네임스페이스의 어느 파드든
다른 모든 파드에 닿습니다. 침입자가 웹 파드 하나를 잡으면 그 자리에서
데이터베이스가 보입니다.
그런데 정책의 동작 방식이 직관과 다릅니다. **파드에 정책이 하나도 붙지 않으면
전부 허용이고, 하나라도 붙는 순간 그 파드는 허용 목록 방식으로 바뀝니다.**
그래서 "막는 정책" 을 쓰는 것이 아니라 "허용하는 정책" 을 쓰게 되고, 이
전환을 모르면 정책을 추가할수록 뜻밖의 것이 끊깁니다.
가장 흔한 사고가 5번 단계입니다. egress 를 기본 차단하는 순간 **DNS 가
함께 끊깁니다.** CoreDNS 로 나가는 53번 포트도 egress 이기 때문입니다.
증상은 "이름을 못 찾습니다" 라서 아무도 방금 붙인 네트워크 정책을 의심하지
않습니다.
단계
준비된 것: shop 네임스페이스에 api(app=api)와 db(app=db, nginx) 파드, 그리고 ops 네임스페이스가 있습니다. 없으면 1번에서 만듭니다.
1. 정책이 하나도 없을 때 아무 파드에서나 db 에 닿는 것을 확인해 /root/k8snp/baseline.txt 에 저장하세요. 응답 코드 200 이 보여야 합니다.
2. shop 에 default-deny 정책을 만드세요. podSelector: {} 이고 policyTypes: [Ingress] 입니다. 그리고 이제 막힌다는 것을 /root/k8snp/deny.txt 에 기록하세요.
3. allow-api 정책으로 app=api 파드만 db 에 닿게 하세요. 결과를 /root/k8snp/allow-pod.txt 에 저장합니다. 정책은 받는 쪽(app=db)에 붙습니다.
4. allow-ops 정책으로 ops 네임스페이스 전체를 허용하고 /root/k8snp/namespace.txt 에 저장하세요. 네임스페이스는 kubernetes.io/metadata.name 라벨로 고릅니다.
5. shop 에 deny-egress(policyTypes: [Egress], 빈 선택자) 를 붙이고 무슨 일이 생기는지 보세요. 그리고 /root/k8snp/incident.md 에 사고 보고서를 쓰세요. 원인이 DNS 라는 것, 53번 포트, CoreDNS 가 어느 네임스페이스에 있는지가 들어가야 합니다.
6. allow-dns 정책으로 DNS 만 열어 되살리세요. 결과를 /root/k8snp/fixed.txt 에 저장합니다. UDP 와 TCP 둘 다 53번을 열어야 합니다.
7. allow-api 에 포트 제한(80) 을 추가하고 결과를 /root/k8snp/ports.txt 에 저장하세요.
8. /root/k8snp/report.md 에 policies=(정책 개수)와 dns_fix_policy=allow-dns 두 줄, 그리고 기본 허용에서 허용 목록으로 바뀌는 지점을 설명하세요.
참고
- 접속 시험은
kubectl -n shop run t --rm -i --restart=Never --image=busybox:1.36 -- timeout 5 wget -q -O- http://<db의 IP>/로 합니다. 서비스 이름 대신 파드 IP 를 쓰면 DNS 문제와 정책 문제를 섞지 않고 볼 수 있습니다. kubernetes.io/metadata.name라벨은 쿠버네티스가 모든 네임스페이스에 자동으로 붙여 줍니다. 직접 붙일 필요가 없습니다.- 6번에서
to를 비우면 "어디로든" 이 됩니다. 그러면 DNS 는 살아나지만 나머지 egress 도 전부 열려 5번의 의미가 사라집니다.kube-system네임스페이스로 좁히세요. - 흔한 실수 1: 정책을 보내는 쪽에 붙이는 것. ingress 규칙은 언제나 받는 쪽 파드를 고릅니다.
- 흔한 실수 2: 6번에서 UDP 만 여는 것. DNS 응답이 512바이트를 넘으면 TCP 로 넘어갑니다. UDP 만 열면 가끔씩만 실패해서 원인을 찾기가 훨씬 어렵습니다.
- 흔한 실수 3:
allow-api에서ports를 비워 두는 것. 그러면api는 db 의 모든 포트에 닿습니다.
단계 8개
- 기본값은 전부 허용이다
- 하나만 붙여도 방식이 바뀐다
- 받는 쪽에 붙인다
- 네임스페이스 단위로 허용한다
- egress 를 막았더니 이름이 안 풀린다
- DNS 만 열어 되살린다
- 출처만 고르면 절반이다
- 무엇을 배웠나