Kubernetes 클러스터는 “컴포넌트가 서로 계속 통신하는 분산 시스템”입니다.
그래서 클러스터 보안의 핵심은 결국 이 한 줄로 귀결됩니다.
“누가 누구인지 증명(mTLS)하고, 통신을 암호화(TLS)한다.”
이 글은 강의 흐름 그대로, OpenSSL로 인증서를 직접 생성하는 과정을 초보자도 따라갈 수 있게 정리합니다.
-
- 클러스터 CA(루트) 만들기
- 클라이언트 인증서 만들기(관리자/스케줄러/컨트롤러/프록시 등)
- 서버 인증서 만들기(etcd / kube-apiserver / kubelet)
- kube-apiserver SAN(대체이름) 왜 중요한지
- 각 컴포넌트에 인증서/CA를 어디에 설정하는지(플래그/쿠브컨피그)
참고: kubeadm 환경에서는 대부분 이미 만들어져 있고
/etc/kubernetes/pki에 있습니다. 이 글은 “원리/수동 구성” 이해에 초점을 둡니다.
0) 먼저 큰 그림: Kubernetes에서 “서버 인증서 vs 클라이언트 인증서”
Kubernetes TLS는 단순히 “암호화”만이 아니라 서버/클라이언트 상호 인증(mTLS)이 핵심입니다.
서버 인증서(Serving cert)가 필요한 컴포넌트
- kube-apiserver: HTTPS API 서버
- etcd: HTTPS로 API 서버가 붙는 저장소
- kubelet: 각 노드의 HTTPS 엔드포인트(상태/exec/log 등)
클라이언트 인증서(Client cert)가 필요한 주체
- 관리자(kubectl)
- scheduler, controller-manager, kube-proxy
- kube-apiserver → etcd 로 접근할 때의 클라이언트 신원
- kube-apiserver → kubelet 로 접근할 때의 클라이언트 신원
- kubelet이 API 서버에 붙는 신원(노드 신원)
그리고 중요한 전제:
서버와 클라이언트 모두 “서로를 검증”하려면 CA의 루트 인증서(ca.crt) 를 신뢰 목록에 가지고 있어야 합니다.
1) 파일 이름 규칙(초보자 혼동 방지)
강의에서 말한 규칙은 아주 유용합니다.
- 보통 인증서(공개키 포함):
.crt또는.pem - 보통 개인키:
.key(또는 파일명에key)
단, 실무 팁 하나:
.pem은 “포맷”이라서, 인증서도 들어갈 수 있고 개인키도 들어갈 수 있습니다.
확장자만 믿지 말고 필요하면openssl로 확인하세요.
# 인증서인지 확인
openssl x509 -in file.crt -noout -text
# 개인키인지 확인
openssl pkey -in file.key -noout -text
2) Step 1. 클러스터 CA(루트) 만들기
CA는 “클러스터 내 모든 인증서를 서명해주는 최상위 발급자”입니다.
CA 개인키(ca.key) 가 유출되면 클러스터 신분증을 무한 발급할 수 있으므로 최우선 보호 대상입니다.
2.1 CA 개인키 생성
openssl genrsa -out ca.key 2048
2.2 CA 인증서(루트 인증서) 생성 (Self-Signed)
openssl req -x509 -new -nodes \
-key ca.key \
-subj "/CN=Kubernetes-CA" \
-days 3650 \
-out ca.crt
CN(Common Name)은 “이 인증서의 이름”- CA는 자기 자신을 서명(Self-signed)합니다.
3) Step 2. 클라이언트 인증서 만들기 (관리자부터)
클라이언트 인증서는 “API 서버에 접근하는 주체의 신원”입니다.
강의에서 말한 비유가 아주 정확합니다:
- 인증서 = 신분증
- 개인키 = 비밀번호(절대 공유하면 안 됨)
3.1 관리자(admin) 키/CSR/인증서
(1) 개인키
openssl genrsa -out admin.key 2048
(2) CSR 생성 (CN=사용자 이름)
관리자 권한을 주려면 보통 O(organization) 또는 OU에 그룹을 넣습니다.
Kubernetes에서 대표적인 관리자 그룹은 system:masters 입니다.
openssl req -new \
-key admin.key \
-subj "/CN=kube-admin/O=system:masters" \
-out admin.csr
(3) CA로 서명해서 인증서 발급
openssl x509 -req \
-in admin.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-out admin.crt \
-days 365
이렇게 발급된
admin.crt/admin.key는 kubectl 또는 kubeconfig에서 사용됩니다.
3.2 scheduler / controller-manager / kube-proxy 클라이언트 인증서
이 컴포넌트들은 “API 서버에 붙는 클라이언트”입니다.
강의 포인트:
- control plane 시스템 컴포넌트는 관례적으로
system:prefix를 붙이는 경우가 많음(환경/설계에 따라 다름). - 중요한 건 CN 값이 API 서버 로그/감사 로그에서 식별되는 실제 사용자/컴포넌트 이름이라는 점.
예시(개념용):
kube-scheduler
openssl genrsa -out scheduler.key 2048
openssl req -new -key scheduler.key -subj "/CN=system:kube-scheduler" -out scheduler.csr
openssl x509 -req -in scheduler.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out scheduler.crt -days 365
kube-controller-manager
openssl genrsa -out controller-manager.key 2048
openssl req -new -key controller-manager.key -subj "/CN=system:kube-controller-manager" -out controller-manager.csr
openssl x509 -req -in controller-manager.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out controller-manager.crt -days 365
kube-proxy
openssl genrsa -out kube-proxy.key 2048
openssl req -new -key kube-proxy.key -subj "/CN=system:kube-proxy" -out kube-proxy.csr
openssl x509 -req -in kube-proxy.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out kube-proxy.crt -days 365
실무에서는 이 인증서/키가 “별도 파일”로 존재하기도 하지만, kubeconfig 내부에 base64로 포함되는 경우가 많습니다.
4) Step 3. 서버 인증서 만들기 (etcd → apiserver → kubelet)
공통 패턴
서버 인증서도 흐름은 동일합니다.
- 개인키 생성
- CSR 생성(CN 지정)
- CA로 서명해서 인증서 발급
4.1 etcd 서버 인증서
(1) 개인키
openssl genrsa -out etcd-server.key 2048
(2) CSR
openssl req -new -key etcd-server.key -subj "/CN=etcd-server" -out etcd-server.csr
(3) 서명
openssl x509 -req -in etcd-server.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-out etcd-server.crt -days 365
etcd가 여러 대(HA)면?
- etcd 서버끼리 통신(peer)이 필요하므로 peer 인증서가 추가로 필요합니다.
- 또한 healthcheck 전용 클라이언트 인증서가 따로 쓰이기도 합니다(kubeadm 기준).
4.2 kube-apiserver 서버 인증서 (SAN이 핵심)
강의에서 가장 중요한 포인트가 이 부분입니다.
API 서버는 여러 이름으로 불립니다.
그 이름들이 인증서의 SAN(Subject Alternative Name)에 모두 들어 있어야 TLS 검증이 통과합니다.
API 서버가 불리는 대표 이름들:
kuberneteskubernetes.defaultkubernetes.default.svckubernetes.default.svc.cluster.local- API 서버 서비스 IP (보통
10.96.0.1같은 ClusterIP) - control-plane 노드 IP / 로드밸런서 IP / 도메인 등(구성에 따라)
(1) 개인키
openssl genrsa -out apiserver.key 2048
(2) OpenSSL 설정 파일 작성 (SAN 포함)
apiserver-openssl.cnf 예시:
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = v3_req
distinguished_name = dn
[ dn ]
CN = kube-apiserver
[ v3_req ]
keyUsage = keyEncipherment, digitalSignature
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster.local
# 보통 서비스 IP(예시)
IP.1 = 10.96.0.1
# control-plane 노드 IP(예시)
IP.2 = 192.168.0.10
(3) CSR 생성(설정 파일 포함)
openssl req -new -key apiserver.key -out apiserver.csr -config apiserver-openssl.cnf
(4) CA로 서명(확장 포함)
openssl x509 -req -in apiserver.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-out apiserver.crt -days 365 \
-extensions v3_req -extfile apiserver-openssl.cnf
4.3 kubelet 서버 인증서 (노드별로 1개씩)
kubelet은 “각 노드의 HTTPS 서버”입니다. 그래서 노드마다 서버 인증서가 필요합니다.
핵심:
- kubelet 서버 인증서는 노드 이름 기준으로 CN을 구성하는 경우가 많습니다.
- 또한 kubelet도 API 서버에 붙는 “클라이언트 인증서”가 별도로 필요합니다(아래 4.4).
예: node01의 kubelet 서버 인증서
openssl genrsa -out node01-kubelet.key 2048
openssl req -new -key node01-kubelet.key -subj "/CN=node01" -out node01-kubelet.csr
openssl x509 -req -in node01-kubelet.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-out node01-kubelet.crt -days 365
4.4 kubelet이 API 서버에 붙을 때의 “노드 클라이언트 인증서”
강의의 매우 중요한 포인트:
API 서버는 “이 클라이언트가 어떤 노드인지” 알아야 권한을 줄 수 있다.
그래서 노드 클라이언트 인증서는 관례적으로system:node:<노드이름>형태를 쓴다.
그리고 그룹은system:nodes로 묶는다.
예: node01 노드 클라이언트 인증서
openssl genrsa -out node01-client.key 2048
openssl req -new -key node01-client.key \
-subj "/CN=system:node:node01/O=system:nodes" \
-out node01-client.csr
openssl x509 -req -in node01-client.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-out node01-client.crt -days 365
이 형식이 맞아야 Kubernetes의 Node Authorizer/RBAC 흐름에서 정상 권한 매핑이 됩니다.
5) 생성한 인증서/키는 어디에 “설정”하나?
강의에서 말한 것처럼, 단순히 파일을 만든다고 끝이 아닙니다.
각 컴포넌트가 실행될 때 “이 인증서를 써라”라고 연결해줘야 합니다.
5.1 kube-apiserver (대표 플래그)
- 서버로서 사용할 인증서/키
- 클라이언트 인증서 검증을 위한 CA
- etcd 접속용 클라이언트 인증서/키 + etcd CA
- kubelet 접속용 클라이언트 인증서/키
대표적으로 이런 축입니다(환경마다 플래그명/경로는 다를 수 있음).
--tls-cert-file=apiserver.crt--tls-private-key-file=apiserver.key--client-ca-file=ca.crt--etcd-cafile=ca.crt(또는 etcd 전용 CA)--etcd-certfile=apiserver-etcd-client.crt--etcd-keyfile=apiserver-etcd-client.key--kubelet-client-certificate=apiserver-kubelet-client.crt--kubelet-client-key=apiserver-kubelet-client.key
5.2 etcd
--cert-file=etcd-server.crt--key-file=etcd-server.key--trusted-ca-file=ca.crt- HA이면 peer용
--peer-cert-file,--peer-key-file,--peer-trusted-ca-file등
5.3 kubectl/컴포넌트 클라이언트
- curl로 직접 호출할 수도 있지만 보통 kubeconfig에 넣습니다.
- kubeconfig에는 최소 3개가 들어갑니다.
- client cert
- client key
- CA cert
6) 운영/보안 관점에서 꼭 짚고 넘어갈 리스크
6.1 CA 개인키 유출 = 클러스터 붕괴급
- 공격자가 마음대로 “유효한 인증서”를 발급 가능
- 결과적으로 가짜 컴포넌트/가짜 노드/가짜 관리자 신분증 발급 가능
방어:
ca.key접근권한 최소화, 오프라인 보관 고려- 파일 권한/소유자 강제
- 만료/회전 계획
6.2 apiserver SAN 누락 = “갑자기 접속이 안 됨”의 원흉
kubectl이https://kubernetes.default.svc로 붙는데 cert SAN에 없으면 TLS 검증 실패- 로드밸런서 도메인/새 IP 추가 시도 SAN에 없으면 장애
방어:
- API 서버가 실제로 불리는 DNS/IP를 먼저 확정하고 SAN에 포함
- 변경 시 인증서 재발급/롤링 반영
6.3 CN/O(그룹) 규칙 틀리면 “인증은 되는데 권한이 없음”
- 인증서로 “누구인지”는 알겠는데 RBAC/노드권한 매핑이 안 되는 케이스
- 예: 노드 클라이언트 인증서 CN을
system:node:<node>로 안 만들면 꼬임
방어:
- 시스템 컴포넌트/노드/관리자 CN/O 관례를 준수
마무리 요약
- Kubernetes TLS는 (1) 암호화 + (2) 서버/클라이언트 상호 인증(mTLS) 구조다.
- CA를 만들고(ca.crt/ca.key), 모든 인증서는 그 CA로 서명한다.
- 클라이언트 인증서(CN/O)는 “누구인지 + 어느 그룹인지”를 표현하고 권한과 연결된다.
- kube-apiserver 서버 인증서는 SAN이 핵심이며, 누락 시 운영 장애로 직결된다.
- 생성한 인증서는 컴포넌트 실행 플래그 또는 kubeconfig에 연결해야 실제로 적용된다.
'CKA' 카테고리의 다른 글
| Security - CSR API (0) | 2026.01.01 |
|---|---|
| Security - 인증서 상태 점검 방법 (1) | 2026.01.01 |
| Security - TLS in Kubernetes (0) | 2026.01.01 |
| Security - SSH 프로세스 정리 (0) | 2026.01.01 |
| Security - 대칭키/비대칭키/CA (0) | 2026.01.01 |