CCA — 실리움 인증 어소시에이트 · 보안 정책 사고 조사: DNS와 허용 경계 · 실습
DNS를 죽인 방화벽과 문을 넓힌 허용 정책
목표
정책의 방향, 네임스페이스 선택자, DNS 의존성, 허용 합집합과 명시적 거부를 실제 Cilium에서 구분합니다.
왜 중요한가
보안 변경 뒤 timeout이 났다고 서버부터 재시작하면 원인을 지울 수 있습니다. IP 통제군과 이름 요청을 비교해 의존성을 찾고, 정상 요청과 거부 요청을 함께 확인합니다. 정책 개수가 아닌 실제 접근 범위를 검증합니다. 비교 대상은 마지막까지 남기므로 전체 채점도 현재 상태를 다시 봅니다.
VM 안의 개인 k3s만 사용하세요. 새 환경은 Cilium 1.20.1과 k3s 1.35.8+k3s1을 사용하며 시작에 수 분이 걸릴 수 있습니다. 단계 준비만으로 현재 단계는 해결되지 않습니다. 정책 전파가 끝나기 전에는 관측 결과가 일시적으로 다를 수 있으므로 관측 후 다시 채점하세요. 세션 종료 시 작업 파일은 사라지니 필요하면 먼저 내보내세요.
단계
1. 도구의 inventory 명령으로 11파드의 namespace·name·uid·ip·identity를 /root/cca-policy/inventory.json에 저장하세요. cca-blue/client와 cca-red/client의 role 라벨은 같지만 namespace 라벨과 identity는 다릅니다. 출력의 실제 값을 읽고 비교하세요. 파드가 다시 만들어졌다면 기록도 갱신해야 합니다.
2. /root/cca-policy/native.yaml에 cca-blue의 native-only NetworkPolicy를 작성·적용하세요. podSelector.matchLabels는 target=native, policyTypes는 [Ingress], ingress 하나의 from 하나에는 podSelector.matchLabels.role=client만 둡니다. native는 파란 client만 200, 파란 stranger와 빨간 client는 timeout이어야 합니다. 무정책 baseline은 셋 모두 200이어야 합니다.
3. /root/cca-policy/ingress.yaml에 cca-blue의 blue-ingress CiliumNetworkPolicy를 작성·적용하세요. endpointSelector.matchLabels.target=ingress, ingress 하나의 fromEndpoints 하나에는 matchLabels.role=client만 둡니다. 파란 client만 200, stranger와 빨간 client는 timeout이어야 합니다. native 정책은 지우지 마세요.
4. /root/cca-policy/dns-blocked.yaml에 cca-blue의 dns-blocked CNP를 작성·적용하세요. endpointSelector.matchLabels.client-mode=blocked입니다. egress 하나에 toEndpoints.matchLabels={role: api, target: egress}와 toPorts.ports=[{port: "8080", protocol: TCP}]만 둡니다. DNS 허용은 넣지 않습니다. dns-blocked 클라이언트의 egress 서버 IP 요청은 200, 서비스 이름 요청은 timeout이어야 합니다.
5. /root/cca-policy/dns-open.yaml에 cca-blue의 dns-open CNP를 작성·적용하세요. client-mode=open을 선택합니다. 첫 egress 항목은 앞 단계의 API 대상과 TCP 8080 그대로입니다. 두 번째 항목의 toEndpoints.matchLabels는 k8s:io.kubernetes.pod.namespace=kube-system과 k8s:k8s-app=kube-dns이며 toPorts.ports는 문자열 53의 UDP와 TCP 두 항목입니다. dns-open의 IP·이름 접근 모두 200이어야 합니다. dns-blocked의 제한은 그대로 둡니다.
6. 초기 blue-union CNP는 보존합니다. /root/cca-policy/union.yaml에 cca-blue의 red-union NetworkPolicy를 작성·적용하세요. target=union을 선택하고 policyTypes=[Ingress]로 둡니다. ingress 하나의 from 하나에 namespaceSelector.matchLabels.team=cca-red와 podSelector.matchLabels.role=client를 함께 넣습니다. 파란 client와 빨간 client는 200, stranger는 timeout이어야 합니다.
7. 초기 blue-deny CNP와 red-deny NetworkPolicy를 보존합니다. /root/cca-policy/deny.yaml에 cca-blue의 deny-red CNP를 작성·적용하세요. target=deny를 선택하고 ingressDeny 하나의 fromEndpoints 하나에 matchLabels의 k8s:io.kubernetes.pod.namespace=cca-red와 k8s:role=client를 함께 넣습니다. 파란 client는 200, stranger와 빨간 client는 timeout이어야 합니다.
8. 도구의 report 명령 결과를 /root/cca-policy/report.json에 저장하세요. 빨간 client가 baseline·union·deny에 보낸 세 요청은 각각 200·200·timeout이어야 합니다. 출력에서 현재 파드 UID/IP/identity, 정책 UID/spec 해시, 요청 source port, 같은 노드·시각의 Hubble FORWARDED/DROPPED 흐름을 대조하세요. 정책이나 파드를 바꿨다면 보고서를 새로 만드세요. 마지막 전체 채점에서 이전 단계도 모두 살아 있어야 합니다.
참고
- 관측 도구: python3 /opt/fixtures/cca-policy/runtime.py observe 사례명. 사례명은 baseline, native, ingress, dns-blocked, dns-open, union, deny입니다.
- 신원: kubectl get cep -A. 정책: kubectl get cnp,netpol -A -o yaml.
- Hubble: hubble observe --server 127.0.0.1:4245 --namespace cca-blue --last 50.
- 과제 파일은 JSON 또는 단일 YAML 객체로 저장할 수 있습니다. 값뿐 아니라 목록의 묶임을 확인하세요.
- HTTP 000은 서버 응답 코드가 아닙니다. 응답을 받지 못했을 때 실제 종료 코드와 흐름도 확인합니다.
단계 8개
- 두 팀의 실제 파드와 보안 신원 기록
- 표준 NetworkPolicy도 라벨을 선택한다
- CNP에서도 두 팀의 경계를 확인
- API는 살리고 이름 해석만 막힌 사고 재현
- 다른 비교 클라이언트에서 DNS만 추가 복구
- 허용을 추가하자 다른 팀에 문이 열린다
- 명시적 거부를 허용 정책보다 우선시킨다
- 현재 정책과 같은 요청의 흐름으로 사고 보고