주변에서 생각보다 Kubernetes CSR의 존재를 잘 모르거나, 단순히 cert-manager에서 사용하는 리소스 정도로 알고있는 경우가 있어 이번 기회에 정리하고자 한다.
Kubernetes CSR은 v1.19에서 GA된 기능으로 admission controller가 한창 이목을 끌며 떠오를때 함께 알게되었던 개념이었다.
CSR 리소스의 개념
CertificateSigningRequest는 Kubernetes API 리소스 중 하나로, 사용자가 클러스터 내에서 인증서 서명 요청을 제출하고, 클러스터 내 CA가 이를 승인하여 X.509 인증서를 발급해주는 과정을 위한 리소스이다.
CSR 리소스를 사용하면 외부에서 수작업 없이, 자동화된 방식으로 인증서를 생성하고 관리할 수 있다.
경험을 바탕으로 설명하자면, multi cluster를 관리하는 플랫폼 혹은 제품들에서 service account를 생성하고, cluster admin 권한을 할당하여 auto generate 되는 secret token을 kubeconfig에 주입해 사용하는 일반적인 방법과 달리 kubelet, 사용자 kubeconfig, 서비스메쉬 등 관리 측면의 역할(Role) 인증에서 주로 사용되는 방법이다.
이때 사용되는 방법이 두 가지가 있다.
1. 쿠버네티스 CA와 조합하여 CRT 인증을 만들어 사용하기
2. CertificateSigningRequest를 사용하기
CSR 리소스의 구조부터 사용 방법을 차례로 알아보자
CSR 리소스의 구조
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: my-csr
spec:
request: <Base64-encoded CSR>
signerName: kubernetes.io/kube-apiserver-client
usages:
- client auth
username: alice
groups:
- system:authenticated
status:
conditions:
- type: Approved
reason: ...
message: ...
certificate: <Base64-encoded X.509 certificate> # 서명된 인증서
- spec.request: openssl 등으로 생성한 CSR 파일을 base64 인코딩한 값
- spec.signerName: 어떤 인증서 발급자가 서명할 것인지 (예: kubernetes.io/kube-apiserver-client)
- spec.usages: 인증서의 용도 (예: client auth, server auth)
digital signature | 서명용 (TLS 핸드셰이크, 인증서 증명) | KeyUsage: digitalSignature |
key encipherment | 키 암호화 (TLS 키 교환) | KeyUsage: keyEncipherment |
server auth | 서버 인증용 인증서 | ExtendedKeyUsage: serverAuth |
client auth | 클라이언트 인증용 인증서 | ExtendedKeyUsage: clientAuth |
- status.certificate: 인증기관(CA)이 서명한 최종 X.509 인증서가 여기에 포함됨
- status.conditions: 승인(Approved) 혹은 거절(Denied) 여부
다음으로, CSR을 생성하고 사용하는 방법을 살펴보자.
CSR 발급 워크플로우
- CSR 생성
사용자 또는 노드가 CSR (X.509 Certificate Signing Request)을 생성
→ 일반적으로 OpenSSL 또는 Go 코드로 .csr 파일 생성 - CSR 리소스 제출
Base64 인코딩된 CSR을 포함하여 Kubernetes에 CertificateSigningRequest 리소스로 제출 - CSR 승인 or 거부
클러스터 관리자 또는 승인 컨트롤러가 CSR을 Approved 또는 Denied로 설정
(수동 승인: kubectl certificate approve, 자동화 가능) - CA 서명 및 인증서 발급
Kubernetes의 CA가 서명을 진행하고 .status.certificate 필드에 서명된 인증서를 넣고 - 인증서 수령 및 사용
CSR 리소스를 조회하여 발급된 인증서를 추출하고, 클라이언트는 이를 자신의 신원 증명에 사용
사용 예시
# key 파일을 만든다. (개인키)
openssl genrsa -out 00103.key 2048
# Certificate Signing Request
# 아래 명령어로 csr 파일을 만든다. key를 기반으로 만듦
# csr 파일은 인증서를 요청할 때 인증 기관에 제출하는 인증서 서명 요청 파일 (.csr 또는 .pem)
openssl req -new -key 00103.key -out 00103.csr
# 위 명령 진행시 각종 정보를 입력함 이때, Common Name에 입력하는 내용이 user named가 된다.
openssl req -new -key 00103.key -out 00103.csr
위 과정까지 진행한 후 CSR 리소스를 사용하느냐, 수동 생성하느냐의 선택지로 나뉘어진다.
k8s CA로 인증하여 crt를 만드는게 아닌 CertificateSigningRequest를 사용한 방법은 다음과 같다.
# 위에서 이어서, 아래 명령어로 token을 인코딩된 출력에서 줄바꿈 없이 한 줄로 출력 후 복사
cat 00103.csr | base64 -w 0
```yaml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: 00103@internal.users # ADD
spec:
groups:
- system:authenticated
request: LS0tLS1CRUdJTiABCDEFGHIJK0JIHGFEDCBA... # ADD
signerName: kubernetes.io/kube-apiserver-client
usages:
- client auth
```
kubectl get csr # 하면 pending을 확인할 수 있음. 허가해줘야함
kubectl certificate approve 00103@internal.users
# 그리고 서명된 crt 파일을 받음
kubectl get csr 00103@internal.users -ojsonpath="{.status.certificate}" | base64 -d > 00103.crt`
kubectl config set-credentials 00103@internal.users --client-key=00103.key --client-certificate=00103.crt
kubectl config set-context 00103@internal.users --cluster=kubernetes --user=00103@internal.users
kubectl config get-contexts
kubectl config use-context 00103@internal.users
SignerName 종류
Kubernetes에서 제공하는 기본 signer는 다음과 같다.
Signer Name | 설명 |
kubernetes.io/kube-apiserver-client | kube-apiserver 클라이언트 인증서 |
kubernetes.io/kubelet-serving | kubelet의 서버 인증서 (TLS) |
kubernetes.io/kube-apiserver-client-kubelet | kubelet의 클라이언트 인증서 |
kubernetes.io/legacy-unknown | 이전 버전 호환용, 되도록 사용 지양 |
cert-manager의 signer와 같이 커스텀 signer를 설치하여 사용할 수도 있다.
Admission Controller와 CSR
CSR 리소스를 처리하기 위해 사용하는 Admission Controller는 다음과 같다.
Controller 이름 | 역할 |
CertificateApproval | 사용자의 kubectl certificate approve 요청을 감지하고 상태를 업데이트 |
CertificateSigning | 승인된 CSR을 감지하고, cluster CA로 서명된 인증서를 발급 |
CertificateSubjectRestriction | (옵션) 사용자 또는 그룹이 CSR에서 특정 주체(subject)를 요청하지 못하게 막음 |
더 알아보기: ServiceAccount token vs CSR-based 인증서
항목 | ServiceAccount Token (automount) | CSR 기반 X.509 인증서 |
인증 방식 | JWT (JSON Web Token) | X.509 인증서 (TLS 인증) |
주체 | Pod 내부의 ServiceAccount | 노드, 사용자, 외부 서비스 등 |
자동 발급 여부 | ✅ Pod 생성 시 자동 마운트 | ❌ CSR 제출 및 승인 필요 |
저장 위치 | Pod 내부 /var/run/secrets/kubernetes.io/serviceaccount/token | 별도 파일로 저장 (.crt, .key) |
사용 목적 | 주로 Pod → API Server 호출 | 노드 인증, 사용자 인증, mTLS |
인증 대상 | Kubernetes API Server | 주로 API Server or peer component |
유효기간 | 짧음 (default 1hr~3hrs), 자동 회전 가능 | 일반적으로 더 길고 수동 회전 필요 |
보안 특성 | 서명된 JWT → API Server에서 검증 | 표준 TLS 핸드셰이크 사용 |
주요 사용처 | 일반 Pod 인증 | kubelet, 사용자 kubeconfig, 서비스메쉬 등 |
더 알아보기: ServiceAccount Signing Key vs Kubernetes CA
항목 | ServiceAccount Signing Key (--service-account-signing-key-file) | Kubernetes CA (ca.crt/ca.key) |
키 종류 | JWT 서명용 RSA 키 쌍 (PEM 포맷) | X.509 인증서용 RSA/EC 키 쌍 |
파일 예 | /etc/kubernetes/pki/sa.pub, sa.key | /etc/kubernetes/pki/ca.crt, ca.key |
사용 목적 | ServiceAccount JWT 토큰 서명 및 검증 | 인증서(CSR) 서명, TLS 통신 검증 |
사용 위치 | kube-apiserver의 JWT 검증 및 발급 (--service-account-...) | kube-apiserver, kubelet 등 X.509 인증서 관련 구성 |
교차 사용 가능? | ❌ 서로 호환되지 않음 | ❌ 전혀 다름 |