Skip to content

Split View: CKS (Certified Kubernetes Security Specialist) 실전 모의고사 완전 정복

|

CKS (Certified Kubernetes Security Specialist) 실전 모의고사 완전 정복

1. CKS 시험 개요

CKS(Certified Kubernetes Security Specialist)는 CNCF와 Linux Foundation이 제공하는 고급 Kubernetes 보안 자격증입니다.

항목내용
시험 시간120분
문제 유형15~20개 실기 문제 (퍼포먼스 기반)
합격 기준67% 이상
선행 조건현재 유효한 CKA 자격증
시험 환경원격 감독, 브라우저 기반 터미널
유효 기간2년

도메인별 비율

도메인비율
Cluster Setup10%
Cluster Hardening15%
System Hardening15%
Minimizing Microservice Vulnerabilities20%
Supply Chain Security20%
Monitoring, Logging and Runtime Security20%

2. Kubernetes 보안 핵심 개념 요약

2.1 RBAC (Role-Based Access Control)

RBAC는 Kubernetes API 접근을 제어하는 핵심 메커니즘입니다. Role/ClusterRole은 권한을 정의하고, RoleBinding/ClusterRoleBinding은 그 권한을 주체(user, group, serviceaccount)에 바인딩합니다.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
  - apiGroups: ['']
    resources: ['pods']
    verbs: ['get', 'watch', 'list']

2.2 Pod Security Standards (PSS)

프로파일설명
Privileged제한 없음, 모든 권한 허용
Baseline최소한의 제한, 알려진 권한 상승 방지
Restricted강력한 보안 정책, 모범 사례 준수

2.3 Network Policy

NetworkPolicy는 Pod 간 트래픽을 L3/L4 수준에서 제어합니다. 기본적으로 모든 트래픽이 허용되며, NetworkPolicy를 적용하면 명시된 트래픽만 허용됩니다.

2.4 Falco 런타임 보안

Falco는 커널 시스템 콜을 모니터링하여 런타임 위협을 탐지합니다. 규칙 기반으로 의심스러운 활동을 감지하고 알림을 보냅니다.

2.5 Supply Chain Security

  • Image Scanning: Trivy, Snyk으로 CVE 취약점 탐지
  • Image Signing: Cosign으로 이미지 서명 및 검증
  • SBOM: 소프트웨어 구성 요소 목록 (Software Bill of Materials)
  • Admission Controllers: ImagePolicyWebhook으로 이미지 정책 강제

3. 개념 이해 문제 (Q1~Q55)

Cluster Setup (Q1~Q10)

Q1. kube-bench는 어떤 표준을 기반으로 Kubernetes 클러스터를 점검합니까?

A) NIST SP 800-190 B) CIS Kubernetes Benchmark C) PCI DSS D) ISO 27001

정답: B

설명: kube-bench는 CIS(Center for Internet Security) Kubernetes Benchmark를 기반으로 클러스터 구성 요소의 보안 설정을 자동으로 점검합니다. 마스터 노드, 워커 노드, etcd, API 서버 등을 검사합니다.

Q2. 다음 중 etcd 데이터를 저장 시(at rest) 암호화하기 위한 올바른 설정 위치는?

A) /etc/kubernetes/manifests/kube-apiserver.yaml--etcd-encryption-key 플래그 B) /etc/kubernetes/encryption-config.yaml을 kube-apiserver의 --encryption-provider-config로 지정 C) etcd의 --cipher-suites 플래그 D) kubelet의 --encrypt-data 플래그

정답: B

설명: etcd at-rest 암호화는 EncryptionConfiguration 리소스를 yaml 파일로 작성하고, kube-apiserver의 --encryption-provider-config 플래그로 해당 파일을 지정하여 활성화합니다. Secrets, ConfigMaps 등 특정 리소스 유형에 대해 암호화 프로바이더(aescbc, aesgcm, secretbox 등)를 설정합니다.

Q3. Kubernetes Ingress에 TLS를 구성할 때 인증서와 키는 어디에 저장해야 합니까?

A) ConfigMap B) Secret (type: kubernetes.io/tls) C) PersistentVolume D) ServiceAccount token

정답: B

설명: TLS 인증서와 개인키는 kubernetes.io/tls 타입의 Secret에 저장합니다. tls.crt 필드에 인증서, tls.key 필드에 개인키를 base64 인코딩하여 저장하며, Ingress 리소스의 spec.tls 섹션에서 이 Secret을 참조합니다.

Q4. 클라우드 환경에서 Node의 IMDS(Instance Metadata Service)에 Pod가 직접 접근하는 것을 방지하는 가장 적절한 방법은?

A) NetworkPolicy로 169.254.169.254 주소 차단 B) Pod의 hostNetwork: true 설정 C) ServiceAccount automount 비활성화 D) PSP에서 hostPID 금지

정답: A

설명: AWS IMDSv1은 인증 없이 169.254.169.254에 접근하여 IAM 자격증명을 탈취할 수 있습니다. NetworkPolicy로 해당 IP 주소로의 egress를 차단하거나, IMDSv2로 업그레이드하여 hop limit을 1로 설정하면 컨테이너에서의 직접 접근을 방지할 수 있습니다.

Q5. NetworkPolicy를 적용하여 특정 namespace의 Pod만 접근을 허용하려면 어떤 selector를 사용해야 합니까?

A) podSelector B) namespaceSelector C) ipBlock D) serviceSelector

정답: B

설명: namespaceSelector를 사용하면 특정 namespace 레이블을 가진 namespace의 Pod에서 오는 트래픽만 허용할 수 있습니다. podSelector와 함께 사용하면 특정 namespace 내 특정 Pod만 허용하는 세밀한 정책을 만들 수 있습니다.

Q6. kube-bench 실행 결과에서 [FAIL] 항목을 수정할 때 가장 먼저 해야 할 일은?

A) 클러스터를 즉시 재시작 B) 해당 권고사항의 remediation 섹션 확인 C) 새 클러스터 생성 D) etcd 백업 삭제

정답: B

설명: kube-bench 결과의 각 [FAIL] 항목에는 remediation(수정 방법) 섹션이 포함되어 있습니다. 이 섹션에는 구체적인 수정 명령어나 설정 변경 방법이 기술되어 있으므로, 이를 먼저 확인하고 신중하게 적용해야 합니다.

Q7. 다음 중 Kubernetes API 서버에 대한 익명(anonymous) 인증을 비활성화하는 올바른 설정은?

A) --anonymous-auth=false B) --disable-anonymous=true C) --allow-anonymous=false D) --auth-anonymous=disabled

정답: A

설명: kube-apiserver의 --anonymous-auth=false 플래그로 익명 인증을 비활성화할 수 있습니다. 이를 설정하면 인증되지 않은 요청이 system:anonymous 사용자로 처리되지 않고 거부됩니다.

Q8. etcd 클러스터의 피어(peer) 통신을 TLS로 보호하기 위해 필요한 etcd 플래그 조합은?

A) --peer-cert-file, --peer-key-file, --peer-trusted-ca-file B) --tls-cert-file, --tls-key-file C) --client-cert-auth, --trusted-ca-file D) --peer-auth=tls

정답: A

설명: etcd 피어 통신 TLS는 --peer-cert-file(피어 인증서), --peer-key-file(피어 개인키), --peer-trusted-ca-file(피어 CA 인증서) 세 가지 플래그로 설정합니다. --peer-client-cert-auth=true도 함께 설정하면 피어 클라이언트 인증도 강제할 수 있습니다.

Q9. Kubernetes 감사 로그(Audit Log)에서 RequestResponse 레벨로 기록하면 어떤 정보가 포함됩니까?

A) 이벤트 메타데이터만 B) 요청 메타데이터와 요청 본문 C) 메타데이터, 요청 본문, 응답 본문 모두 D) 응답 본문만

정답: C

설명: 감사 로그 레벨은 None, Metadata, Request, RequestResponse 4단계입니다. RequestResponse는 가장 상세한 레벨로 이벤트 메타데이터, 요청 본문(request body), 응답 본문(response body)을 모두 기록합니다. 다만 데이터 양이 많아 스토리지 비용이 높습니다.

Q10. 다음 중 CIS Benchmark에서 권장하는 kube-apiserver의 admission controller 설정은?

A) AlwaysAllow B) NodeRestriction, PodSecurityAdmission 포함 C) AlwaysDeny D) LimitRanger만 활성화

정답: B

설명: CIS Benchmark는 NodeRestriction(노드가 자신의 리소스만 수정 가능), PodSecurityAdmission(PSS 정책 적용), ResourceQuota, LimitRanger 등 보안 강화 admission controller를 활성화할 것을 권장합니다.

Cluster Hardening (Q11~Q22)

Q11. ServiceAccount의 토큰이 자동으로 Pod에 마운트되지 않도록 하려면 어떻게 설정합니까?

A) ServiceAccount에 automountServiceAccountToken: false 설정 B) Pod spec에 serviceAccountName: none 설정 C) RBAC에서 serviceaccount 리소스를 삭제 D) Secret 삭제

정답: A

설명: ServiceAccount 리소스에 automountServiceAccountToken: false를 설정하거나, Pod spec에 automountServiceAccountToken: false를 설정하면 ServiceAccount 토큰이 자동으로 마운트되지 않습니다. Pod 레벨 설정이 ServiceAccount 레벨 설정을 오버라이드합니다.

Q12. 최소 권한 원칙(Principle of Least Privilege)에 따라 RBAC를 구성할 때 올바른 접근 방식은?

A) cluster-admin ClusterRole을 모든 ServiceAccount에 바인딩 B) 필요한 리소스와 동사(verbs)만 포함하는 맞춤형 Role 생성 C) RBAC를 비활성화하고 ABAC 사용 D) 모든 리소스에 wildcard(*) 사용

정답: B

설명: 최소 권한 원칙은 필요한 작업에 최소한의 권한만 부여하는 것입니다. 특정 namespace의 특정 리소스에 대한 특정 동사만 허용하는 맞춤형 Role을 만들고, 필요한 주체에만 RoleBinding을 통해 부여해야 합니다.

