Security - 인증서 생성 방법

2026. 1. 1. 18:01·CKA

Kubernetes 클러스터는 “컴포넌트가 서로 계속 통신하는 분산 시스템”입니다.
그래서 클러스터 보안의 핵심은 결국 이 한 줄로 귀결됩니다.

“누가 누구인지 증명(mTLS)하고, 통신을 암호화(TLS)한다.”

이 글은 강의 흐름 그대로, OpenSSL로 인증서를 직접 생성하는 과정을 초보자도 따라갈 수 있게 정리합니다.

    1. 클러스터 CA(루트) 만들기
    1. 클라이언트 인증서 만들기(관리자/스케줄러/컨트롤러/프록시 등)
    1. 서버 인증서 만들기(etcd / kube-apiserver / kubelet)
    1. kube-apiserver SAN(대체이름) 왜 중요한지
    1. 각 컴포넌트에 인증서/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)

공통 패턴

서버 인증서도 흐름은 동일합니다.

  1. 개인키 생성
  2. CSR 생성(CN 지정)
  3. 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 서버가 불리는 대표 이름들:

  • kubernetes
  • kubernetes.default
  • kubernetes.default.svc
  • kubernetes.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
'CKA' 카테고리의 다른 글
  • Security - CSR API
  • Security - 인증서 상태 점검 방법
  • Security - TLS in Kubernetes
  • Security - SSH 프로세스 정리
5jyan5
5jyan5
  • 5jyan5
    jyan
    5jyan5
  • 전체
    오늘
    어제
    • 분류 전체보기 (243)
      • 김영한의 스프링 핵심 원리(기본편) (8)
      • 김영한의 스프링 핵심 원리 - 고급편 (11)
      • 김영한의 스프링 MVC 1편 (1)
      • 김영한의 스프링 DB 1편 (3)
      • 김영한의 스프링 MVC 2편 (3)
      • 김영한의 ORM 표준 JPA 프로그래밍(기본편) (9)
      • 김영한의 스프링 부트와 JPA 활용2 (2)
      • 김영한의 실전 자바 - 중급 1편 (1)
      • 김영한의 실전 자바 - 고급 1편 (9)
      • 김영한의 실전 자바 - 고급 2편 (9)
      • Readable Code: 읽기 좋은 코드를 작성.. (2)
      • 김영한의 실전 자바 - 고급 3편 (9)
      • CKA (119)
      • 개발 (37)
      • 경제 (4)
      • 리뷰 (1)
      • 정보 (2)
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

      @discriminatorcolumn
      빈 후처리기
      typequery
      jpq
      단방향 맵핑
      조회 성능 최적화
      log trace
      jdk 동적 프록시
      hibernate5module
      버퍼
      김영한
      @within
      자바
      페치 조인
      WAS
      reentarantlock
      락
      고급
      Thread
      프록시 팩토리
      Target
      양방향 맵핑
      JPQL
      스레드
      프록시
      @discriminatorvalue
      @args
      requset scope
      cglib
      gesingleresult
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.2
    5jyan5
    Security - 인증서 생성 방법
    상단으로

    티스토리툴바