CKS — 쿠버네티스 보안 전문가 · 클러스터 셋업 · 실습
기본 거부부터 시작하는 클러스터 셋업
목표
네임스페이스 하나를 기본 거부 상태로 만든 뒤 필요한 통로만 하나씩 다시 여는 순서를 손에 익히고,
컨트롤 플레인 설정 파일에서 무엇을 확인해야 하는지 직접 써 봅니다.
왜 중요한가
쿠버네티스의 기본값은 전부 열려 있습니다. 정책이 하나도 없는 파드는 클러스터의 어떤 파드와도
통신할 수 있고, 노드의 메타데이터 주소에도 그대로 도달합니다. 그래서 보안 설계의 첫 동작은
무언가를 막는 규칙을 추가하는 것이 아니라, 전부 막아 놓고 필요한 것만 되돌리는 것입니다.
이 순서를 뒤집으면 "무엇을 빠뜨렸는지" 를 영원히 알 수 없습니다. 설정 파일 감사도 같은
발상입니다. 실행 중인 프로세스를 관찰하는 것보다 매니페스트 한 장을 읽는 쪽이 빠르고, 무엇이
빠져 있는지를 목록으로 만들 수 있습니다.
이 실습 환경에는 실제 데이터플레인이 없으므로 정책이 트래픽을 정말 끊는지는 확인할 수 없습니다.
채점은 오브젝트의 스펙이 의도대로 쓰였는지를 봅니다. 시험에서도 요구하는 것은 정확한 스펙입니다.
단계
1. 네임스페이스 cks-net 을 만들고 라벨 tier=restricted 를 붙인다.
2. cks-net 에 NetworkPolicy default-deny-all 을 만든다. podSelector 는 비우고policyTypes 에 Ingress 와 Egress 를 모두 적되, ingress/egress 규칙은 하나도 두지 않는다.
3. cks-net 에 NetworkPolicy allow-dns-egress 를 만든다. 모든 파드를 대상으로 하고policyTypes 는 Egress 만, egress 대상은 kubernetes.io/metadata.name=kube-system 라벨의
네임스페이스 안 k8s-app=kube-dns 라벨 파드이며 포트는 UDP 53 과 TCP 53 두 개다.
4. cks-net 에 NetworkPolicy allow-frontend-to-api 를 만든다. 대상은 app=api 파드,
ingress 허용 출처는 같은 네임스페이스의 app=frontend 파드, 포트는 TCP 8080 이다.
5. cks-net 에 NetworkPolicy deny-node-metadata 를 만든다. 모든 파드 대상, policyTypes 는Egress, egress 대상은 ipBlock 으로 cidr: 0.0.0.0/0 에 except: [169.254.169.254/32] 다.
6. cks-net 에 kubernetes.io/tls 타입 Secret shop-tls 를 만든다. tls.crt 와 tls.key 가
모두 비어 있지 않아야 한다.
7. cks-net 에 Ingress shop 을 만든다. spec.tls[0] 의 hosts 는 shop.cks.local,secretName 은 shop-tls 이고, spec.rules[0].host 도 shop.cks.local 이며 경로 / 는
서비스 api 의 8080 포트로 보낸다.
8. /root/cks-cluster-setup/kube-apiserver.yaml 에 CIS 권고를 반영한 정적 파드 매니페스트를
쓴다. kind: Pod, 컨테이너 이름은 kube-apiserver, command 배열에--anonymous-auth=false, --authorization-mode=Node,RBAC, --profiling=false,--audit-log-path=/var/log/kubernetes/audit.log,--enable-admission-plugins=NodeRestriction,PodSecurity 가 들어가고--insecure-port 로 시작하는 플래그는 하나도 없어야 한다.
참고
kubectl create ns cks-net뒤에kubectl label ns cks-net tier=restricted- 정책 초안은
kubectl create networkpolicy로 만들 수 없습니다.kubectl explain networkpolicy.spec.egress로 필드를 확인하며 YAML 을 직접 쓰는 편이 빠릅니다. - 자체 서명 인증서 예:
openssl req -x509 -newkey rsa:2048 -nodes -keyout tls.key -out tls.crt -days 365 -subj "/CN=shop.cks.local"뒤에kubectl create secret tls shop-tls --cert=tls.crt --key=tls.key -n cks-net - 흔한 실수 1: 기본 거부를 걸고 DNS egress 를 잊으면 애플리케이션이 "연결 거부"가 아니라 "이름 못 찾음"으로 죽습니다.
- 흔한 실수 2:
except대역이cidr밖에 있으면 API 서버가 정책을 거부합니다.
단계 8개
- 격리할 네임스페이스 만들기
- ingress·egress 전부 막는 기본 정책
- DNS 만 예외로 여는 egress
- 필요한 파드 쌍만 여는 ingress
- 노드 메타데이터로 나가는 길 도려내기
- Ingress 용 TLS Secret
- Ingress 에 TLS 연결하기
- kube-apiserver 매니페스트 감사