Q13. kubelet 인증을 강화하기 위해 설정해야 하는 kubelet 플래그는?

A) --authentication-token-webhook=true, --authorization-mode=Webhook B) --anonymous-auth=true C) --read-only-port=10255 D) --allow-all-requests=true

정답: A

설명: kubelet 보안 강화를 위해 --anonymous-auth=false로 익명 접근을 차단하고, --authentication-token-webhook=true로 토큰 웹훅 인증을 활성화하며, --authorization-mode=Webhook으로 API 서버를 통한 권한 부여를 설정합니다.

Q14. Kubernetes 버전 업그레이드 주기가 보안에 중요한 이유는?

A) 새 기능 추가를 위해 B) CVE 취약점 패치 및 보안 픽스 적용 C) 성능 향상을 위해 D) kubectl 버전 호환성

정답: B

설명: Kubernetes는 마이너 버전을 약 4개월 주기로 릴리스하며, 각 버전은 약 14개월간 지원됩니다. 업그레이드하지 않으면 CVE(Common Vulnerabilities and Exposures) 취약점이 패치되지 않아 보안 위험이 증가합니다. CKS 시험에서는 최신 지원 버전 유지를 권장합니다.

Q15. 다음 ClusterRoleBinding이 위험한 이유는?
subjects:
  - kind: Group
    name: system:authenticated
roleRef:
  kind: ClusterRole
  name: cluster-admin

A) subjects 필드가 잘못됨 B) 인증된 모든 사용자에게 cluster-admin 권한 부여 C) ClusterRoleBinding 이름이 없음 D) apiGroup이 누락됨

정답: B

설명: system:authenticated 그룹은 인증된 모든 사용자를 포함합니다. 이 그룹에 cluster-admin을 바인딩하면 클러스터에 접근 가능한 모든 사용자가 최고 권한을 갖게 됩니다. 마찬가지로 system:unauthenticated에 권한을 부여하는 것도 매우 위험합니다.

Q16. Audit Policy에서 특정 리소스의 변경(create/update/delete)만 기록하고 get/list는 제외하려면?

A) rules의 verbs 필드에 원하는 동사만 지정 B) resourceNames 필드 사용 C) namespace 필드로 필터링 D) level을 None으로 설정

정답: A

설명: Audit Policy의 rules에서 verbs 필드를 사용하여 특정 HTTP 동사에 대해서만 로깅할 수 있습니다. 예를 들어 verbs: ["create", "update", "delete", "patch"]로 설정하면 변경 작업만 감사 로그에 기록됩니다.

Q17. kubelet의 read-only 포트(기본 10255)를 비활성화하려면?

A) --read-only-port=0 B) --disable-readonly=true C) --secure-port=0 D) --port=0

정답: A

설명: --read-only-port=0으로 설정하면 kubelet의 읽기 전용 HTTP 포트(기본 10255)가 비활성화됩니다. 이 포트는 인증 없이 Pod 정보와 메트릭을 노출하므로 비활성화하는 것이 보안상 권장됩니다.

Q18. 다음 중 ServiceAccount에 최소 권한을 적용하는 모범 사례로 올바른 것은?

A) 모든 Pod가 default ServiceAccount 사용 B) 각 애플리케이션 전용 ServiceAccount 생성, 필요 최소 권한만 부여 C) cluster-admin을 모든 ServiceAccount에 부여 D) RBAC 대신 파일 기반 접근 제어 사용

정답: B

설명: 각 워크로드에 맞는 전용 ServiceAccount를 생성하고, 해당 애플리케이션이 실제로 필요한 리소스와 동사만 허용하는 Role을 만들어 바인딩하는 것이 모범 사례입니다. default ServiceAccount를 공유하면 불필요한 권한이 과다 부여될 수 있습니다.

Q19. kube-apiserver에서 --insecure-port 플래그의 보안상 올바른 설정은?

A) 8080으로 설정 B) 0으로 설정하여 비활성화 C) 443으로 변경 D) TLS 인증서 추가

정답: B

설명: --insecure-port=0으로 설정하면 TLS 없이 인증도 거치지 않는 HTTP 포트를 비활성화합니다. Kubernetes 1.20부터 이 플래그는 deprecated되었고 기본값이 0이지만, 명시적으로 0으로 설정하는 것이 CIS Benchmark 권장사항입니다.

Q20. Node Authorization 모드가 하는 역할은?

A) 모든 사용자에게 노드 접근 허용 B) kubelet이 자신이 실행하는 Pod와 관련된 리소스에만 접근하도록 제한 C) 노드 간 네트워크 통신 암호화 D) 노드의 OS 레벨 접근 제어

정답: B

설명: Node Authorization 모드는 kubelet이 API 서버에 접근할 때 자신의 노드에서 실행 중인 Pod에 필요한 리소스(Secrets, ConfigMaps, PersistentVolumes 등)에만 접근하도록 제한합니다. --authorization-mode=Node,RBAC로 함께 사용하는 것이 권장됩니다.

Q21. Kubernetes CertificateSigningRequest(CSR)를 통해 사용자 인증서를 발급하는 올바른 순서는?

A) CSR 생성 → approve → CSR 오브젝트 생성 → 인증서 추출 B) 개인키 생성 → CSR 파일 생성 → CSR 오브젝트 생성 → approve → 인증서 추출 C) CA 직접 서명 → kubeconfig 설정 D) ServiceAccount 토큰 사용

정답: B

설명: 올바른 순서는 1) openssl로 개인키 생성, 2) CSR 파일 생성, 3) base64 인코딩하여 CertificateSigningRequest 오브젝트 생성, 4) kubectl certificate approve로 승인, 5) kubectl get csr -o jsonpath='{.status.certificate}'로 인증서 추출입니다.

Q22. kubectl auth can-i 명령어는 어떤 용도로 사용합니까?

A) 클러스터 인증서 갱신 B) 특정 사용자/ServiceAccount가 특정 작업을 수행할 수 있는지 확인 C) RBAC 규칙 적용 D) 감사 로그 확인

정답: B

설명: kubectl auth can-i get pods --namespace default처럼 사용하여 현재 사용자가 특정 작업을 할 수 있는지 확인합니다. --as 플래그로 다른 사용자를 가장하여 확인할 수도 있습니다. RBAC 설정 검증에 매우 유용합니다.

System Hardening (Q23~Q32)

Q23. AppArmor 프로파일을 Pod에 적용하기 위한 annotation 형식은?

A) security.alpha.kubernetes.io/apparmor: runtime/default B) container.apparmor.security.beta.kubernetes.io/CONTAINER_NAME: localhost/PROFILE_NAME C) apparmor.kubernetes.io/profile: enforced D) securityContext.appArmorProfile: localhost/custom

정답: B

설명: Kubernetes 1.30 이전에는 container.apparmor.security.beta.kubernetes.io/컨테이너이름: localhost/프로파일이름 annotation으로 AppArmor를 적용했습니다. 1.30부터는 securityContext.appArmorProfile 필드를 사용합니다. 프로파일은 노드에 미리 로드되어 있어야 합니다.

Q24. Seccomp 프로파일 RuntimeDefault를 Pod에 적용하는 올바른 방법은?

A) Pod annotation으로만 설정 B) securityContext.seccompProfile.type: RuntimeDefault C) 별도 CRD 생성 필요 D) Node 레벨에서만 설정 가능

정답: B

설명: Kubernetes 1.19부터 securityContext.seccompProfile 필드로 Seccomp를 설정할 수 있습니다. type: RuntimeDefault는 컨테이너 런타임의 기본 Seccomp 프로파일을 사용하며, type: Localhost로 사용자 정의 프로파일을 지정할 수도 있습니다.

Q25. 다음 중 컨테이너 내부에서 실행되는 프로세스의 OS 레벨 보안을 강화하는 도구는?

A) NetworkPolicy B) RBAC C) AppArmor, Seccomp D) PodDisruptionBudget

정답: C

설명: AppArmor는 MAC(Mandatory Access Control)으로 프로세스가 접근할 수 있는 파일, 네트워크, 기능을 제한합니다. Seccomp는 프로세스가 호출할 수 있는 시스템 콜을 제한합니다. 두 도구 모두 컨테이너 내 프로세스의 OS 레벨 행동을 제한합니다.

Q26. 노드에서 불필요한 서비스와 포트를 확인하는 명령어로 적절한 것은?

A) kubectl describe node B) ss -tlnp 또는 netstat -tlnp C) docker ps D) journalctl -u kubelet

정답: B

설명: ss -tlnp(소켓 통계) 또는 netstat -tlnp 명령어로 현재 노드에서 리스닝 중인 TCP 포트와 해당 프로세스를 확인할 수 있습니다. 불필요한 서비스가 포트를 열고 있다면 비활성화하거나 제거해야 합니다.

Q27. Linux capability를 제거하여 컨테이너의 권한을 제한하는 securityContext 설정은?

A) securityContext.privileged: false B) securityContext.capabilities.drop: ["ALL"] C) securityContext.runAsRoot: false D) securityContext.allowPrivilegeEscalation: false

정답: B

설명: securityContext.capabilities.drop: ["ALL"]로 모든 Linux capability를 제거하고, capabilities.add로 필요한 capability만 선택적으로 추가하는 것이 모범 사례입니다. allowPrivilegeEscalation: false와 함께 사용하면 더욱 강화됩니다.

Q28. gVisor(runsc)를 사용하는 RuntimeClass를 Pod에 적용하는 방법은?

A) spec.runtimeClassName: gvisor B) spec.securityContext.runtime: gvisor C) annotation으로 설정 D) Node label로 자동 선택

정답: A

설명: RuntimeClass 오브젝트를 먼저 생성(handler: runsc)한 후, Pod spec의 runtimeClassName 필드로 해당 RuntimeClass를 지정합니다. gVisor는 사용자 공간 커널을 구현하여 컨테이너를 샌드박싱하므로 호스트 커널과 격리됩니다.

