보안 점검 항목으로 자주 요구되는 두 값은 모두 kubelet 설정이다. kube-apiserver 옵션이 아니다.
# /var/lib/kubelet/config.yaml
podPidsLimit: 10000
seccompDefault: true
podPidsLimit 는 파드 하나가 만들 수 있는 프로세스 수를 제한해 포크 폭탄이 노드를 마비시키는 것을 막는다. seccompDefault: true 는 별도 지정이 없는 컨테이너에 런타임 기본 seccomp 프로파일(RuntimeDefault)을 적용한다.
SupportPodPidsLimit 같은 피처 게이트를 apiserver 에 넣으라는 안내가 오래된 문서에 남아 있으나, 해당 게이트는 이미 정식 기능이 되어 제거됐다. apiserver 실행 옵션에서 이 값을 찾으면 나오지 않는 것이 정상이다.
설치 도구가 kubeadm-config 템플릿을 통해 kubelet 설정을 내려보내는 경우(Cloudera CDSW · CML 처럼 배포판이 템플릿을 제공하는 제품 포함), 템플릿을 고친 뒤 실제 노드에 반영됐는지는 아래로 확인한다.
kubelet 이 읽는 설정 파일을 직접 본다.
grep -E 'podPidsLimit|seccompDefault' /var/lib/kubelet/config.yaml
systemctl cat kubelet | grep -i config
kubelet 이 기동 시 읽은 값을 확인하려면 설정 조회 엔드포인트를 쓴다.
kubectl get --raw "/api/v1/nodes/<노드이름>/proxy/configz" | python3 -m json.tool | grep -E 'podPidsLimit|seccompDefault'
노드에서 직접 볼 수도 있다.
curl -sk --cert /var/lib/kubelet/pki/kubelet-client-current.pem \
--key /var/lib/kubelet/pki/kubelet-client-current.pem \
https://127.0.0.1:10250/configz | python3 -m json.tool | head -40
PID 제한은 cgroup 값을 보면 확실하다. 파드를 하나 띄우고 컨테이너 안에서 읽는다.
kubectl run pidtest --image=busybox --restart=Never -- sh -c "sleep 3600"
kubectl exec pidtest -- cat /sys/fs/cgroup/pids.max
cgroup v1 노드라면 경로가 다르다.
kubectl exec pidtest -- cat /sys/fs/cgroup/pids/pids.max
seccomp 는 프로세스 상태에서 확인한다. Seccomp: 값이 2(filter mode)면 프로파일이 걸린 것이고 0 이면 걸리지 않은 것이다.
kubectl exec pidtest -- grep Seccomp /proc/1/status
파드 스펙에 명시된 값도 함께 본다.
kubectl get pod pidtest -o jsonpath='{.spec.securityContext.seccompProfile}{"\n"}'
정리한다.
kubectl delete pod pidtest
kubelet 설정을 바꾸면 kubelet 을 재시작해야 반영된다. 이미 떠 있는 파드에는 소급 적용되지 않으므로, 확인은 반드시 설정 이후 새로 만든 파드로 한다.
seccompDefault 를 켜면 시스템 콜을 폭넓게 쓰는 워크로드가 깨질 수 있다. 특히 오래된 컨테이너 런타임과 새 glibc 조합에서는 스레드 생성이 막히는 사례가 있다.
podPidsLimit 를 지나치게 낮추면 스레드를 많이 쓰는 JVM 워크로드가 기동하지 못한다. 노드 전체 한도(/proc/sys/kernel/pid_max)와 함께 계산한다.