Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)

기본 생성된 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

비밀번호

댓글 작성자
 




1  2  3  4  [5]  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13505정성태12/27/20232754닷넷: 2189. C# - WebSocket 클라이언트를 닷넷으로 구현하는 예제 (System.Net.WebSockets)파일 다운로드1
13504정성태12/27/20232329닷넷: 2188. C# - ASP.NET Core SignalR로 구현하는 채팅 서비스 예제파일 다운로드1
13503정성태12/27/20232194Linux: 67. WSL 환경 + mlocate(locate) 도구의 /mnt 디렉터리 검색 문제
13502정성태12/26/20232307닷넷: 2187. C# - 다른 프로세스의 환경변수 읽는 예제파일 다운로드1
13501정성태12/25/20232102개발 환경 구성: 700. WSL + uwsgi - IPv6로 바인딩하는 방법
13500정성태12/24/20232186디버깅 기술: 194. Windbg - x64 가상 주소를 물리 주소로 변환
13498정성태12/23/20232868닷넷: 2186. 한국투자증권 KIS Developers OpenAPI의 C# 래퍼 버전 - eFriendOpenAPI NuGet 패키지
13497정성태12/22/20232299오류 유형: 885. Visual Studiio - error : Could not connect to the remote system. Please verify your connection settings, and that your machine is on the network and reachable.
13496정성태12/21/20232319Linux: 66. 리눅스 - 실행 중인 프로세스 내부의 환경변수 설정을 구하는 방법 (gdb)
13495정성태12/20/20232327Linux: 65. clang++로 공유 라이브러리의 -static 옵션 빌드가 가능할까요?
13494정성태12/20/20232509Linux: 64. Linux 응용 프로그램의 (C++) so 의존성 줄이기(ReleaseMinDependency) - 두 번째 이야기
13493정성태12/19/20232599닷넷: 2185. C# - object를 QueryString으로 직렬화하는 방법
13492정성태12/19/20232302개발 환경 구성: 699. WSL에 nopCommerce 예제 구성
13491정성태12/19/20232239Linux: 63. 리눅스 - 다중 그룹 또는 사용자를 리소스에 권한 부여
13490정성태12/19/20232358개발 환경 구성: 698. Golang - GLIBC 의존을 없애는 정적 빌드 방법
13489정성태12/19/20232143개발 환경 구성: 697. GoLand에서 ldflags 지정 방법
13488정성태12/18/20232074오류 유형: 884. HTTP 500.0 - 명령행에서 실행한 ASP.NET Core 응용 프로그램을 실행하는 방법
13487정성태12/16/20232392개발 환경 구성: 696. C# - 리눅스용 AOT 빌드를 docker에서 수행 [1]
13486정성태12/15/20232206개발 환경 구성: 695. Nuget config 파일에 값 설정/삭제 방법
13485정성태12/15/20232091오류 유형: 883. dotnet build/restore - error : Root element is missing
13484정성태12/14/20232168개발 환경 구성: 694. Windows 디렉터리 경로를 WSL의 /mnt 포맷으로 구하는 방법
13483정성태12/14/20232306닷넷: 2184. C# - 하나의 resource 파일을 여러 프로그램에서 (AOT 시에도) 사용하는 방법파일 다운로드1
13482정성태12/13/20232884닷넷: 2183. C# - eFriend Expert OCX 예제를 .NET Core/5+ Console App에서 사용하는 방법 [2]파일 다운로드1
13481정성태12/13/20232275개발 환경 구성: 693. msbuild - .NET Core/5+ 프로젝트에서 resgen을 이용한 리소스 파일 생성 방법파일 다운로드1
13480정성태12/12/20232629개발 환경 구성: 692. Windows WSL 2 + Chrome 웹 브라우저 설치
13479정성태12/11/20232320개발 환경 구성: 691. WSL 2 (Ubuntu) + nginx 환경 설정
1  2  3  4  [5]  6  7  8  9  10  11  12  13  14  15  ...