Q29. AWS에서 Pod에 IAM 권한을 부여하는 권장 방법(IRSA)은?

A) 노드 IAM 역할에 모든 권한 부여 B) Access Key/Secret Key를 Secret에 저장 C) OIDC Provider와 ServiceAccount annotation으로 IAM Role 연결 D) EC2 인스턴스 프로파일만 사용

정답: C

설명: IRSA(IAM Roles for Service Accounts)는 EKS OIDC Provider를 사용하여 Kubernetes ServiceAccount를 IAM Role과 연결합니다. eks.amazonaws.com/role-arn annotation을 ServiceAccount에 추가하면 해당 SA를 사용하는 Pod에만 특정 IAM 권한이 부여됩니다.

Q30. 컨테이너의 파일시스템을 읽기 전용으로 설정하는 securityContext 필드는?

A) securityContext.immutable: true B) securityContext.readOnlyRootFilesystem: true C) securityContext.noWrite: true D) volumeMounts.readOnly: true

정답: B

설명: securityContext.readOnlyRootFilesystem: true를 설정하면 컨테이너의 루트 파일시스템이 읽기 전용이 됩니다. 공격자가 컨테이너 내부에 악성 파일을 생성하거나 바이너리를 변조하는 것을 방지합니다. 쓰기가 필요한 경로는 emptyDir 볼륨으로 마운트합니다.

Q31. 다음 중 컨테이너가 root로 실행되지 않도록 강제하는 설정은?

A) securityContext.runAsUser: 0 B) securityContext.runAsNonRoot: true C) securityContext.privileged: false D) RBAC로 제어

정답: B

설명: securityContext.runAsNonRoot: true를 설정하면 컨테이너가 root(UID 0)로 실행되려 할 때 Kubernetes가 이를 차단합니다. runAsUser: 1000처럼 특정 UID를 지정하는 것도 좋은 방법입니다.

Q32. 다음 중 Kata Containers의 특징으로 올바른 것은?

A) 커널 공유하는 일반 컨테이너 격리 B) 각 컨테이너/Pod가 경량 VM과 독립 커널로 실행 C) 네트워크 격리만 제공 D) Seccomp 프로파일 기반 격리

정답: B

설명: Kata Containers는 각 컨테이너(또는 Pod)를 경량 VM 위에서 실행합니다. 각 워크로드가 독립적인 커널을 가지므로 커널 취약점을 통한 컨테이너 탈출이 극도로 어렵습니다. gVisor와 달리 실제 Linux 커널을 사용합니다.

Minimizing Microservice Vulnerabilities (Q33~42)

Q33. Pod Security Admission(PSA)에서 enforce 모드와 warn 모드의 차이점은?

A) 차이 없음 B) enforce는 정책 위반 Pod를 거부, warn은 경고만 표시하고 허용 C) warn이 더 엄격 D) enforce는 기존 Pod에도 소급 적용

정답: B

설명: PSA의 세 가지 모드 중 enforce는 정책을 위반하는 Pod 생성을 거부합니다. warn은 위반 시 경고 메시지를 반환하지만 Pod는 생성됩니다. audit는 감사 로그에 기록하지만 역시 Pod는 허용됩니다.

Q34. OPA Gatekeeper와 Kyverno의 공통점은?

A) 동일한 정책 언어 사용 B) Kubernetes admission webhook으로 동작하여 정책을 강제 C) 런타임 모니터링 도구 D) 네트워크 정책 관리

정답: B

설명: OPA Gatekeeper와 Kyverno 모두 Kubernetes ValidatingAdmissionWebhook으로 동작하여 리소스 생성/수정 시 정책을 검사하고 위반 시 거부합니다. Gatekeeper는 Rego 언어를, Kyverno는 YAML 기반 정책을 사용한다는 차이가 있습니다.

Q35. mTLS(mutual TLS)를 서비스 메시(Istio)에서 활성화할 때의 이점은?

A) 성능 향상 B) 서비스 간 통신의 양방향 인증 및 암호화 C) 외부 트래픽 차단 D) 데이터베이스 암호화

정답: B

설명: mTLS는 클라이언트와 서버 모두 인증서로 서로를 인증합니다. Istio에서 PeerAuthentication 리소스로 STRICT mTLS를 설정하면 서비스 간 모든 통신이 암호화되고, 인증된 서비스만 통신할 수 있어 측면 이동(lateral movement) 공격을 방지합니다.

Q36. Kubernetes Secrets를 더 안전하게 관리하는 방법으로 올바르지 않은 것은?

A) etcd at-rest 암호화 활성화 B) Vault나 Sealed Secrets 사용 C) Secrets를 Git 저장소에 평문으로 저장 D) RBAC로 Secrets 접근 제한

정답: C

설명: Secrets를 Git에 평문으로 저장하는 것은 매우 위험합니다. 올바른 방법은 etcd 암호화, Bitnami Sealed Secrets(암호화된 SealedSecret을 Git에 저장), HashiCorp Vault(동적 시크릿 관리), AWS Secrets Manager 연동 등입니다.

Q37. Restricted Pod Security Standard를 위반하는 설정은?

A) runAsNonRoot: true B) seccompProfile.type: RuntimeDefault C) privileged: true D) capabilities.drop: ["ALL"]

정답: C

설명: Restricted PSS는 가장 엄격한 프로파일로 privileged: true, hostNetwork, hostPID, hostIPC 사용 금지, 특정 capability 추가 금지, runAsNonRoot 필수 등을 요구합니다. privileged: true는 Privileged PSS에서만 허용됩니다.

Q38. PodSecurityPolicy(PSP)가 deprecated된 이유와 대체재는?

A) 성능 문제로 인해, RuntimeClass로 대체 B) 복잡성과 권한 상승 위험으로 인해, Pod Security Admission으로 대체 C) 기능 부족으로 인해, OPA로 대체 D) etcd 호환성 문제

정답: B

설명: PSP는 Kubernetes 1.21에서 deprecated, 1.25에서 제거되었습니다. PSP를 사용하려면 서비스에 ClusterRole을 통한 PSP use 권한이 필요했는데, 이 과정에서 권한 상승이 발생할 수 있었고 설정이 복잡했습니다. 대체재는 Pod Security Admission(PSA)이며, OPA Gatekeeper나 Kyverno도 사용됩니다.

Q39. 다음 중 컨테이너 샌드박싱(sandboxing) 기술이 아닌 것은?

A) gVisor B) Kata Containers C) Firecracker D) Calico

정답: D

설명: gVisor, Kata Containers, Firecracker는 컨테이너 격리를 강화하는 샌드박싱 기술입니다. Calico는 CNI 네트워크 플러그인으로 네트워크 정책을 구현하는 도구이며 샌드박싱 기술이 아닙니다.

Q40. Istio의 AuthorizationPolicy를 사용하는 목적은?

A) 인증서 자동 갱신 B) 서비스 간 접근 제어(누가 누구에게 요청 가능한지 정의) C) 트래픽 로드 밸런싱 D) 컨테이너 이미지 스캔

정답: B

설명: Istio AuthorizationPolicy는 서비스 메시 내에서 L7 수준의 접근 제어를 구현합니다. 특정 서비스, 경로, 메서드에 대해 어떤 서비스/사용자가 접근할 수 있는지 정의합니다. mTLS와 함께 사용하면 Zero Trust 네트워킹을 구현할 수 있습니다.

Q41. Kubernetes에서 Secret을 환경 변수로 사용할 때의 보안 위험은?

A) 성능 저하 B) 프로세스 환경에 노출되어 proc/PID/environ으로 읽히거나 로그에 출력될 위험 C) 크기 제한 D) 타입 제한

정답: B

설명: 환경 변수는 프로세스의 /proc/PID/environ을 통해 읽을 수 있고, 애플리케이션이 실수로 환경 변수를 로그에 출력할 수 있습니다. 볼륨 마운트 방식이 더 안전하며, 특히 Vault Agent Injector나 CSI Secret Store 방식을 권장합니다.

Q42. 다음 중 Zero Trust 보안 모델을 Kubernetes에서 구현하는 방법은?

A) 방화벽만 사용 B) mTLS + RBAC + NetworkPolicy + PSA 조합 C) VPN만 사용 D) 물리적 네트워크 분리

정답: B

설명: Zero Trust는 "신뢰하지 말고 항상 검증하라"는 원칙입니다. Kubernetes에서는 mTLS(서비스 간 인증), RBAC(최소 권한), NetworkPolicy(네트워크 마이크로세그멘테이션), PSA(워크로드 보안 표준)를 조합하여 구현합니다.

Supply Chain Security (Q43~52)

Q43. Trivy로 컨테이너 이미지를 스캔하는 명령어는?

A) trivy scan IMAGE_NAME B) trivy image IMAGE_NAME C) trivy check IMAGE_NAME D) trivy docker IMAGE_NAME

정답: B

설명: trivy image nginx:latest처럼 trivy image 서브커맨드를 사용합니다. CVE 데이터베이스를 기반으로 이미지의 OS 패키지, 언어별 의존성 등의 취약점을 스캔합니다. --severity HIGH,CRITICAL로 심각도 필터링도 가능합니다.

Q44. ImagePolicyWebhook admission controller의 역할은?

A) 이미지를 자동으로 최신 버전으로 업데이트 B) 외부 웹훅 서비스에 이미지 허용 여부를 질의 C) 이미지 취약점 자동 수정 D) 이미지 크기 제한

정답: B

설명: ImagePolicyWebhook은 Pod 생성 시 외부 웹훅 서비스에 이미지 사용 허용 여부를 질의합니다. 웹훅 서비스는 이미지 스캔 결과, 서명 검증, 레지스트리 정책 등을 기반으로 허용/거부를 응답합니다.

Q45. Cosign으로 컨테이너 이미지에 서명하는 명령어는?

A) cosign sign --key cosign.key IMAGE_DIGEST B) cosign create-signature IMAGE C) docker sign IMAGE D) kubectl sign image IMAGE

