CCA — Cilium Certified Associate
Watch What Cilium Actually Blocks
한국어 원문으로 표시합니다.
이 실습은 진짜 Cilium 에서 돕니다
VM 안에 k3s + Cilium 이 실제로 떠 있습니다. kube-proxy 를 끄고 Cilium 이
그 일을 대신하며(kubeProxyReplacement), L7 정책은 Envoy 가 실제로 강제하고,
Hubble 이 흐름을 모읍니다.
CCA 과정의 다른 실습은 CRD 만 적재된 가짜 클러스터에서 돕니다. 거기서는
kubectl apply 가 통과할 뿐 아무것도 막지 않습니다. 여기서는 막힙니다.
처음 뜨는 데 4~5분 걸립니다. Cilium 을 설치하기 때문입니다.
목표
아이덴티티가 무엇인지 눈으로 확인하고, L3 정책과 L7 정책을 차례로 쌓은 뒤, Hubble 로 "무엇이 왜 막혔는지" 를 읽습니다.
왜 중요한가
쿠버네티스 기본 NetworkPolicy도 파드·네임스페이스의 라벨 선택자와
ipBlock으로 통신 상대를 고릅니다. podSelector와 namespaceSelector는
ingress의 from과 egress의 to 모두에서 사용할 수 있습니다. IP만 직접
나열해야 하는 API가 아닙니다. 실제 강제는 이를 지원하는 네트워크 플러그인이 합니다.
Cilium은 이 정책 의도를 구현하면서 보안 관련 라벨 집합을 아이덴티티 번호에
대응시킵니다. app=tgt 하나만 같다고 같은 신원인 것은 아닙니다. 네임스페이스 등
다른 보안 관련 라벨도 비교해야 합니다. 같은 집합의 엔드포인트는 신원을 공유하므로
파드 IP를 정책에 일일이 고정하지 않아도 됩니다. 번호 자체를 영구 식별자로 삼기보다
어떤 라벨 집합이 그 번호에 대응하는지 확인하세요.
그리고 Cilium 은 HTTP 경로·메서드까지 봅니다. "이 서비스는 /api/read 만
호출할 수 있다" 를 네트워크 계층에서 강제할 수 있고, 막히면 연결이 끊기는 것이
아니라 403 이 돌아옵니다 — 애플리케이션 입장에서 훨씬 다루기 쉽습니다.
단계
cilium status를/root/cca/status.txt에 저장하세요.KubeProxyReplacement: True가 보여야 하고,kube-proxy데몬셋은 없어야 합니다.mesh네임스페이스에tgt(app=tgt, nginx)와client(app=client, curl)를 만들고,tgt의 아이덴티티 번호와 그 번호가 어떤 라벨에서 나왔는지를/root/cca/identity.txt에 저장하세요.l3-allowCiliumNetworkPolicy 로app=client만tgt에 닿게 하고, 허용된 쪽과 아닌 쪽을 둘 다 시험해/root/cca/l3.txt에 저장하세요.l7-allow정책으로/allowed경로만 허용하세요./secret이 403 을 받는 것을/root/cca/l7.txt에 기록합니다.- 막히는 요청을 한 번 보낸 뒤
hubble observe로 흐름을 관찰해/root/cca/hubble.txt에 저장하세요.FORWARDED와DROPPED가 함께 보여야 합니다. egress-fqdn정책으로tgt가 특정 이름으로만 나갈 수 있게 하세요. 결과를/root/cca/dnspolicy.txt에 저장합니다.hubble observe --type policy-verdict로 왜 막혔는지 판정 로그를 뽑아/root/cca/verdict.txt에 저장하세요./root/cca/report.md에tgt_identity=,l7_denied_code=,policies=세 줄과 설명을 쓰세요.
참고
- 아이덴티티는
kubectl get ciliumendpoint -n mesh tgt -o yaml의status.identity에 있습니다.cilium identity list로도 봅니다. - Hubble 은
hubble observe -n mesh --last 30처럼 씁니다. 먼저cilium hubble port-forward &가 필요합니다. - FQDN 정책은 Cilium 이 DNS 응답을 들여다봐야 동작합니다. 그래서
toFQDNs를 쓰려면 DNS 자체를 먼저toEndpoints+rules.dns.matchPattern으로 열어야 합니다. 이것을 빠뜨리면 이름이 아예 안 풀려서 정책이 동작하지 않습니다. - 흔한 실수 1: L7 정책에서
toPorts없이rules.http를 쓰는 것. HTTP 규칙은 포트 안에 들어갑니다. - 흔한 실수 2: L7 이 막았는데 연결 실패를 기대하는 것. Cilium 은 Envoy 로 프록시해서 403 을 돌려줍니다.
connection refused가 아닙니다.
kube-proxy 없는 클러스터
cilium status 를 /root/cca/status.txt 에 저장하세요. KubeProxyReplacement: True 가 보여야 하고, kube-proxy 데몬셋은 없어야 합니다.
cilium status 의 KubeProxyReplacement 줄을 봅니다. True 라면 Service 의 부하 분산을 iptables 가 아니라 eBPF 가 하고 있다는 뜻입니다.
정책은 IP 가 아니라 번호로 판단한다
mesh 네임스페이스에 tgt(app=tgt, nginx)와 client(app=client, curl)를 만들고, tgt 의 아이덴티티 번호와 그 번호가 어떤 라벨에서 나왔는지를 /root/cca/identity.txt 에 저장하세요.
kubectl get ciliumendpoint -n mesh tgt -o yaml 의 status.identity 를 봅니다. 그 번호가 어떤 라벨 조합에서 나왔는지도 함께 담으세요.
L3 — 누가 닿을 수 있는가
l3-allow CiliumNetworkPolicy 로 app=client 만 tgt 에 닿게 하고, 허용된 쪽과 아닌 쪽을 둘 다 시험해 /root/cca/l3.txt 에 저장하세요.
endpointSelector 가 보호받는 파드를, ingress.fromEndpoints 가 허용할 출처를 고릅니다. 쿠버네티스 NetworkPolicy 와 방향 규칙이 같습니다.
L7 — 어느 경로까지 허용하는가
l7-allow 정책으로 /allowed 경로만 허용하세요. /secret 이 403 을 받는 것을 /root/cca/l7.txt 에 기록합니다.
HTTP 규칙은 toPorts[].rules.http 안에 씁니다. 막히면 연결이 끊기는 것이 아니라 403 이 돌아옵니다.
흐름을 눈으로 본다
막히는 요청을 한 번 보낸 뒤 hubble observe 로 흐름을 관찰해 /root/cca/hubble.txt 에 저장하세요. FORWARDED 와 DROPPED 가 함께 보여야 합니다.
cilium hubble port-forward & 를 먼저 띄우고 hubble observe -n mesh --last 30 을 씁니다. 막히는 요청을 보낸 뒤에 관찰해야 DROPPED 가 보입니다.
이름으로 나가는 곳을 고른다
egress-fqdn 정책으로 tgt 가 특정 이름으로만 나갈 수 있게 하세요. 결과를 /root/cca/dnspolicy.txt 에 저장합니다.
toFQDNs 는 Cilium 이 DNS 응답을 들여다봐야 동작합니다. 그래서 DNS 자체를 toEndpoints + rules.dns.matchPattern 으로 먼저 열어야 합니다.
왜 막혔는지를 묻는다
hubble observe --type policy-verdict 로 왜 막혔는지 판정 로그를 뽑아 /root/cca/verdict.txt 에 저장하세요.
hubble observe --type policy-verdict 는 각 흐름이 어느 정책에 걸려 어떻게 판정됐는지를 보여 줍니다.
무엇을 배웠나
/root/cca/report.md 에 tgt_identity=, l7_denied_code=, policies= 세 줄과 설명을 쓰세요.
tgt_identity=, l7_denied_code=, policies= 세 줄과 함께, 아이덴티티가 IP 보다 나은 이유와 L7 거부가 403 인 이유를 설명하세요.