Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

기본 생성된 kubeconfig 파일의 내용을 새롭게 생성한 인증서로 구성하는 방법

지난 글에서,

kubectl 수행 시 다른 k8s 클러스터로 접속하는 방법
; https://www.sysnet.pe.kr/2/0/12583

결국 중요한 것은 config 파일만 있으면 해당 config과 연관된 k8s 클러스터를 자유롭게 접근하는 것이 가능하다는 것을 알았습니다. 그렇다는 것은, config 파일을 다른 곳으로 복사해야 한다는 것을 의미합니다.

혹시 새롭게 인증서를 생성해서 주는 방법은 없을까요? 아래의 글을 읽어봤다면,

openssl - CA로부터 인증받은 새로운 인증서를 생성하는 방법
; https://www.sysnet.pe.kr/2/0/12570

이것이 가능하다는 것을 알 수 있을 것입니다. 즉, 새롭게 client 측에서 사용할 개인키를 생성하고 인증서 요청 파일(csr)을 만든 다음 CA 서버의 개인키와 인증서로 서명을 하면 되는 것입니다.

실제로 한 번 해볼까요? ^^




자, 그럼 먼저 개인키를 하나 생성해 보겠습니다.

C:\temp\pki\cluster2> openssl genrsa -out client-side.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
............+++++
.+++++
e is 65537 (0x010001)

k8s가 요구하는 인증서 규약에 따라,

PKI certificates and requirements
; https://kubernetes.io/docs/setup/best-practices/certificates/

다음의 cnf 파일을 만들고,

FQDN = testusr
ORGNAME = system:masters