정답: A

설명: cosign sign --key cosign.key IMAGE@sha256:DIGEST로 이미지에 서명합니다. 서명은 OCI 레지스트리에 별도 태그로 저장됩니다. cosign verify --key cosign.pub IMAGE로 검증하며, Kyverno 정책으로 서명된 이미지만 허용하도록 강제할 수 있습니다.

Q46. SBOM(Software Bill of Materials)이란?

A) 소프트웨어 라이선스 목록 B) 소프트웨어를 구성하는 모든 컴포넌트, 라이브러리, 의존성 목록 C) 소프트웨어 비용 명세서 D) 소프트웨어 배포 계획서

정답: B

설명: SBOM은 소프트웨어에 포함된 모든 오픈소스 및 독점 컴포넌트, 버전, 라이선스, 취약점 정보를 담은 목록입니다. CycloneDX, SPDX 형식이 표준으로 사용됩니다. 공급망 공격 방지와 취약점 추적에 필수적입니다.

Q47. Distroless 이미지를 사용하는 보안상 이점은?

A) 이미지 크기가 작아 빌드 속도 향상 B) 쉘, 패키지 관리자 등 불필요한 도구 제거로 공격 표면 최소화 C) 무료로 사용 가능 D) CI/CD 파이프라인 통합 용이

정답: B

설명: Distroless 이미지는 애플리케이션 실행에 필요한 런타임만 포함하고 쉘(/bin/sh), 패키지 관리자, 불필요한 유틸리티가 없습니다. 공격자가 컨테이너에 침입해도 활용할 수 있는 도구가 없어 피해를 최소화할 수 있습니다.

Q48. ValidatingWebhookConfiguration을 사용하여 특정 레이블이 없는 Pod를 차단하려면?

A) RBAC 규칙 추가 B) webhook 서비스가 admission review 요청을 검사하고 거부 응답 C) NetworkPolicy 설정 D) Pod 삭제 컨트롤러 배포

정답: B

설명: ValidatingWebhookConfiguration은 리소스 생성/수정 시 외부 webhook 서비스에 AdmissionReview 요청을 보냅니다. webhook 서비스는 요청을 검사하여 allowed: false와 메시지를 반환하면 Kubernetes API 서버가 리소스 생성을 거부합니다.

Q49. 컨테이너 이미지에 latest 태그를 사용하지 않아야 하는 이유는?

A) latest 태그가 deprecated됨 B) 재현성 부재, 어떤 이미지 버전이 실행 중인지 알 수 없음 C) 레지스트리 용량 낭비 D) 빌드 속도 저하

정답: B

설명: latest 태그는 변경 가능(mutable)하여 동일한 태그로 다른 이미지가 푸시될 수 있습니다. 이로 인해 배포 재현성이 없고, 보안 취약점이 있는 이미지가 latest로 배포될 수 있습니다. 항상 SHA256 다이제스트나 고정된 버전 태그를 사용해야 합니다.

Q50. Kyverno 정책으로 latest 태그 사용을 금지하는 정책 유형은?

A) MutatePolicy B) ClusterPolicy with validate rule C) GeneratePolicy D) SyncPolicy

정답: B

설명: Kyverno ClusterPolicyvalidate 규칙으로 이미지 태그가 latest인 경우를 거부할 수 있습니다. deny 조건에서 이미지 태그를 검사하고 위반 시 message와 함께 거부합니다. mutate 규칙으로 이미지를 자동 변환할 수도 있습니다.

Q51. 다음 중 소프트웨어 공급망 공격(Supply Chain Attack)의 예시가 아닌 것은?

A) SolarWinds 해킹 B) 악성 npm 패키지 배포 C) DDoS 공격 D) 의존성 혼동 공격(Dependency Confusion)

정답: C

설명: 공급망 공격은 소프트웨어 개발/배포 파이프라인의 취약점을 이용합니다. SolarWinds 빌드 서버 침해, 악성 npm/PyPI 패키지, Dependency Confusion(사설 패키지명으로 공개 패키지 배포)이 대표적 예시입니다. DDoS는 가용성 공격으로 공급망 공격이 아닙니다.

Q52. 컨테이너 레지스트리에서 이미지를 pull할 때 인증하는 Kubernetes 리소스는?

A) ServiceAccount B) imagePullSecret C) ConfigMap D) PersistentVolumeClaim

정답: B

설명: 프라이빗 레지스트리 인증을 위해 docker-registry 타입의 Secret을 생성하고, Pod spec의 imagePullSecrets에 참조하거나 ServiceAccount의 imagePullSecrets에 추가합니다. 이렇게 하면 해당 SA를 사용하는 모든 Pod가 자동으로 인증됩니다.

Monitoring, Logging and Runtime Security (Q53~55)

Q53. Falco 규칙에서 컨테이너 내에서 쉘이 실행될 때 알림을 생성하는 조건은?

A) evt.type=connect and fd.type=ipv4 B) evt.type=execve and container.id!=host and proc.name in (sh, bash, zsh) C) evt.type=open and fd.name contains /etc/passwd D) evt.type=write and fd.name startswith /tmp

정답: B

설명: Falco에서 execve 이벤트 타입은 새 프로세스 실행을 의미합니다. container.id!=host는 컨테이너 내부를 의미하고, proc.name in (sh, bash, zsh)는 쉘 프로세스를 필터링합니다. 기본 제공 규칙 Terminal shell in container가 이 패턴을 사용합니다.

Q54. Kubernetes Audit Policy에서 kube-system namespace의 Secrets에 대한 get 요청을 기록하지 않으려면?

A) audit policy에서 해당 규칙을 제거 B) 해당 리소스/namespace/동사에 level: None 규칙을 먼저 작성 C) kube-system namespace 삭제 D) Secrets 타입 변경

정답: B

설명: Audit Policy는 규칙을 순서대로 평가하여 첫 번째 매칭 규칙을 적용합니다. level: None으로 특정 조건을 건너뛰려면 해당 규칙을 다른 규칙보다 먼저(상위에) 작성해야 합니다. 예를 들어 kube-system secrets의 get 요청을 제외할 때는 level: None, resources: secrets, namespaces: kube-system, verbs: get 규칙을 파일 상단에 작성합니다.

Q55. 침해된 Pod를 발견했을 때 올바른 대응 순서는?

A) 즉시 삭제 후 재배포 B) 증거 수집(로그, 포렌식) → Pod 격리(NetworkPolicy) → 침해 범위 파악 → 수정 및 재배포 C) 노드 재시작 D) 클러스터 전체 재배포

정답: B

설명: 침해 대응의 올바른 순서는 1) 증거 보존(로그 수집, 메모리 덤프), 2) 추가 피해 방지를 위해 NetworkPolicy로 해당 Pod의 네트워크 격리, 3) 침해 경로와 범위 파악, 4) 취약점 수정 후 새 이미지 빌드 및 배포입니다. 즉시 삭제하면 포렌식 증거를 잃게 됩니다.


4. 실기 시나리오 (P1~P10)

P1. NetworkPolicy로 Pod 격리 설정

# 특정 namespace의 Pod만 DB에 접근 허용하는 NetworkPolicy 작성
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-allow-app-only
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: database
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: production
      podSelector:
        matchLabels:
          app: backend
    ports:
    - protocol: TCP
      port: 5432
EOF

P2. ServiceAccount 보안 강화

# 1. 전용 ServiceAccount 생성 (automount 비활성화)
kubectl create serviceaccount app-sa -n default

kubectl patch serviceaccount app-sa -n default -p '{"automountServiceAccountToken": false}'

# 2. 필요한 권한만 부여하는 Role 생성
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: app-role
  namespace: default
rules:
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["get", "list"]
EOF

# 3. RoleBinding
kubectl create rolebinding app-binding \
  --role=app-role \
  --serviceaccount=default:app-sa \
  -n default

# 4. 권한 확인
kubectl auth can-i get configmaps \
  --as=system:serviceaccount:default:app-sa \
  -n default

P3. etcd 암호화 설정

# 1. 암호화 키 생성
head -c 32 /dev/urandom | base64

# 2. EncryptionConfiguration 작성
cat <<EOF > /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
  - secrets
  providers:
  - aescbc:
      keys:
      - name: key1
        secret: <BASE64_32BYTE_KEY>
  - identity: {}
EOF

# 3. kube-apiserver manifest 수정 (/etc/kubernetes/manifests/kube-apiserver.yaml)
# --encryption-provider-config=/etc/kubernetes/encryption-config.yaml 추가

# 4. 기존 Secrets를 새로 암호화 (re-encrypt)
kubectl get secrets --all-namespaces -o json | kubectl replace -f -

# 5. etcd에서 직접 확인 (암호화되어 읽을 수 없어야 함)
ETCDCTL_API=3 etcdctl \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  get /registry/secrets/default/my-secret

P4. AppArmor 프로파일 적용

# 1. 노드에 AppArmor 프로파일 확인
ssh worker-node-1 "aa-status"

# 2. 커스텀 프로파일 파일 생성 (노드에서)
cat <<EOF > /etc/apparmor.d/k8s-custom-profile
#include <tunables/global>

