Kubernetes kubeadm 기반 취약점 점검 및 보완 방법
1. 목적 및 대상
Kubernetes 클러스터에서 운영자가 직접 점검하고 보완할 수 있는 설정 및 인증서 관련 취약점 항목을 정리합니다.
대상은 다음과 같습니다.
- Kubernetes: kubeadm 기반 클러스터
- 적용 버전: v1.30, v1.33 계열 등 kubeadm 인증서 체계를 사용하는 버전
- OS: Red Hat 계열 Linux, Ubuntu 계열 Linux
- 구성: 단일 Control Plane 또는 3-master HA 구성
- API Server 접속: 노드 IP, VIP 또는 FQDN 사용
- 환경: 폐쇄망 또는 온라인 설치 환경
2. HA 구성 작업 주의사항
3-master HA 구성에서는 점검은 전체 노드에서 수행하되, 보완 작업은 한 번에 한 대씩 진행합니다.
- 조치 전
kubectl get nodes와kubectl get pods -n kube-system을 확인합니다. - 작업 대상 마스터 1대를 선정합니다.
- 해당 마스터에서 manifest 백업, 설정 변경, 인증서 갱신 등 보완 작업을 수행합니다.
- kubelet 또는 control plane 정적 Pod를 재시작합니다.
- API Server
/readyz, NodeReady,kube-systemPod 상태를 확인합니다. - 정상 확인 후 다음 마스터로 진행합니다.
동시에 3대 마스터의 kubelet, containerd, API Server, etcd를 재시작하지 않습니다.
3. 점검 항목 요약
| 구분 | 점검 내용 | 보완 기준 |
|---|---|---|
| API Server 설정 | 익명 접근, 권한 모드, Admission Plugin, 감사 로그 설정 확인 | 보안 기준에 맞게 설정 |
| etcd 설정 | client/peer TLS, 인증서 사용 여부 확인 | TLS 및 인증서 기반 통신 적용 |
| 인증서 만료 | Kubernetes 인증서 잔여 기간 확인 | 만료 전 갱신 |
| API Server SAN | 인증서에 VIP, FQDN 또는 접속 IP 포함 여부 확인 | 실제 접속 엔드포인트 포함 |
| 인증서 공유 | Kubernetes 인증서와 타 서비스 인증서 공유 여부 확인 | 서비스별 인증서/개인키 분리 |
| 클러스터 상태 | Node 및 Control Plane Pod 상태 확인 | Ready, Running, /readyz 응답 ok |
4. Kubernetes 설정 취약점 점검 및 보완
4.1 API Server 설정 점검
마스터 노드에서 API Server manifest를 확인합니다.
sudo grep -nE 'anonymous-auth|authorization-mode|enable-admission-plugins|disable-admission-plugins|audit-log' /etc/kubernetes/manifests/kube-apiserver.yaml
출력에 없는 옵션은 kube-apiserver 바이너리 기본값으로 동작합니다. 예를 들어
--anonymous-auth는 명시하지 않으면 기본값 false로 동작합니다. 다만 보안 점검자가
manifest만 보고 확인할 수 있도록 운영 환경에서는 --anonymous-auth=false처럼 명시하는
것을 권장합니다.
옵션별 요약은 다음과 같습니다.
| 옵션 | 한줄 요약 | 권장 기준 |
|---|---|---|
--anonymous-auth |
인증서나 토큰이 없는 익명 요청 허용 여부 | 기본값 false, 명시 권장 |
--authorization-mode |
API 요청 권한 검증 방식 | Node,RBAC 포함 |
--enable-admission-plugins |
API 요청 저장 전 추가 검증 플러그인 | NodeRestriction 포함 |
--disable-admission-plugins |
기본 활성 Admission Plugin 비활성화 | 보안 필수 플러그인 비활성화 금지 |
--audit-log-path |
감사 로그 저장 경로 | 운영 기준에 따라 설정 |
--audit-policy-file |
감사 로그 기록 정책 파일 | 운영 기준에 따라 설정 |
확인 기준은 다음과 같습니다.
| 항목 | 판정 기준 |
|---|---|
--anonymous-auth=false |
옵션이 없어도 기본값은 false. 점검 대응을 위해 명시 권장 |
--authorization-mode=Node,RBAC |
포함되어 있으면 양호 |
--enable-admission-plugins=NodeRestriction |
포함되어 있으면 양호 |
| 감사 로그 | 점검 기준에서 요구하는 경우 audit-log-path, audit-policy-file 확인 |
4.2 API Server 설정 보완
/etc/kubernetes/manifests/kube-apiserver.yaml을 백업합니다.
sudo cp -a /etc/kubernetes/manifests/kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml.bak.$(date +%Y%m%d%H%M%S)
필요한 설정을 추가 또는 수정합니다.
- --anonymous-auth=false
- --authorization-mode=Node,RBAC
- --enable-admission-plugins=NodeRestriction
기존 --enable-admission-plugins 값이 이미 있으면 덮어쓰지 말고 NodeRestriction을
기존 목록에 추가합니다.
정적 Pod는 manifest 변경 후 kubelet이 자동으로 재기동합니다.
4.3 etcd TLS 설정 점검
sudo grep -nE 'cert-file|key-file|trusted-ca-file|peer-cert-file|peer-key-file|peer-trusted-ca-file|client-cert-auth|peer-client-cert-auth' /etc/kubernetes/manifests/etcd.yaml
옵션별 요약은 다음과 같습니다.
| 옵션 | 한줄 요약 | 권장 기준 |
|---|---|---|
--cert-file |
etcd client 접속용 서버 인증서 | etcd 전용 인증서 지정 |
--key-file |
etcd client 접속용 서버 개인키 | etcd 전용 개인키 지정 |
--trusted-ca-file |
etcd client 인증서 검증용 CA | etcd CA 지정 |
--client-cert-auth |
client 인증서 인증 강제 여부 | true |
--peer-cert-file |
etcd peer 통신용 인증서 | etcd peer 인증서 지정 |
--peer-key-file |
etcd peer 통신용 개인키 | etcd peer 개인키 지정 |
--peer-trusted-ca-file |
etcd peer 인증서 검증용 CA | etcd CA 지정 |
--peer-client-cert-auth |
peer 인증서 인증 강제 여부 | true |
확인 기준은 다음과 같습니다.
| 항목 | 판정 기준 |
|---|---|
| client 인증서 | --cert-file, --key-file, --trusted-ca-file, --client-cert-auth=true 확인 |
| peer 인증서 | --peer-cert-file, --peer-key-file, --peer-trusted-ca-file, --peer-client-cert-auth=true 확인 |
| 인증서/키 | /etc/kubernetes/pki/etcd/ 하위의 etcd 전용 인증서와 개인키 사용 |
4.4 etcd 설정 보완
kubeadm 기본 stacked etcd 구성은 일반적으로 etcd TLS가 이미 적용되어 있습니다. 점검 결과에 위 옵션들이 모두 보이면 별도 보완 작업은 필요하지 않습니다.
누락된 경우에도 운영자가 인증서를 직접 새로 만들어 넣는 절차가 우선은 아닙니다. 먼저 현재 클러스터가 kubeadm stacked etcd인지 확인하고, 기존 백업 또는 kubeadm이 관리하는 etcd 인증서를 기준으로 복구합니다.
sudo cp -a /etc/kubernetes/manifests/etcd.yaml /etc/kubernetes/manifests/etcd.yaml.bak.$(date +%Y%m%d%H%M%S)
sudo ls -l /etc/kubernetes/pki/etcd/
sudo kubeadm certs check-expiration
etcd 인증서가 만료되었거나 재발급이 필요한 경우 kubeadm으로 갱신합니다.
sudo kubeadm certs renew etcd-server
sudo kubeadm certs renew etcd-peer
sudo kubeadm certs renew etcd-healthcheck-client
sudo kubeadm certs renew apiserver-etcd-client
sudo systemctl restart kubelet
etcd manifest의 TLS 옵션 자체가 누락된 경우에는 인증서를 새로 만드는 것이 아니라,
백업 또는 kubeadm 기본 manifest 형식에 맞춰 /etc/kubernetes/manifests/etcd.yaml의
인증서 경로를 복구합니다.
수정 후 상태를 확인합니다.
sudo crictl ps | grep etcd
kubectl get pods -n kube-system -o wide | grep etcd
sudo kubeadm certs check-expiration
외부 etcd를 사용하는 구성은 인증서 경로와 갱신 절차가 다르므로 별도 운영 절차를 따릅니다.
5. 인증서 및 PKI 취약점 점검 및 보완
5.1 인증서 만료 점검
마스터 노드에서 실행합니다.
파일 기준으로도 확인합니다.
sudo openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -subject -issuer -dates
sudo openssl x509 -in /etc/kubernetes/pki/front-proxy-client.crt -noout -subject -issuer -dates
sudo openssl x509 -in /etc/kubernetes/pki/etcd/server.crt -noout -subject -issuer -dates
sudo openssl x509 -in /etc/kubernetes/pki/etcd/peer.crt -noout -subject -issuer -dates
sudo openssl x509 -in /etc/kubernetes/pki/etcd/healthcheck-client.crt -noout -subject -issuer -dates
5.2 인증서 만료 보완
사전 백업을 수행합니다.
BACKUP_DIR=/root/k8s-cert-backup-$(date +%Y%m%d-%H%M%S)
sudo mkdir -p ${BACKUP_DIR}
sudo cp -a /etc/kubernetes/pki ${BACKUP_DIR}/
sudo cp -a /etc/kubernetes/*.conf ${BACKUP_DIR}/
kubeadm 기반 클러스터에서 인증서를 갱신합니다.
kubeadm certs renew all은 admin.conf, controller-manager.conf,
scheduler.conf, super-admin.conf에 포함된 client certificate도 함께 갱신합니다.
별도로 kubeconfig 재생성이 필요한 경우에만 백업 후 다음 명령을 사용합니다. 기존
파일이 있으면 kubeadm이 덮어쓰지 않을 수 있으므로 출력 메시지를 확인합니다.
갱신 후 확인합니다.
sudo kubeadm certs check-expiration
kubectl get nodes -o wide
kubectl get pods -n kube-system -o wide
5.3 API Server 인증서 SAN 점검
API Server에 VIP, FQDN 또는 특정 IP로 접속하는 구성에서는 apiserver.crt의 SAN에
실제 접속 엔드포인트가 포함되어야 합니다.
sudo openssl x509 \
-in /etc/kubernetes/pki/apiserver.crt \
-noout -text | grep -A1 "Subject Alternative Name"
확인 대상 예시는 다음과 같습니다.
IP Address:<K8S_API_VIP>
IP Address:<MASTER_NODE_IP>
DNS:<K8S_API_DNS>
DNS:kubernetes
DNS:kubernetes.default
DNS:kubernetes.default.svc
DNS:kubernetes.default.svc.cluster.local
5.4 API Server 인증서 SAN 보완
운영 중인 kubeadm 설정을 확인합니다.
설정 파일에 SAN 값을 포함합니다.
기존 API Server 인증서를 백업하고 재생성합니다.
sudo cp -a /etc/kubernetes/pki/apiserver.crt /etc/kubernetes/pki/apiserver.crt.bak.$(date +%Y%m%d%H%M%S)
sudo cp -a /etc/kubernetes/pki/apiserver.key /etc/kubernetes/pki/apiserver.key.bak.$(date +%Y%m%d%H%M%S)
sudo rm -f /etc/kubernetes/pki/apiserver.crt /etc/kubernetes/pki/apiserver.key
sudo kubeadm init phase certs apiserver --config /path/to/kubeadm-config.yaml
sudo systemctl restart kubelet
SAN 반영을 확인합니다.
sudo openssl x509 \
-in /etc/kubernetes/pki/apiserver.crt \
-noout -text | grep -A1 "Subject Alternative Name"
5.5 인증서 공유 여부 점검
Kubernetes 인증서와 개인키를 MariaDB, Harbor, Jenkins, Ingress 등 다른 서비스에서 공유하지 않아야 합니다.
sudo find /etc/kubernetes/pki -maxdepth 3 -type f -print
sudo grep -RInE "/etc/kubernetes/pki|apiserver\.crt|apiserver\.key|front-proxy|etcd/server" \
/etc /opt /app 2>/dev/null
다른 서비스에서 다음과 같이 Kubernetes 인증서를 직접 참조하면 안 됩니다.
ssl-ca=/etc/kubernetes/pki/ca.crt
ssl-cert=/etc/kubernetes/pki/apiserver.crt
ssl-key=/etc/kubernetes/pki/apiserver.key
5.6 인증서 공유 보완
서비스별 인증서를 별도로 발급합니다.
| 서비스 | 인증서 기준 |
|---|---|
| Kubernetes | Kubernetes PKI 전용 |
| MariaDB | MariaDB 서버 인증서 별도 발급 |
| Harbor | Harbor 또는 Ingress 인증서 별도 발급 |
| Jenkins | Jenkins 또는 Ingress 인증서 별도 발급 |
동일한 내부 CA를 사용할 수는 있습니다.
단, 서버 인증서와 개인키는 서비스별로 분리합니다.
6. API Server 및 클러스터 상태 확인
6.1 API Server 상태 확인
실제 API Server 접속 엔드포인트 기준으로 상태를 확인합니다.
curl -k https://<K8S_API_ENDPOINT>:6443/readyz
curl --cacert /etc/kubernetes/pki/ca.crt https://<K8S_API_ENDPOINT>:6443/readyz
정상 결과는 다음과 같습니다.
6.2 클러스터 상태 확인
kubectl get nodes -o wide
kubectl get pods -n kube-system -o wide
kubectl get componentstatuses 2>/dev/null || true
Control Plane 정적 Pod 상태를 확인합니다.
kubelet 상태를 확인합니다.
7. 최종 확인 명령
sudo kubeadm certs check-expiration
kubectl get nodes -o wide
kubectl get pods -n kube-system -o wide
curl --cacert /etc/kubernetes/pki/ca.crt https://<K8S_API_ENDPOINT>:6443/readyz
sudo openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text | grep -A1 "Subject Alternative Name"
8. 최종 판정 기준
| 항목 | 기준 |
|---|---|
| API Server 설정 | 익명 접근, 권한 모드, Admission Plugin 등 운영 보안 기준 충족 |
| etcd 설정 | TLS 및 인증서 기반 통신 설정 확인 |
| API Server SAN | 실제 접속 VIP, FQDN 또는 IP 포함 |
| API Server 상태 | /readyz 응답 ok |
| Node 상태 | Ready |
| Control Plane Pod | Running |
| 인증서 만료 | 운영 기준 기간 이상 남음 |
| 인증서 공유 | Kubernetes 인증서와 개인키를 타 서비스에서 미사용 |