[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[ dn ]
CN = $FQDN
O = $ORGNAME

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster
DNS.5 = kubernetes.default.svc.cluster.local
IP.1 = 127.0.0.1

[ v3_ext ]
authorityKeyIdentifier=keyid,issuer:always
basicConstraints=CA:FALSE
keyUsage=keyEncipherment,dataEncipherment
extendedKeyUsage=serverAuth,clientAuth
subjectAltName=@alt_names

CSR 파일을 생성합니다.

C:\temp\pki\cluster2> openssl req -new -key client-side.key -out client.csr -config client.cnf

이렇게 생성한 csr 파일을 이제 CA 인증서로 서명을 하면 되는데요, 이를 위해 필요한 파일이 CA 인증서와 개인키입니다. 이 파일들을 구하는 방법은 해당 k8s 클러스터와 관계된 pki 디렉터리를 찾아야 합니다. 이에 대해서는 이미 다음의 글에서 설명했는데요,

Docker Desktop for Windows 기반의 Kubernetes 구성 (2) - WSL 2 인스턴스에 kind가 구성한 k8s 서비스 위치
; https://www.sysnet.pe.kr/2/0/12578#cert_path

여기서는 k8s를 kind로 구성한 경우를 예로 들겠습니다. 이를 위해 해당 k8s를 호스팅하는 컨테이너를 알아내고,

C:\temp\pki\cluster2> docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED        STATUS        PORTS                       NAMES
62cd9120f957   kindest/node:v1.20.2   "/usr/local/bin/entr…"   3 days ago     Up 3 days     127.0.0.1:20971->6443/tcp   cluster2-control-plane

그 컨테이너 내에 위치한 /etc/kubernetes/pki 디렉터리의 파일들을 로컬로 복사해 온 다음 (또는, 정확하게 ca.crt, ca.key 파일만 복사),

C:\temp\test> docker cp 62cd9120f957:/etc/kubernetes/pki .

로컬에 복사된 ca.crt, ca.key 파일을 사용해 다음과 같이 클라이언트 인증서의 요청 파일을 서명해 줍니다.

C:\temp\pki\cluster2> openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 10000 -extensions v3_ext -extfile client.cnf
Signature ok
subject=CN = testusr, O = system:masters
Getting CA Private Key

이렇게 해서 새로 생성된 client.crt 파일과 client-side.key, ca.crt 파일만 있으면 이제 다음과 같이 kubectl을 사용할 수 있습니다.

C:\temp\pki\cluster2> kubectl get nodes --server https://127.0.0.1:20971 --client-certificate client.crt --client-key client-side.key --certificate-authority ca.crt
NAME                     STATUS   ROLES                  AGE    VERSION
cluster2-control-plane   Ready    control-plane,master   3d7h   v1.20.2




자, 그럼 절차가 정해졌군요. 만약 다른 사람이 여러분들의 k8s 클러스터에 접근하고 싶다면 간단하게는 여러분들이 사용하는 config 파일을 전달하면 됩니다. 혹은, 상대방에게 CSR 파일을 달라고 해 그것을 자신이 운영하고 있는 k8s 클러스터의 ca.crt, ca.key 파일로 csr 파일을 서명 후 생성된 crt 파일과 ca.crt 파일을 함께 전달해 주면 됩니다.

그럼 상대 측은 전달받은 client.crt, ca.crt 파일과 함께 자신이 가지고 있는 client-side.key 파일을 이용해 kubectl 명령어를 실행할 수 있게 됩니다. (사실, 이것은 SSL 인증서나 소프트웨어 인증서를 취득하는 과정과 정확히 일치합니다.)

물론, 명령행에 일일이 "--client-certificate client.crt --client-key client-side.key --certificate-authority ca.crt" 옵션을 넣는 것은 귀찮으므로 지난 글에서 설명한 방법을 이용해,

kubectl config --kubeconfig=config-demo set-cluster kind-cluster3 --server=https://127.0.0.1:20971 --certificate-authority="ca.crt"
kubectl config --kubeconfig=config-demo set-credentials kind-cluster3 --client-certificate="client.crt" --client-key="client-side.key"
kubectl config --kubeconfig=config-demo set-context kind-cluster3 --cluster=kind-cluster3 --user=kind-cluster3
kubectl config --kubeconfig=config-demo use-context kind-cluster3

kubeconfig 파일을 생성해 두는 것도 좋을 것입니다.

apiVersion: v1
clusters:
- cluster:
    certificate-authority: ca.crt
    server: https://127.0.0.1:20971
  name: kind-cluster3
contexts:
- context:
    cluster: kind-cluster3
    user: kind-cluster3
  name: kind-cluster3
current-context: kind-cluster3
kind: Config
preferences: {}
users:
- name: kind-cluster3
  user:
    client-certificate: client.crt
    client-key: client-side.key

그런데 위와 같이 설정해 두면 ca.crt, client.crt, client-side.key 파일을 함께 들고 다녀야 하므로 불편하니, 각각의 파일 내용을 base64 인코딩 시켜 kubeconfig 파일 내에 합치는 것이 좋습니다.

이를 위해 ca.crt를 certificate-authority-data로, client.crt를 client-certificate-data로, client-side.key를 client-key-data로 각각 값을 설정하면 됩니다. (base64 명령어는 윈도우의 경우 없으므로 별도로 다운로드해야 합니다.)

C:\temp\pki\cluster2> base64 -w 0 ca.crt | clip
// clipboard에 복사되었으므로 config-demo 파일의 certificate-authority-data로 복사

C:\temp\pki\cluster2> base64 -w 0 client.crt | clip
// clipboard에 복사되었으므로 config-demo 파일의 client-certificate-data로 복사

C:\temp\pki\cluster2> base64 -w 0 client-side.key | clip
// clipboard에 복사되었으므로 config-demo 파일의 client-key-data로 복사

그럼 config-demo의 최종 파일 구성이 다음과 같이 될 것이고,

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS...[생략]...LS0tCg==
    server: https://127.0.0.1:20971
  name: kind-cluster3
contexts:
- context:
    cluster: kind-cluster3
    user: kind-cluster3
  name: kind-cluster3
current-context: kind-cluster3
kind: Config
preferences: {}
users:
- name: kind-cluster3
  user:
    client-certificate-data: LS0tLS1CRU...[생략]...tCg==
    client-key-data: LS0tLS1CR...[생략]...S0tCg==

이제 별다른 부가 파일 필요 없이 config-demo 파일 하나로 kubectl 명령어를 수행할 수 있습니다.

C:\temp\pki\cluster2> kubectl cluster-info --kubeconfig=config-demo
Kubernetes master is running at https://127.0.0.1:20971
KubeDNS is running at https://127.0.0.1:20971/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy





지난 글에서 configmaps에 CA 인증서를 담고 있는 것을 설명했는데요,

kubeconfig 파일 없이 kubectl 옵션만으로 실행하는 방법
; https://www.sysnet.pe.kr/2/0/12584#configmaps

C:\temp\wsl2> kubectl get configmaps
NAME               DATA   AGE
kube-root-ca.crt   1      11h

그렇다면 혹시 또 다른 CA 인증서를 등록하는 것도 가능할까요? ^^ 일단 다음과 같은 식으로 명령을 내리면,

C:\temp\wsl2> kubectl create configmap test-ca.crt --from-file=C:\temp\wsl2\ca.crt
configmap/test-ca.crt created

C:\temp\wsl2> kubectl get configmaps
NAME               DATA   AGE
kube-root-ca.crt   1      27h
test-ca.crt        1      6s

test-ca.crt는 kube-root-ca.crt와 동일한 양식으로 등록은 됩니다.

C:\temp\wsl2> kubectl describe configmaps test-ca.crt
Name:         test-ca.crt
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
ca.crt:
----
-----BEGIN CERTIFICATE-----
MIIDCTCCAfGgAwIBAgIUc57N5ZHozrDio2hBQlOLB2iCfs4wDQYJKoZIhvcNAQEL
...[생략]...
q1gObmghvUdhkdx1u8iNtKTua3czzwpzuOhsp7H0GFVh5jlK+RoD0rrlHEubIt4L
Zij0Yk2SrgxO3GvA1Q==
-----END CERTIFICATE-----

Events:  <none>

동작 여부는, 나중에 시간 나면 확인해 보겠습니다. ^^




참고로 openssl의 cnf 파일에 있는 FQDN은 임의의 값을 넣어도 되지만, 이 외의 값들(예를 들어, ORGNAME)은 가능한 규격을 지켜야 합니다. 만약 (ORGNAME으로 인한) O = system:masters 설정이 없으면,

FQDN = testusr

[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
...[생략]...

kubectl 실행 시 다음과 같은 오류가 발생합니다.

C:\temp\pki\cluster2> kubectl get nodes --server https://127.0.0.1:20971 --client-certificate client.crt --client-key client-side.key --certificate-authority ca.crt
Error from server (Forbidden): nodes is forbidden: User "testusr" cannot list resource "nodes" in API group "" at the cluster scope




"kubectl create configmap... " 명령어 수행 시 다음과 같은 오류가 발생한다면?

C:\temp\wsl2> kubectl create configmap test_ca.crt --from-file=C:\temp\wsl2\ca.crt
The ConfigMap "test_ca.crt" is invalid: metadata.name: Invalid value: "test_ca.crt": a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')

오류 메시지에 볼 수 있는 것처럼, configmap의 이름으로 지정할 수 있는 값에 밑줄(underscore, _)은 유효하지 않은 문자이므로, '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*' 정규 표현식을 만족하는 범위 내의 문자로 이름을 지어야 합니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]



donaricano-btn



[최초 등록일: ]
[최종 수정일: 4/5/2021

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 쓴 사람
 




1  2  3  4  5  [6]  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
12715정성태7/17/2021898오류 유형: 736. Windows - MySQL zip 파일 버전의 "mysqld --skip-grant-tables" 실행 시 비정상 종료
12714정성태7/16/2021239오류 유형: 735. VCRUNTIME140.dll, MSVCP140.dll, VCRUNTIME140.dll, VCRUNTIME140_1.dll이 없어 exe 실행이 안 되는 경우
12713정성태7/16/2021284.NET Framework: 1077. C# - 동기 방식이면서 비동기 규약을 따르게 만드는 Task.FromResult파일 다운로드1
12712정성태7/15/2021194개발 환경 구성: 579. Azure - 리눅스 호스팅의 Site Extension 제작 방법
12711정성태7/15/2021200개발 환경 구성: 578. Azure - Java Web App Service를 위한 Site Extension 제작 방법
12710정성태7/15/2021266개발 환경 구성: 577. MQTT - emqx.io 서비스 소개
12709정성태7/14/2021145Linux: 42. 실행 중인 docker 컨테이너에 대한 구동 시점의 docker run 명령어를 확인하는 방법
12708정성태7/14/2021246Linux: 41. 리눅스 환경에서 디스크 용량 부족 시 원인 분석 방법
12707정성태7/14/2021402오류 유형: 734. MySQL - Authentication method 'caching_sha2_password' not supported by any of the available plugins.
12706정성태7/14/2021345.NET Framework: 1076. C# - AsyncLocal 기능을 CallContext만으로 구현하는 방법 [1]파일 다운로드1
12705정성태7/13/2021239VS.NET IDE: 168. x64 DLL 프로젝트의 컨트롤이 Visual Studio의 Designer에서 보이지 않는 문제 - 두 번째 이야기
12704정성태7/12/2021173개발 환경 구성: 576. Azure VM의 서비스를 Azure Web App Service에서만 접근하도록 NSG 설정을 제한하는 방법
12703정성태7/11/2021218개발 환경 구성: 575. Azure VM에 (ICMP) ping을 허용하는 방법
12702정성태7/11/2021175오류 유형: 733. TaskScheduler에 등록된 wacs.exe의 Let's Encrypt 인증서 업데이트 문제
12701정성태7/9/2021215.NET Framework: 1075. C# - ThreadPool의 스레드는 반환 시 ThreadStatic과 AsyncLocal 값이 초기화 될까요?파일 다운로드1
12700정성태7/8/2021349.NET Framework: 1074. RuntimeType의 메모리 누수? [1]
12699정성태7/8/2021268VS.NET IDE: 167. Visual Studio 디버깅 중 GC Heap 상태를 보여주는 "Show Diagnostic Tools" 메뉴 사용법
12698정성태7/7/2021537오류 유형: 732. Windows 11 업데이트 시 3% 또는 0%에서 다운로드가 멈춘 경우
12697정성태7/7/2021404개발 환경 구성: 574. Windows 11 (Insider Preview) 설치하는 방법
12696정성태7/6/2021322VC++: 146. 운영체제의 스레드 문맥 교환(Context Switch)을 유사하게 구현하는 방법파일 다운로드2
12695정성태7/3/2021302VC++: 145. C 언어의 setjmp/longjmp 기능을 Thread Context를 이용해 유사하게 구현하는 방법파일 다운로드1
12694정성태7/2/2021160Java: 24. Azure - Spring Boot 앱을 Java SE(Embedded Web Server)로 호스팅 시 로그 파일 남기는 방법
12693정성태6/30/2021167오류 유형: 731. Azure Web App Site Extension - Failed to install web app extension [...]. {1}
12692정성태6/30/2021322디버깅 기술: 180. Azure - Web App의 비정상 종료 시 남겨지는 로그 확인
12691정성태6/30/2021228개발 환경 구성: 573. 테스트 용도이지만 테스트에 적합하지 않은 Azure D1 공유(shared) 요금제
12690정성태6/28/2021371Java: 23. Azure - 자바(Java)로 만드는 Web App Service - Tomcat 호스팅
1  2  3  4  5  [6]  7  8  9  10  11  12  13  14  15  ...