profile k8s-custom-profile flags=(attach_disconnected) {
  #include <abstractions/base>
  file,
  deny /etc/shadow r,
  deny /proc/** w,
}
EOF

# 3. 프로파일 로드
apparmor_parser -r /etc/apparmor.d/k8s-custom-profile

# 4. Pod에 AppArmor 적용 (Kubernetes 1.30 이전)
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: secured-pod
  annotations:
    container.apparmor.security.beta.kubernetes.io/app: localhost/k8s-custom-profile
spec:
  containers:
  - name: app
    image: nginx:alpine
EOF

P5. Falco 규칙 커스터마이징

# /etc/falco/rules.d/custom-rules.yaml
- rule: Detect Shell in Container
  desc: Alert when a shell is spawned in a container
  condition: >
    spawned_process and
    container and
    proc.name in (shell_binaries)
  output: >
    Shell spawned in container
    (user=%user.name container=%container.name
    image=%container.image.repository proc=%proc.name
    parent=%proc.pname cmdline=%proc.cmdline)
  priority: WARNING
  tags: [container, shell, cks]

- rule: Sensitive File Access
  desc: Detect access to sensitive files
  condition: >
    open_read and
    (fd.name in (/etc/shadow, /etc/sudoers) or
     fd.name startswith /root/.ssh)
  output: >
    Sensitive file accessed
    (user=%user.name file=%fd.name
    container=%container.name proc=%proc.name)
  priority: CRITICAL
  tags: [filesystem, sensitive, cks]
# Falco 재시작 후 규칙 확인
systemctl restart falco
falco --list | grep "Detect Shell"

P6. Pod Security Admission 설정

# namespace에 PSA 레이블 설정
kubectl label namespace production \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/enforce-version=latest \
  pod-security.kubernetes.io/warn=restricted \
  pod-security.kubernetes.io/warn-version=latest \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/audit-version=latest

# Restricted PSS 준수 Pod 예시
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: restricted-pod
  namespace: production
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: nginx:alpine
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop: ["ALL"]
    volumeMounts:
    - name: tmp
      mountPath: /tmp
    - name: var-cache
      mountPath: /var/cache/nginx
    - name: var-run
      mountPath: /var/run
  volumes:
  - name: tmp
    emptyDir: {}
  - name: var-cache
    emptyDir: {}
  - name: var-run
    emptyDir: {}
EOF

P7. Trivy를 사용한 이미지 스캔

# 이미지 스캔 (HIGH, CRITICAL만)
trivy image --severity HIGH,CRITICAL nginx:latest

# JSON 형식으로 출력
trivy image -f json -o scan-result.json nginx:latest

# 파일시스템 스캔
trivy fs --security-checks vuln,secret /path/to/project

# Kubernetes cluster 스캔
trivy k8s --report summary cluster

# CI/CD 파이프라인에서 취약점 발견 시 실패처리
trivy image --exit-code 1 --severity CRITICAL myapp:latest

P8. Audit Policy 설정

# /etc/kubernetes/audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  # kube-system의 ServiceAccount token 요청은 기록 안 함
  - level: None
    resources:
      - group: ''
        resources: ['secrets']
    namespaces: ['kube-system']
    verbs: ['get']

  # Secrets에 대한 모든 접근 상세 기록
  - level: RequestResponse
    resources:
      - group: ''
        resources: ['secrets']

  # Pod 변경사항 기록
  - level: Request
    resources:
      - group: ''
        resources: ['pods']
    verbs: ['create', 'update', 'patch', 'delete']

  # 그 외 모든 요청 메타데이터만 기록
  - level: Metadata
    omitStages:
      - RequestReceived
# kube-apiserver에 audit policy 적용 (manifest 수정)
# --audit-log-path=/var/log/kubernetes/audit.log
# --audit-policy-file=/etc/kubernetes/audit-policy.yaml
# --audit-log-maxage=30
# --audit-log-maxbackup=10
# --audit-log-maxsize=100

P9. gVisor RuntimeClass 설정

# 1. containerd에 gVisor 설정 확인 (/etc/containerd/config.toml)
# [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runsc]
#   runtime_type = "io.containerd.runsc.v1"

# 2. RuntimeClass 생성
cat <<EOF | kubectl apply -f -
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: gvisor
handler: runsc
EOF

# 3. gVisor를 사용하는 Pod 배포
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: sandboxed-pod
spec:
  runtimeClassName: gvisor
  containers:
  - name: app
    image: nginx:alpine
EOF

# 4. 샌드박싱 확인
kubectl exec sandboxed-pod -- uname -r
# gVisor 커널 버전이 표시됨

P10. Cosign을 사용한 이미지 서명 및 검증

# 1. 키 쌍 생성
cosign generate-key-pair

# 2. 이미지 빌드 및 push
docker build -t registry.example.com/myapp:v1.0 .
docker push registry.example.com/myapp:v1.0

# 3. 이미지 서명
cosign sign --key cosign.key registry.example.com/myapp:v1.0

# 4. 서명 검증
cosign verify --key cosign.pub registry.example.com/myapp:v1.0

# 5. Kyverno 정책으로 서명된 이미지만 허용
cat <<EOF | kubectl apply -f -
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-image-signature
spec:
  validationFailureAction: Enforce
  rules:
  - name: verify-cosign
    match:
      any:
      - resources:
          kinds: ["Pod"]
    verifyImages:
    - imageReferences: ["registry.example.com/*"]
      attestors:
      - entries:
        - keys:
            publicKeys: |-
              -----BEGIN PUBLIC KEY-----
              <COSIGN_PUBLIC_KEY>
              -----END PUBLIC KEY-----
EOF

5. 시험 팁

  • 시험 환경: 브라우저 터미널에서 kubectl, crictl, kubeadm, openssl, falco, trivy, cosign 등 사용 가능
  • 빠른 명령어: kubectl config use-context 로 문제별 컨텍스트 전환 필수
  • 북마크: killer.sh, Kubernetes 공식 문서 등 허용된 리소스 적극 활용
  • 우선순위: 배점이 높은 문제부터 풀고 어려운 문제는 나중에
  • 검증: 설정 변경 후 항상 kubectl get, kubectl describe로 검증

CKS (Certified Kubernetes Security Specialist) Complete Practice Exam

1. CKS Exam Overview

The CKS (Certified Kubernetes Security Specialist) is an advanced Kubernetes security certification offered by CNCF and the Linux Foundation.

ItemDetails
Exam Duration120 minutes
Question Type15-20 performance-based practical tasks
Passing Score67% or higher
PrerequisitesActive CKA certification
Exam EnvironmentRemote proctored, browser-based terminal
Validity2 years

Domain Weights

DomainWeight
Cluster Setup10%
Cluster Hardening15%
System Hardening15%
Minimizing Microservice Vulnerabilities20%
Supply Chain Security20%
Monitoring, Logging and Runtime Security20%

2. Key Kubernetes Security Concepts

2.1 RBAC (Role-Based Access Control)

RBAC is the core mechanism for controlling Kubernetes API access. Roles/ClusterRoles define permissions; RoleBindings/ClusterRoleBindings bind those permissions to subjects (users, groups, service accounts).

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
  - apiGroups: ['']
    resources: ['pods']
    verbs: ['get', 'watch', 'list']

2.2 Pod Security Standards (PSS)

ProfileDescription
PrivilegedNo restrictions, all permissions allowed
BaselineMinimal restrictions, prevents known privilege escalation
RestrictedStrong security policies, enforces best practices

2.3 Network Policy

NetworkPolicy controls traffic between Pods at L3/L4. By default all traffic is allowed; once a NetworkPolicy is applied, only explicitly permitted traffic flows.

2.4 Falco Runtime Security

Falco monitors kernel system calls to detect runtime threats. It fires alerts based on rules that describe suspicious activity.

2.5 Supply Chain Security

  • Image Scanning: Trivy, Snyk for CVE detection
  • Image Signing: Cosign for signing and verification
  • SBOM: Software Bill of Materials
  • Admission Controllers: ImagePolicyWebhook for image policy enforcement

3. Practice Questions (Q1-Q55)

Cluster Setup (Q1-Q10)

Q1. On which standard does kube-bench base its Kubernetes cluster security checks?

A) NIST SP 800-190 B) CIS Kubernetes Benchmark C) PCI DSS D) ISO 27001

Answer: B

Explanation: kube-bench automatically audits cluster component configurations against the CIS (Center for Internet Security) Kubernetes Benchmark. It checks master nodes, worker nodes, etcd, and the API server.

Q2. Where do you configure encryption at rest for etcd data?

A) --etcd-encryption-key flag in /etc/kubernetes/manifests/kube-apiserver.yaml B) Write /etc/kubernetes/encryption-config.yaml and reference it with kube-apiserver's --encryption-provider-config C) --cipher-suites flag on etcd D) --encrypt-data flag on kubelet

Answer: B

Explanation: etcd at-rest encryption is enabled by writing an EncryptionConfiguration YAML and pointing kube-apiserver's --encryption-provider-config flag to it. You configure encryption providers (aescbc, aesgcm, secretbox, etc.) for specific resource types such as Secrets and ConfigMaps.

Q3. Where should TLS certificates and keys be stored when configuring Kubernetes Ingress with TLS?

A) ConfigMap B) Secret (type: kubernetes.io/tls) C) PersistentVolume D) ServiceAccount token

Answer: B

Explanation: TLS certificates and private keys are stored in a Secret of type kubernetes.io/tls, with tls.crt for the certificate and tls.key for the private key, both base64-encoded. The Ingress resource references this Secret in its spec.tls section.

Q4. In a cloud environment, what is the best way to prevent Pods from directly accessing the Instance Metadata Service (IMDS)?

A) Block 169.254.169.254 with NetworkPolicy B) Set hostNetwork: true on the Pod C) Disable ServiceAccount automount D) Disallow hostPID in PSP

Answer: A

Explanation: AWS IMDSv1 allows unauthenticated access to 169.254.169.254 to steal IAM credentials. Block outbound egress to that IP with NetworkPolicy, or upgrade to IMDSv2 and set the hop limit to 1, preventing containers from reaching the metadata endpoint directly.

Q5. Which NetworkPolicy selector allows only Pods from a specific namespace?

A) podSelector B) namespaceSelector C) ipBlock D) serviceSelector

Answer: B

Explanation: namespaceSelector matches namespaces by label, allowing traffic only from Pods in those namespaces. Combined with podSelector you can permit only specific Pods within a specific namespace.

Q6. When fixing a [FAIL] item from kube-bench, what should you do first?

A) Immediately restart the cluster B) Read the remediation section for that finding C) Create a new cluster D) Delete etcd backups

Answer: B

Explanation: Each kube-bench [FAIL] item includes a remediation section with specific commands or configuration changes to fix the issue. Always review it carefully before applying changes.

Q7. Which kube-apiserver flag disables anonymous authentication?

A) --anonymous-auth=false B) --disable-anonymous=true C) --allow-anonymous=false D) --auth-anonymous=disabled

Answer: A

Explanation: Setting --anonymous-auth=false on kube-apiserver prevents unauthenticated requests from being treated as the system:anonymous user, causing them to be rejected instead.

Q8. Which combination of etcd flags enables TLS for peer communication?

A) --peer-cert-file, --peer-key-file, --peer-trusted-ca-file B) --tls-cert-file, --tls-key-file C) --client-cert-auth, --trusted-ca-file D) --peer-auth=tls

Answer: A

Explanation: etcd peer TLS requires --peer-cert-file (peer certificate), --peer-key-file (peer private key), and --peer-trusted-ca-file (peer CA certificate). Adding --peer-client-cert-auth=true also enforces mutual peer authentication.

Q9. What information does the RequestResponse audit log level capture?

A) Event metadata only B) Request metadata and request body C) Metadata, request body, and response body D) Response body only

Answer: C

Explanation: The four audit levels are None, Metadata, Request, and RequestResponse. RequestResponse is the most verbose; it captures all of: event metadata, request body, and response body. This provides the most detail but also generates the most data and storage cost.

Q10. What admission controllers does CIS Benchmark recommend enabling on kube-apiserver?

A) AlwaysAllow B) NodeRestriction and PodSecurityAdmission among others C) AlwaysDeny D) LimitRanger only

Answer: B

Explanation: CIS Benchmark recommends enabling security-hardening admission controllers: NodeRestriction (limits nodes to modifying only their own resources), PodSecurityAdmission (enforces PSS policies), ResourceQuota, LimitRanger, and others.

Cluster Hardening (Q11-Q22)

Q11. How do you prevent a ServiceAccount token from being automatically mounted into a Pod?

A) Set automountServiceAccountToken: false on the ServiceAccount B) Set serviceAccountName: none in the Pod spec C) Delete the serviceaccount resource with RBAC D) Delete the Secret

Answer: A

Explanation: Setting automountServiceAccountToken: false on the ServiceAccount or the Pod spec prevents automatic token mounting. The Pod-level setting overrides the ServiceAccount-level setting.

Q12. What is the correct approach when configuring RBAC following the Principle of Least Privilege?

A) Bind cluster-admin ClusterRole to all ServiceAccounts B) Create custom Roles with only the required resources and verbs C) Disable RBAC and use ABAC instead D) Use wildcards (*) for all resources

Answer: B

Explanation: The Principle of Least Privilege requires granting only the minimum permissions necessary. Create custom Roles with specific namespaces, resources, and verbs, and bind them only to the subjects that need them.

Q13. Which kubelet flags should be set to harden kubelet authentication?

A) --authentication-token-webhook=true, --authorization-mode=Webhook B) --anonymous-auth=true C) --read-only-port=10255 D) --allow-all-requests=true

Answer: A

Explanation: To harden kubelet: set --anonymous-auth=false to block anonymous access, --authentication-token-webhook=true to enable token webhook authentication, and --authorization-mode=Webhook so the API server handles authorization.

Q14. Why does the Kubernetes version upgrade cadence matter for security?

A) To add new features B) To apply CVE patches and security fixes C) To improve performance D) For kubectl version compatibility

Answer: B

Explanation: Kubernetes releases a minor version approximately every 4 months, with each version supported for about 14 months. Running outdated versions leaves known CVEs (Common Vulnerabilities and Exposures) unpatched, increasing security risk. CKS recommends staying on a supported version.

Q15. Why is the following ClusterRoleBinding dangerous?
subjects:
  - kind: Group
    name: system:authenticated
roleRef:
  kind: ClusterRole
  name: cluster-admin

A) The subjects field is wrong B) It grants cluster-admin to every authenticated user C) The ClusterRoleBinding has no name D) The apiGroup is missing

Answer: B

Explanation: The system:authenticated group includes every authenticated user in the cluster. Binding cluster-admin to it gives maximum privileges to everyone who can authenticate. Similarly, granting permissions to system:unauthenticated is extremely dangerous.

Q16. How do you record only mutating verbs (create/update/delete) in an Audit Policy while excluding get/list?

A) Specify only the desired verbs in the rules' verbs field B) Use the resourceNames field C) Filter by namespace field D) Set level to None

Answer: A

Explanation: Use the verbs field in Audit Policy rules to log only specific HTTP verbs. For example, verbs: ["create", "update", "delete", "patch"] records only write operations in the audit log.

Q17. How do you disable the kubelet read-only port (default 10255)?

A) --read-only-port=0 B) --disable-readonly=true C) --secure-port=0 D) --port=0

Answer: A

Explanation: Setting --read-only-port=0 disables the unauthenticated HTTP read-only port (default 10255) on kubelet. This port exposes Pod information and metrics without authentication, so disabling it is a security best practice.

Q18. Which is the best practice for applying least privilege to ServiceAccounts?

A) All Pods use the default ServiceAccount B) Create a dedicated ServiceAccount per application with only the required permissions C) Grant cluster-admin to all ServiceAccounts D) Use file-based access control instead of RBAC

Answer: B

Explanation: Create a dedicated ServiceAccount per workload and bind a Role that permits only the specific resources and verbs that application actually needs. Sharing the default ServiceAccount risks over-provisioning permissions.

Q19. What is the correct security setting for kube-apiserver's --insecure-port flag?

A) Set to 8080 B) Set to 0 to disable it C) Change to 443 D) Add a TLS certificate

Answer: B

Explanation: Setting --insecure-port=0 disables the unauthenticated HTTP port. This flag is deprecated since Kubernetes 1.20 with a default of 0, but explicitly setting it to 0 is the CIS Benchmark recommendation.

Q20. What does Node Authorization mode do?

A) Allows all users to access any node B) Restricts kubelets to accessing only resources needed by the Pods running on their node C) Encrypts inter-node network communication D) Controls OS-level access on nodes

Answer: B

Explanation: Node Authorization limits kubelet API server requests to only the resources (Secrets, ConfigMaps, PersistentVolumes, etc.) needed by Pods scheduled on that kubelet's node. Using --authorization-mode=Node,RBAC together is recommended.

Q21. What is the correct order for issuing a user certificate via CertificateSigningRequest (CSR)?

A) Create CSR → approve → create CSR object → extract certificate B) Generate private key → create CSR file → create CSR object → approve → extract certificate C) Sign directly with CA → configure kubeconfig D) Use ServiceAccount token

Answer: B

Explanation: The correct order is: 1) Generate a private key with openssl, 2) Create a CSR file, 3) Base64-encode and create a CertificateSigningRequest object, 4) Approve with kubectl certificate approve, 5) Extract the certificate with kubectl get csr -o jsonpath='{.status.certificate}'.

Q22. What is kubectl auth can-i used for?

A) Renewing cluster certificates B) Checking whether a specific user/ServiceAccount can perform a specific action C) Applying RBAC rules D) Reviewing audit logs

Answer: B

Explanation: Use it as kubectl auth can-i get pods --namespace default to verify whether the current user can perform an action. The --as flag lets you impersonate another user. This is invaluable for validating RBAC configurations.

System Hardening (Q23-Q32)

Q23. What is the annotation format for applying an AppArmor profile to a Pod?

A) security.alpha.kubernetes.io/apparmor: runtime/default B) container.apparmor.security.beta.kubernetes.io/CONTAINER_NAME: localhost/PROFILE_NAME C) apparmor.kubernetes.io/profile: enforced D) securityContext.appArmorProfile: localhost/custom

Answer: B

Explanation: Before Kubernetes 1.30, AppArmor was applied with the annotation container.apparmor.security.beta.kubernetes.io/containerName: localhost/profileName. From 1.30 onward use the securityContext.appArmorProfile field. The profile must be pre-loaded on the node.

Q24. How do you apply the RuntimeDefault Seccomp profile to a Pod?

A) Set only via Pod annotation B) securityContext.seccompProfile.type: RuntimeDefault C) Create a separate CRD D) Can only be set at the Node level

Answer: B

Explanation: Since Kubernetes 1.19, use the securityContext.seccompProfile field. type: RuntimeDefault uses the container runtime's default Seccomp profile; type: Localhost allows a custom profile.

Q25. Which tools harden OS-level security for processes running inside containers?

A) NetworkPolicy B) RBAC C) AppArmor, Seccomp D) PodDisruptionBudget

Answer: C

Explanation: AppArmor enforces MAC (Mandatory Access Control) restricting which files, network, and capabilities a process can access. Seccomp restricts which system calls a process can invoke. Both operate at the OS level to limit container process behavior.

Q26. Which command is appropriate for identifying unnecessary services and open ports on a node?

A) kubectl describe node B) ss -tlnp or netstat -tlnp C) docker ps D) journalctl -u kubelet

Answer: B

Explanation: ss -tlnp (socket statistics) or netstat -tlnp shows which TCP ports are listening on the node and the corresponding processes. Any unnecessary services found should be disabled or removed.

Q27. Which securityContext setting removes Linux capabilities from a container?

A) securityContext.privileged: false B) securityContext.capabilities.drop: ["ALL"] C) securityContext.runAsRoot: false D) securityContext.allowPrivilegeEscalation: false

Answer: B

Explanation: securityContext.capabilities.drop: ["ALL"] removes all Linux capabilities, then capabilities.add selectively re-adds only what is needed. Using this with allowPrivilegeEscalation: false provides strong hardening.

Q28. How do you apply a RuntimeClass that uses gVisor (runsc) to a Pod?

A) spec.runtimeClassName: gvisor B) spec.securityContext.runtime: gvisor C) Set via annotation D) Automatically selected by Node label

Answer: A

Explanation: First create a RuntimeClass object with handler: runsc, then reference it in the Pod spec's runtimeClassName field. gVisor implements a user-space kernel, sandboxing the container from the host kernel.

Q29. What is the recommended way to grant IAM permissions to a Pod on AWS (IRSA)?

A) Grant all permissions to the node IAM role B) Store access key / secret key in a Secret C) Connect an IAM Role to a ServiceAccount via OIDC Provider and annotation D) Use only EC2 instance profiles

Answer: C

Explanation: IRSA (IAM Roles for Service Accounts) uses the EKS OIDC Provider to link Kubernetes ServiceAccounts with IAM Roles. Adding the eks.amazonaws.com/role-arn annotation to a ServiceAccount grants that IAM role only to Pods using that SA.

Q30. Which securityContext field makes a container's filesystem read-only?

A) securityContext.immutable: true B) securityContext.readOnlyRootFilesystem: true C) securityContext.noWrite: true D) volumeMounts.readOnly: true

Answer: B

Explanation: securityContext.readOnlyRootFilesystem: true makes the container's root filesystem read-only, preventing attackers from creating malicious files or tampering with binaries. Paths that need write access should be mounted as emptyDir volumes.

Q31. Which setting forces a container not to run as root?

A) securityContext.runAsUser: 0 B) securityContext.runAsNonRoot: true C) securityContext.privileged: false D) Control via RBAC

Answer: B

Explanation: securityContext.runAsNonRoot: true causes Kubernetes to reject the container if it tries to run as root (UID 0). Specifying runAsUser: 1000 (or another non-zero UID) is also a good practice.

Q32. What is a key characteristic of Kata Containers?

A) Shared-kernel container isolation like standard containers B) Each container/Pod runs on a lightweight VM with its own independent kernel C) Only provides network isolation D) Seccomp profile-based isolation

Answer: B

Explanation: Kata Containers runs each container (or Pod) on a lightweight VM. Each workload has its own independent kernel, making kernel-exploit container escapes extremely difficult. Unlike gVisor, Kata uses a real Linux kernel.

Minimizing Microservice Vulnerabilities (Q33-Q42)

Q33. What is the difference between enforce and warn modes in Pod Security Admission (PSA)?

A) No difference B) enforce rejects policy-violating Pods; warn allows them but shows a warning C) warn is stricter D) enforce applies retroactively to existing Pods

Answer: B

Explanation: Among PSA's three modes: enforce rejects Pods that violate the policy. warn returns a warning message but still creates the Pod. audit logs a violation but also allows the Pod.

Q34. What do OPA Gatekeeper and Kyverno have in common?

A) They use the same policy language B) Both operate as Kubernetes admission webhooks to enforce policies C) They are runtime monitoring tools D) They manage network policies

Answer: B

Explanation: Both OPA Gatekeeper and Kyverno work as Kubernetes ValidatingAdmissionWebhooks; they inspect resources at creation/modification time and reject violations. Gatekeeper uses the Rego language; Kyverno uses YAML-based policies.

Q35. What is the benefit of enabling mTLS (mutual TLS) in a service mesh like Istio?

A) Performance improvement B) Bidirectional authentication and encryption of service-to-service communication C) Blocking external traffic D) Database encryption

Answer: B

Explanation: mTLS requires both client and server to authenticate each other with certificates. Setting PeerAuthentication to STRICT mTLS in Istio encrypts all service-to-service traffic and allows only authenticated services to communicate, preventing lateral movement attacks.

Q36. Which is NOT a secure way to manage Kubernetes Secrets?

A) Enable etcd at-rest encryption B) Use Vault or Sealed Secrets C) Store Secrets in plaintext in a Git repository D) Restrict Secret access with RBAC

Answer: C

Explanation: Storing Secrets in plaintext in Git is extremely dangerous. Correct approaches include etcd encryption, Bitnami Sealed Secrets (encrypted SealedSecrets committed to Git), HashiCorp Vault (dynamic secret management), and AWS Secrets Manager integration.

Q37. Which setting violates the Restricted Pod Security Standard?

A) runAsNonRoot: true B) seccompProfile.type: RuntimeDefault C) privileged: true D) capabilities.drop: ["ALL"]

Answer: C

Explanation: Restricted PSS is the strictest profile; it forbids privileged: true, hostNetwork, hostPID, hostIPC, adding certain capabilities, and requires runAsNonRoot. Only the Privileged PSS profile permits privileged: true.

Q38. Why was PodSecurityPolicy (PSP) deprecated and what replaced it?

A) Performance issues; replaced by RuntimeClass B) Complexity and privilege escalation risk; replaced by Pod Security Admission C) Insufficient features; replaced by OPA D) etcd compatibility issues

Answer: B

Explanation: PSP was deprecated in Kubernetes 1.21 and removed in 1.25. Using PSP required granting a use ClusterRole to services, which created privilege escalation vectors and was complex to configure. It was replaced by Pod Security Admission (PSA); OPA Gatekeeper and Kyverno are also commonly used.

Q39. Which of the following is NOT a container sandboxing technology?

A) gVisor B) Kata Containers C) Firecracker D) Calico

Answer: D

Explanation: gVisor, Kata Containers, and Firecracker are all sandboxing technologies that enhance container isolation. Calico is a CNI network plugin that implements network policies; it is not a sandboxing technology.

Q40. What is the purpose of Istio's AuthorizationPolicy?

A) Automatic certificate renewal B) Service-to-service access control (defining who can make requests to whom) C) Traffic load balancing D) Container image scanning

Answer: B

Explanation: Istio AuthorizationPolicy implements L7-level access control within the service mesh. It defines which services/users may access specific services, paths, and methods. Combined with mTLS it enables Zero Trust networking.

Q41. What is the security risk of using a Secret as an environment variable?

A) Performance degradation B) Exposed in the process environment and readable via /proc/PID/environ, or accidentally logged C) Size limitation D) Type restriction

Answer: B

Explanation: Environment variables can be read through /proc/PID/environ and may be accidentally printed in application logs. Volume mount injection is safer; tools like Vault Agent Injector or the CSI Secret Store provider are recommended.

Q42. How is a Zero Trust security model implemented in Kubernetes?

A) Use only a firewall B) Combination of mTLS + RBAC + NetworkPolicy + PSA C) Use only a VPN D) Physical network separation

Answer: B

Explanation: Zero Trust follows the principle "never trust, always verify." In Kubernetes this is achieved by combining mTLS (service-to-service authentication), RBAC (least privilege), NetworkPolicy (network micro-segmentation), and PSA (workload security standards).

Supply Chain Security (Q43-Q52)

Q43. What is the correct command to scan a container image with Trivy?

A) trivy scan IMAGE_NAME B) trivy image IMAGE_NAME C) trivy check IMAGE_NAME D) trivy docker IMAGE_NAME

Answer: B

Explanation: Use trivy image nginx:latest. The trivy image subcommand scans OS packages and language-specific dependencies for CVEs. Use --severity HIGH,CRITICAL to filter by severity.

Q44. What does the ImagePolicyWebhook admission controller do?

A) Automatically updates images to the latest version B) Queries an external webhook service about whether an image is allowed C) Automatically fixes image vulnerabilities D) Restricts image size

Answer: B

Explanation: ImagePolicyWebhook queries an external webhook service at Pod creation time to determine if an image is permitted. The webhook service can base its decision on scan results, signature verification, registry policies, and more.

Q45. What is the correct Cosign command to sign a container image?

A) cosign sign --key cosign.key IMAGE_DIGEST B) cosign create-signature IMAGE C) docker sign IMAGE D) kubectl sign image IMAGE

Answer: A

Explanation: Use cosign sign --key cosign.key IMAGE@sha256:DIGEST. Signatures are stored in the OCI registry as a separate tag. Verify with cosign verify --key cosign.pub IMAGE. A Kyverno policy can enforce that only signed images are admitted.

Q46. What is an SBOM (Software Bill of Materials)?

A) A list of software licenses B) A list of all components, libraries, and dependencies that make up a software artifact C) A software cost breakdown D) A software release plan

Answer: B

Explanation: An SBOM is an inventory of all open-source and proprietary components, versions, licenses, and vulnerability information in a software artifact. CycloneDX and SPDX are standard formats. SBOMs are essential for supply chain attack prevention and vulnerability tracking.

Q47. What is the security benefit of using distroless images?

A) Smaller image size means faster builds B) Minimizes attack surface by removing shells, package managers, and other unnecessary tools C) Available for free D) Easy CI/CD pipeline integration

Answer: B

Explanation: Distroless images contain only the runtime needed to run the application, without a shell (/bin/sh), package manager, or utilities. Even if an attacker breaks into the container there are no tools to leverage, minimizing potential damage.

Q48. How do you block Pods lacking a specific label using ValidatingWebhookConfiguration?

A) Add an RBAC rule B) The webhook service inspects the admission review request and returns a denial response C) Configure a NetworkPolicy D) Deploy a Pod deletion controller

Answer: B

Explanation: ValidatingWebhookConfiguration sends an AdmissionReview request to an external webhook service at resource create/update time. The service inspects the request and returns allowed: false with a message, which causes the Kubernetes API server to reject the resource.

Q49. Why should the latest tag not be used for container images?

A) The latest tag is deprecated B) No reproducibility — you cannot know which exact image version is running C) Wastes registry storage D) Slows down builds

Answer: B

Explanation: The latest tag is mutable; a different image can be pushed under the same tag at any time. This makes deployments non-reproducible, and an image with security vulnerabilities could be deployed as latest. Always use a SHA256 digest or a pinned version tag.

Q50. Which Kyverno policy type blocks the use of the latest tag?

A) MutatePolicy B) ClusterPolicy with validate rule C) GeneratePolicy D) SyncPolicy

Answer: B

Explanation: A Kyverno ClusterPolicy with a validate rule can deny images whose tag is latest. The deny condition checks the image tag and returns a message on violation. A mutate rule can also automatically transform image references.

Q51. Which of the following is NOT an example of a software supply chain attack?

A) SolarWinds hack B) Distribution of a malicious npm package C) DDoS attack D) Dependency confusion attack

Answer: C

Explanation: Supply chain attacks exploit vulnerabilities in the software development and delivery pipeline (SolarWinds build server compromise, malicious npm/PyPI packages, dependency confusion where a public package shadows a private one). A DDoS attack targets availability, not the supply chain.

Q52. Which Kubernetes resource provides credentials to pull images from a private container registry?

A) ServiceAccount B) imagePullSecret C) ConfigMap D) PersistentVolumeClaim

Answer: B

Explanation: Create a Secret of type docker-registry and reference it in the Pod spec's imagePullSecrets, or add it to the ServiceAccount's imagePullSecrets so all Pods using that SA authenticate automatically.

Monitoring, Logging and Runtime Security (Q53-Q55)

Q53. Which Falco condition generates an alert when a shell is executed inside a container?

A) evt.type=connect and fd.type=ipv4 B) evt.type=execve and container.id!=host and proc.name in (sh, bash, zsh) C) evt.type=open and fd.name contains /etc/passwd D) evt.type=write and fd.name startswith /tmp

Answer: B

Explanation: In Falco, the execve event type signals a new process execution. container.id!=host scopes the rule to containers, and proc.name in (sh, bash, zsh) filters for shell processes. The built-in rule "Terminal shell in container" uses this exact pattern.

Q54. How do you exclude get requests for Secrets in the kube-system namespace from the Kubernetes Audit Policy?

A) Remove the relevant rule from the audit policy B) Write a level: None rule for that resource/namespace/verb first, before other rules C) Delete the kube-system namespace D) Change the Secret type

Answer: B

Explanation: Audit Policy rules are evaluated in order, with the first matching rule applied. To skip logging certain requests with level: None, that rule must appear before any broader rule. For example, place a level: None rule for resources: secrets, namespaces: kube-system, verbs: get at the top of the policy file.

Q55. What is the correct response order when a compromised Pod is discovered?

A) Delete immediately then redeploy B) Collect evidence (logs, forensics) → isolate Pod (NetworkPolicy) → assess scope of compromise → remediate and redeploy C) Restart the node D) Redeploy the entire cluster

Answer: B

Explanation: The correct incident response order is: 1) Preserve evidence (collect logs, memory dumps), 2) Isolate the Pod with a NetworkPolicy to prevent further lateral movement, 3) Determine the attack vector and scope, 4) Fix the vulnerability, build a new image, and redeploy. Deleting immediately destroys forensic evidence.


4. Hands-On Scenarios (P1-P10)

P1. Isolating Pods with NetworkPolicy

# NetworkPolicy that allows only the backend app to reach the DB
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-allow-app-only
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: database
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: production
      podSelector:
        matchLabels:
          app: backend
    ports:
    - protocol: TCP
      port: 5432
EOF

P2. Hardening a ServiceAccount

# 1. Create a dedicated ServiceAccount with automount disabled
kubectl create serviceaccount app-sa -n default

kubectl patch serviceaccount app-sa -n default \
  -p '{"automountServiceAccountToken": false}'

# 2. Create a Role with only the required permissions
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: app-role
  namespace: default
rules:
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["get", "list"]
EOF

# 3. Bind the role
kubectl create rolebinding app-binding \
  --role=app-role \
  --serviceaccount=default:app-sa \
  -n default

# 4. Verify
kubectl auth can-i get configmaps \
  --as=system:serviceaccount:default:app-sa \
  -n default

P3. Configuring etcd Encryption

# 1. Generate an encryption key
head -c 32 /dev/urandom | base64

# 2. Write the EncryptionConfiguration
cat <<EOF > /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
  - secrets
  providers:
  - aescbc:
      keys:
      - name: key1
        secret: <BASE64_32BYTE_KEY>
  - identity: {}
EOF

# 3. Edit the kube-apiserver manifest
# Add: --encryption-provider-config=/etc/kubernetes/encryption-config.yaml

# 4. Re-encrypt existing Secrets
kubectl get secrets --all-namespaces -o json | kubectl replace -f -

# 5. Verify (should be unreadable)
ETCDCTL_API=3 etcdctl \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  get /registry/secrets/default/my-secret

P4. Applying an AppArmor Profile

# 1. Check AppArmor status on the node
ssh worker-node-1 "aa-status"

# 2. Create a custom profile (on the node)
cat <<EOF > /etc/apparmor.d/k8s-custom-profile
#include <tunables/global>

profile k8s-custom-profile flags=(attach_disconnected) {
  #include <abstractions/base>
  file,
  deny /etc/shadow r,
  deny /proc/** w,
}
EOF

# 3. Load the profile
apparmor_parser -r /etc/apparmor.d/k8s-custom-profile

# 4. Apply to a Pod (pre-1.30 annotation style)
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: secured-pod
  annotations:
    container.apparmor.security.beta.kubernetes.io/app: localhost/k8s-custom-profile
spec:
  containers:
  - name: app
    image: nginx:alpine
EOF

P5. Customizing Falco Rules

# /etc/falco/rules.d/custom-rules.yaml
- rule: Detect Shell in Container
  desc: Alert when a shell is spawned in a container
  condition: >
    spawned_process and
    container and
    proc.name in (shell_binaries)
  output: >
    Shell spawned in container
    (user=%user.name container=%container.name
    image=%container.image.repository proc=%proc.name
    parent=%proc.pname cmdline=%proc.cmdline)
  priority: WARNING
  tags: [container, shell, cks]

- rule: Sensitive File Access
  desc: Detect access to sensitive files
  condition: >
    open_read and
    (fd.name in (/etc/shadow, /etc/sudoers) or
     fd.name startswith /root/.ssh)
  output: >
    Sensitive file accessed
    (user=%user.name file=%fd.name
    container=%container.name proc=%proc.name)
  priority: CRITICAL
  tags: [filesystem, sensitive, cks]
# Restart Falco and verify rules
systemctl restart falco
falco --list | grep "Detect Shell"

P6. Configuring Pod Security Admission

# Set PSA labels on a namespace
kubectl label namespace production \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/enforce-version=latest \
  pod-security.kubernetes.io/warn=restricted \
  pod-security.kubernetes.io/warn-version=latest \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/audit-version=latest

# Pod that complies with Restricted PSS
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: restricted-pod
  namespace: production
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: nginx:alpine
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop: ["ALL"]
    volumeMounts:
    - name: tmp
      mountPath: /tmp
    - name: var-cache
      mountPath: /var/cache/nginx
    - name: var-run
      mountPath: /var/run
  volumes:
  - name: tmp
    emptyDir: {}
  - name: var-cache
    emptyDir: {}
  - name: var-run
    emptyDir: {}
EOF

P7. Scanning Images with Trivy

# Scan for HIGH and CRITICAL only
trivy image --severity HIGH,CRITICAL nginx:latest

# Output as JSON
trivy image -f json -o scan-result.json nginx:latest

# Filesystem scan
trivy fs --security-checks vuln,secret /path/to/project

# Scan an entire Kubernetes cluster
trivy k8s --report summary cluster

# Fail CI/CD pipeline on CRITICAL findings
trivy image --exit-code 1 --severity CRITICAL myapp:latest

P8. Setting Up an Audit Policy

# /etc/kubernetes/audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  # Do not log get requests for Secrets in kube-system
  - level: None
    resources:
      - group: ''
        resources: ['secrets']
    namespaces: ['kube-system']
    verbs: ['get']

  # Log all Secret access in full detail
  - level: RequestResponse
    resources:
      - group: ''
        resources: ['secrets']

  # Log Pod mutations
  - level: Request
    resources:
      - group: ''
        resources: ['pods']
    verbs: ['create', 'update', 'patch', 'delete']

  # Log metadata only for everything else
  - level: Metadata
    omitStages:
      - RequestReceived
# kube-apiserver flags to add:
# --audit-log-path=/var/log/kubernetes/audit.log
# --audit-policy-file=/etc/kubernetes/audit-policy.yaml
# --audit-log-maxage=30
# --audit-log-maxbackup=10
# --audit-log-maxsize=100

P9. Configuring a gVisor RuntimeClass

# 1. Verify gVisor in containerd config (/etc/containerd/config.toml)
# [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runsc]
#   runtime_type = "io.containerd.runsc.v1"

# 2. Create the RuntimeClass
cat <<EOF | kubectl apply -f -
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: gvisor
handler: runsc
EOF

# 3. Deploy a Pod using gVisor
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: sandboxed-pod
spec:
  runtimeClassName: gvisor
  containers:
  - name: app
    image: nginx:alpine
EOF

# 4. Verify sandboxing (gVisor kernel version shown)
kubectl exec sandboxed-pod -- uname -r

P10. Signing and Verifying Images with Cosign

# 1. Generate a key pair
cosign generate-key-pair

# 2. Build and push the image
docker build -t registry.example.com/myapp:v1.0 .
docker push registry.example.com/myapp:v1.0

# 3. Sign the image
cosign sign --key cosign.key registry.example.com/myapp:v1.0

# 4. Verify the signature
cosign verify --key cosign.pub registry.example.com/myapp:v1.0

# 5. Kyverno policy to allow only signed images
cat <<EOF | kubectl apply -f -
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-image-signature
spec:
  validationFailureAction: Enforce
  rules:
  - name: verify-cosign
    match:
      any:
      - resources:
          kinds: ["Pod"]
    verifyImages:
    - imageReferences: ["registry.example.com/*"]
      attestors:
      - entries:
        - keys:
            publicKeys: |-
              -----BEGIN PUBLIC KEY-----
              <COSIGN_PUBLIC_KEY>
              -----END PUBLIC KEY-----
EOF

5. Exam Tips

  • Exam Environment: The browser terminal provides kubectl, crictl, kubeadm, openssl, falco, trivy, cosign, and more.
  • Context Switching: Always use kubectl config use-context to switch to the correct cluster for each task.
  • Bookmarks: Leverage allowed resources like killer.sh and the official Kubernetes documentation.
  • Prioritize: Attempt high-point tasks first; return to difficult ones later.
  • Verify: After every change, validate with kubectl get and kubectl describe.