Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)
(시리즈 글이 3개 있습니다.)
개발 환경 구성: 561. kubectl 수행 시 다른 k8s 클러스터로 접속하는 방법
; https://www.sysnet.pe.kr/2/0/12583

개발 환경 구성: 562. kubeconfig 파일 없이 kubectl 옵션만으로 실행하는 방법
; https://www.sysnet.pe.kr/2/0/12584

개발 환경 구성: 563. 기본 생성된 kubeconfig 파일의 내용을 새롭게 생성한 인증서로 구성하는 방법
; https://www.sysnet.pe.kr/2/0/12585




기본 생성된 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])?)*' 정규 표현식을 만족하는 범위 내의 문자로 이름을 지어야 합니다.




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

[연관 글]






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

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

비밀번호

댓글 작성자
 




... 151  152  153  154  155  156  157  158  159  [160]  161  162  163  164  165  ...
NoWriterDateCnt.TitleFile(s)
1048정성태5/27/201132254개발 환경 구성: 123. Apache 소스를 윈도우 환경에서 빌드하기
1047정성태5/27/201126117.NET Framework: 217. Firebird ALinq Provider - 날짜 필드에 대한 낙관적 동시성 쿼리 오류
1046정성태5/26/201130784.NET Framework: 216. 라이선스까지도 뛰어넘는 .NET Profiler [5]
1045정성태5/24/201131874.NET Framework: 215. 닷넷 System.ComponentModel.LicenseManager를 이용한 라이선스 적용 [1]파일 다운로드1
1044정성태5/24/201132437오류 유형: 122. zlib 빌드 오류 - inflate.obj : error LNK2001: unresolved external symbol _inflate_fast
1043정성태5/24/201131418.NET Framework: 214. 무료 Linq Provider - DbLinq를 이용한 Firebird 접근파일 다운로드1
1042정성태5/23/201137737개발 환경 구성: 122. PHP 소스를 윈도우 환경에서 빌드하기
1041정성태5/22/201128632.NET Framework: 213. Linq To SQL - ALinq Provider를 이용하여 Firebird 사용파일 다운로드1
1040정성태5/21/201138958개발 환경 구성: 121. .NET 개발자가 처음 설치해 본 Apache + PHP [2]
1039정성태5/17/201131656.NET Framework: 212. Firebird 데이터베이스와 ADO.NET [2]파일 다운로드1
1038정성태5/16/201133629개발 환경 구성: 120. .NET 프로그래머에게도 유용한 Firebird 무료 데이터베이스 [2]
1037정성태5/11/201128468개발 환경 구성: 119. Visual Studio Professional 이하 버전에서도 TFS의 정적 코드 분석 정책 연동이 가능할까? [3]
1036정성태5/7/201194266오류 유형: 121. Access DB에 대한 32bit/64bit OLE DB Provider 관련 오류 [11]
1035정성태5/7/201129022오류 유형: 120. File cannot be opened. Ensure it is a valid Data Link file.
1034정성태5/2/201126059.NET Framework: 211. 파일 잠금 없이 .NET 어셈블리의 버전을 구하는 방법 [2]파일 다운로드1
1033정성태5/1/201131772웹: 19. IIS Express - appcmd.exe를 이용한 applicationHost.config 변경 [2]
1032정성태5/1/201128422웹: 18. IIS Express를 NT 서비스로 변경
1031정성태4/30/201129572웹: 17. IIS Express - "IIS Installed Versions Manager Interface"의 IIISExpressProcessUtility 구하는 방법 [1]파일 다운로드1
1030정성태4/30/201151849개발 환경 구성: 118. IIS Express - localhost 이외의 호스트 이름으로 접근하는 방법 [4]파일 다운로드1
1029정성태4/28/201140979개발 환경 구성: 117. XCopy에서 파일/디렉터리 확인 질문 없애기 [2]
1028정성태4/27/201138371오류 유형: 119. Visual Studio 2010 SP1 설치 후 Windows Phone 개발자 도구로 인한 재설치 문제 [3]
1027정성태4/25/201127548디버깅 기술: 40. 상황별 GetFunctionPointer 반환값 정리 - x86파일 다운로드1
1026정성태4/25/201145836디버깅 기술: 39. DebugDiag 1.1을 사용한 덤프 분석 [7]
1025정성태4/24/201127895개발 환경 구성: 116. IIS 7 관리자 - Active Directory Certification Authority로부터 SSL 사이트 인증서 받는 방법 [2]
1024정성태4/22/201129198오류 유형: 118. Windows 2008 서버에서 Event Viewer / PowerShell 실행 시 비정상 종료되는 문제 [1]
1023정성태4/20/201130084.NET Framework: 210. Windbg 환경에서 확인해 본 .NET 메서드 JIT 컴파일 전과 후 [1]
... 151  152  153  154  155  156  157  158  159  [160]  161  162  163  164  165  ...