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)
12790정성태8/18/2021293.NET Framework: 1094. C# 10 - (1) 구조체를 생성하는 record struct파일 다운로드1
12789정성태8/18/2021179개발 환경 구성: 597. PyCharm - 윈도우 환경에서 WSL을 이용해 파이썬 앱 개발/디버깅하는 방법
12788정성태8/17/2021548.NET Framework: 1093. C# - 인터페이스의 메서드가 다형성을 제공할까요? (virtual일까요?)파일 다운로드1
12787정성태8/17/2021685.NET Framework: 1092. (책 내용 수정) "4.5.1.4 인터페이스"의 "인터페이스와 다형성"
12786정성태8/16/2021441.NET Framework: 1091. C# - Python range 함수 구현 (2) INumber<T>를 이용한 개선 [1]파일 다운로드1
12785정성태8/16/2021257.NET Framework: 1090. .NET 6 Preview 7에 추가된 숫자 형식에 대한 제네릭 연산 지원파일 다운로드1
12784정성태8/15/2021125오류 유형: 757. 구글 메일 - 아웃룩에서 메일 전송 시 Sending' reported error (0x800CCC0F)
12783정성태8/15/2021216.NET Framework: 1089. C# - Indexer에 Range 및 람다 식을 이용한 필터 구현파일 다운로드1
12782정성태8/14/2021159오류 유형: 756. 파이썬 - 윈도우 환경에서 pytagcloud의 한글 출력 방법
12781정성태8/14/2021163오류 유형: 755. 파이썬 - konlpy 사용 시 JVM과 jpype1 관련 오류
12780정성태8/13/2021232.NET Framework: 1088. C# - 버스 노선 및 위치 정보 조회 API 사용을 위한 기초 라이브러리 [2]
12779정성태8/13/2021216개발 환경 구성: 596. 공공 데이터 포털에서 버스 노선 및 위치 정보 조회 API 사용법
12778정성태8/12/202182오류 유형: 755. PyCharm - "Manage Repositories"의 목록이 나오지 않는 문제
12777정성태8/12/2021156오류 유형: 754. Visual Studio - Input or output cannot be redirected because the specified file is invalid.
12776정성태8/12/2021553오류 유형: 753. gunicorn과 uwsgi 함께 사용 시 ERR_CONNECTION_REFUSED
12775정성태8/12/2021494스크립트: 22. 파이썬 - 윈도우 환경에서 개발한 Django 앱을 WSL 환경의 gunicorn을 이용해 실행
12774정성태8/11/2021530.NET Framework: 1087. C# - Collection 개체의 다중 스레드 접근 시 "Operations that change non-concurrent collections must have exclusive access" 예외 발생
12773정성태8/11/2021666개발 환경 구성: 595. PyCharm - WSL과 연동해 Django App을 윈도우에서 리눅스 대상으로 개발
12772정성태8/11/2021345스크립트: 21. 파이썬 - 윈도우 환경에서 개발한 Django 앱을 WSL 환경의 uwsgi를 이용해 실행
12771정성태8/11/2021188Windows: 196. "Microsoft Windows Subsystem for Linux Background Host" / "Vmmem"을 종료하는 방법
12770정성태8/11/2021611.NET Framework: 1086. C# - Windows Forms 응용 프로그램의 자식 컨트롤 부하파일 다운로드1
12769정성태8/11/2021456오류 유형: 752. Python - ImportError: No module named pip._internal.cli.main 두 번째 이야기
12768정성태8/10/2021717.NET Framework: 1085. .NET 6에 포함된 신규 BCL API [1]파일 다운로드1
12767정성태8/10/2021631오류 유형: 752. Python - ImportError: No module named pip._internal.cli.main
12766정성태8/9/2021588Java: 32. closing inbound before receiving peer's close_notify
12765정성태8/9/2021160Java: 31. Cannot load JDBC driver class 'org.mysql.jdbc.Driver'
1  2  [3]  4  5  6  7  8  9  10  11  12  13  14  15  ...