CKS — 쿠버네티스 보안 전문가 · 모의고사 · 실습
CKS 모의고사 A
목표
실제 CKS 와 같은 조건에서 과제 17개를 120분 안에 풉니다. 합격선은 67% 이고
부분 점수제이므로, 17개 중 12개를 통과하면 완료로 처리됩니다.
모의고사입니다. 힌트와 정답지를 보지 말고 먼저 끝까지 풀어 보십시오.
막힌 과제는 표시해 두고 넘어갔다가 남은 시간에 돌아오는 편이 낫습니다.
채점은 언제든 눌러도 되고, 여러 번 눌러도 결과가 달라지지 않습니다.
왜 중요한가
CKS 는 CKA 합격이 선수 조건인 유일한 시험입니다. 쿠버네티스를 다루는 손은
이미 갖췄다고 전제하므로, 문제는 "무엇을 만드세요" 보다 "이 설정의 무엇이
위험한지 찾아 고치세요" 쪽에 가깝습니다. 방어와 진단이 시험 대상이고,
공격 기법은 다루지 않습니다.
실무에서도 같습니다. 클러스터가 뚫리는 자리는 대개 새로 만든 기능이 아니라
기본값을 그대로 둔 곳입니다. 네임스페이스에 파드 보안 승인을 걸지 않았고,
기본 서비스 계정 토큰이 모든 파드에 마운트되고 있고, 이미지가 움직이는
태그로 배포되고 있습니다. 이 시험이 묻는 것이 정확히 그 목록입니다.
시험 환경 (실제 시험에서 확인된 사실)
- 볼 수 있는 문서는
kubernetes.io/docs,kubernetes.io/blog, - 문서 사이트 안에서 검색하는 것은 허용되지만, 결과가 허용 목록 밖으로
k별칭과 bash 자동완성이 이미 설정되어 있습니다. 별칭을 만드는 데- 과제마다 지정된 호스트로
ssh해서 작업하며, 중첩 ssh 는 지원되지 - 도구는 SSH 로 접속한 호스트에만 있습니다.
- 복사는
Ctrl+Shift+C, 붙여넣기는Ctrl+Shift+V입니다.
falco.org/docs, kubernetes-sigs.github.io/bom, etcd.io/docs,kubernetes.github.io/ingress-nginx, docs.cilium.io,istio.io/latest/docs 입니다.
나가면 안 됩니다.
시간을 쓰지 마십시오.
않습니다. 다음 과제로 넘어가기 전에 exit 하십시오.
이 모의고사 환경에서 다른 점
이 실습의 클러스터는 파드 안에서 도는 1인용 클러스터입니다. kube-apiserver 는
진짜라서 매니페스트, RBAC, 파드 보안 승인, 승인 정책은 **실제로 동작하고 실제로
거부합니다.** 다만 컨테이너를 실제로 돌리는 런타임이 없으므로 다음 두 가지는
확인할 수 없습니다.
- NetworkPolicy 는 적용되지만 실제 차단은 일어나지 않습니다. CNI 가 없기
- seccomp 와 AppArmor 프로파일은 커널에 적재되지 않습니다. 7번과 8번
때문입니다. 1번과 2번 과제는 정책 객체가 올바른지만 봅니다.
과제는 프로파일 파일의 내용과 파드에 물린 배선을 봅니다.
나머지는 전부 살아 있는 클러스터에서 다시 계산해 채점합니다. 권한은kubectl auth can-i 로, 승인 정책은 서버 dry-run 으로 그 순간의 판정을
다시 물어봅니다.
단계
Cluster Setup
1. 네임스페이스 prod 를 만들고, 그 안의 모든 파드에 대해 인그레스와
이그레스를 함께 기본 거부하는 NetworkPolicy default-deny 를 만드십시오.
허용 규칙은 하나도 두지 않습니다.
2. 네임스페이스 prod 에서 app=web 라벨이 붙은 파드가 노드 메타데이터
엔드포인트 169.254.169.254/32 로 나가지 못하게 하되, 그 밖의 이그레스는
그대로 열어 두는 NetworkPolicy deny-metadata 를 만드십시오.
3. CN=shop.internal 인 자체 서명 인증서로 네임스페이스 prod 에 TLS 시크릿web-tls 를 만들고, 호스트 shop.internal 을 그 시크릿으로 TLS 종료하는
인그레스 web 을 만드십시오. 백엔드는 서비스 web 의 80 포트입니다.
Cluster Hardening
4. 네임스페이스 prod 에 서비스 계정 report-runner 를 만들고, 이 계정이prod 안에서 파드를 get, list, watch 만 할 수 있게 Role pod-reader
와 RoleBinding report-runner-pod-reader 를 만드십시오. 그 밖의 권한은
주지 않습니다.
5. 네임스페이스 prod 의 default 서비스 계정이 토큰을 자동 마운트하지
않게 하십시오. 그리고 prod 에 파드 frontend 를 만들되 서비스 계정report-runner 를 쓰고, 파드 스펙에서도 토큰 자동 마운트를 끄십시오.
6. 보안 감사자 그룹 security-audit 이 클러스터 전역에서 파드, 네임스페이스,
네트워크폴리시를 읽기만 할 수 있도록 ClusterRole security-auditor 와
ClusterRoleBinding security-auditor 를 만드십시오. 쓰기 권한과 시크릿
접근은 주지 않습니다.
System Hardening
7. /root/exam/seccomp/audit.json 에 seccomp 프로파일을 작성하십시오. 기본
동작은 SCMP_ACT_ERRNO 이고, 최소한 몇 개의 시스템 콜은 SCMP_ACT_ALLOW
로 열어야 합니다. 그리고 네임스페이스 prod 에 파드 probe 를 만들어
이 프로파일을 Localhost 방식으로 profiles/audit.json 경로에서 쓰게
하십시오.
8. /root/exam/apparmor/k8s-deny-write 에 AppArmor 프로파일을 작성하십시오.
프로파일 이름은 k8s-deny-write 이고, #include <tunables/global> 줄과
모든 쓰기를 막는 deny /** w, 규칙이 있어야 합니다. 그리고 네임스페이스prod 에 Deployment logshipper 를 만들어 파드 템플릿의securityContext.appArmorProfile 이 이 프로파일을 Localhost 로 쓰게
하십시오.
Minimize Microservice Vulnerabilities
9. 네임스페이스 payments 를 만들고, 파드 보안 승인의 enforce, audit,warn 세 모드를 모두 restricted 로 걸고 세 모드의 버전을 latest 로
고정하십시오.
10. 네임스페이스 payments 에 restricted 를 위반하는 파드 bad-pod 를
적용해 보고, 거부된 응답을 표준 오류까지 포함해 /root/exam/denied.txt
에 저장하십시오. 파드는 실제로 만들어지면 안 됩니다.
11. RuntimeClass gvisor(handler 는 runsc)를 만들고, 네임스페이스payments 에 레플리카 2개짜리 Deployment checkout 을 만드십시오. 파드
템플릿은 이 RuntimeClass 를 쓰고 restricted 를 통과해야 합니다.
컨테이너 이름은 app 이고, 파드 수준에 runAsNonRoot: true 와seccompProfile.type: RuntimeDefault 를, 컨테이너 수준에allowPrivilegeEscalation: false, capabilities.drop: [ALL],readOnlyRootFilesystem: true 를 두십시오.
Supply Chain Security
12. 네임스페이스 supply 를 만들고 Deployment payments-api 를 만드십시오.
컨테이너 이름은 api 이고, 이미지는 태그가 아니라 다이제스트로 고정해야
합니다. 값은 registry.internal/payments-api@sha256:140eab0459241fb1643767dd4cc3576d282b0059a6328521e714cb545fa4adea 이며imagePullPolicy 는 IfNotPresent 입니다.
13. /root/exam/Dockerfile 에 배포용 이미지를 짓는 Dockerfile 을 작성하십시오.
빌드 단계와 실행 단계를 나눈 멀티스테이지여야 하고, 모든 FROM 의 베이스를@sha256: 다이제스트로 고정해야 하며, 산출물은 COPY --from= 으로만
가져와야 합니다. ADD 를 쓰지 말고, 마지막 USER 는 0 이 아닌 숫자 UID
여야 하며, ENV 나 ARG 에 비밀로 보이는 이름을 남기지 마십시오.
14. 승인되지 않은 레지스트리의 이미지를 막으십시오. ValidatingAdmissionPolicytrusted-images 와 ValidatingAdmissionPolicyBinding trusted-images 를
만들고, 모든 컨테이너 이미지가 registry.internal/ 로 시작할 것을
요구하게 하십시오. 바인딩의 validationActions 는 Deny 이고, 적용
범위는 네임스페이스 supply 뿐입니다. 다른 네임스페이스는 영향을 받으면
안 됩니다.
Monitoring, Logging and Runtime Security
15. /root/exam/audit/policy.yaml 에 감사 정책을 작성하십시오.apiVersion 은 audit.k8s.io/v1, kind 는 Policy, 최상위omitStages 는 RequestReceived 하나입니다. 규칙은 정확히 세 개이고
순서가 중요합니다. 첫째, 코어 그룹의 secrets 와 configmaps 를Metadata 레벨로 남깁니다. 둘째, pods/exec, pods/attach,pods/portforward 를 RequestResponse 레벨로 남깁니다. 셋째, 대상을
적지 않은 Metadata 규칙으로 나머지 전부를 받습니다.
16. /root/exam/audit/kube-apiserver.yaml 에 감사 로그를 켠 kube-apiserver
정적 파드 매니페스트를 작성하십시오. 첫 컨테이너 이름은 kube-apiserver
이고 다음 다섯 플래그가 있어야 합니다.--audit-policy-file=/etc/kubernetes/audit/policy.yaml,--audit-log-path=/var/log/kubernetes/audit/audit.log,--audit-log-maxage=30, --audit-log-maxbackup=10,--audit-log-maxsize=100. 그리고 hostPath 볼륨 audit-policy 와audit-logs 를 각각 마운트하되, 정책 마운트는 readOnly: true 이고
로그 마운트는 읽기 전용이면 안 됩니다.
17. 네임스페이스 prod 에 Deployment ledger 를 만드십시오. 컨테이너
이름은 app 이고 readOnlyRootFilesystem: true,allowPrivilegeEscalation: false, capabilities.drop: [ALL] 을 둡니다.
쓰기가 필요한 /tmp 는 emptyDir 볼륨 scratch 로 제공하고,hostPath 볼륨과 hostNetwork, hostPID, hostIPC 는 쓰지 마십시오.
참고
- 라벨을 다시 걸 때는
kubectl label ... --overwrite를 쓰십시오. 없이 - 파드 보안 승인은 Deployment 를 막지 않고 그 Deployment 가 만드는 파드를
- 서비스 계정에 준 권한이 맞는지는 짐작하지 말고
- 흔한 실수 두 가지입니다. NetworkPolicy 에
policyTypes를 적지 않으면
쓰면 이미 있는 라벨에서 오류가 납니다.
막습니다. Deployment 는 만들어졌는데 파드가 하나도 없다면kubectl -n <네임스페이스> describe rs 로 사유를 보십시오.
kubectl auth can-i <동사> <자원> --as=system:serviceaccount:<ns>:<이름>
으로 확인하십시오. 그룹은 --as-group 으로 흉내 냅니다.
이그레스는 통제되지 않습니다. 그리고 automountServiceAccountToken 은
서비스 계정과 파드 양쪽에 있고, 파드 쪽이 이깁니다.
단계 17개
- prod 네임스페이스 기본 거부
- 노드 메타데이터 차단
- TLS 종료 인그레스
- 서비스 계정 최소 권한
- 토큰 자동 마운트 차단
- 읽기 전용 클러스터 감사자
- seccomp 프로파일 작성과 연결
- AppArmor 프로파일 작성과 연결
- 파드 보안 승인 restricted
- 위반 파드가 거부되는지 확인
- 샌드박스 런타임 워크로드
- 이미지를 다이제스트로 고정
- 이미지 빌드 위생
- 신뢰 레지스트리 강제
- 감사 정책 작성
- 감사 로그 배선
- 런타임 불변성