본문 바로가기

DevOps

[AWS EKS] (17) EKS 스터디 6주차 ( X.509 )

CloudNet@팀의 EKS 스터디 AEWS 2기에 작성된 자료를 토대로 작성합니다.
PKI(X.509) 와 더 나아가서 K8s 인증체계의 이해를 돕기 위해 다음 포스팅을 공유 합니다

 

PKI란? 

  • Public Key Infrastructure (PKI)

PKI-공개키기반구조(Public Key Infrastructure) 사용자들이 한쌍의 공개키와 개인키를 사용함으로써, 안전하게 데이터를 교환할 있게 합니다. 또한 인증서와 CA기관 그리고 인증서를 발급받는 방법에 대해서 이해해 봅시다.

1. 인증서

예를들어 네이버의 주소창 왼쪽의 자물쇠를 눌러보면 이렇게 Connection is secure라고 뜨고 밑의 Certificate Valid하다고 확인할 있습니다.

 

해당 인증서를 확인해보면 

다음과 같은 구성요소를 볼수 있습니다.

 

 

 

네이버의 인증서는 최상위 인증기관인 DigiCert로부터 인증받은 하위 인증서인 DigiCert SHA2~CA로부터 인증을 받았네요.
이렇게 수직적인 구조로 인증받게 되는데 어떻게 인증서가 작동되어 인증이 되게 되는지 알아보도록 하겠습니다.

이 세상에는 무조건 신뢰할 수 있는 기관이 몇군데 존재합니다. 최상위 인증기관(RootCA)이라고도 하며 가장 최상위의 인증서를 발급하는 기관입니다.
위 네이버 예시의 DigiCert가 이 상황에서의 RootCA이 되겠네요.

이러한 RootCA의 인증서들은 일반적으로 웹브라우저에 미리 내장되어 있으며, 해당 인증서에 대응하는 공개키또한 인증서 내부에 포함되어 있습니다.

그리고 암묵적으로 이 RootCA들은 신용할 수 있다! 를 서로 약속하고 RootCA들의 공개키로 복호화가 가능한 데이터는 RootCA의 꽁꽁숨겨진 비밀키로 암호화되었기 때문에 신용할 수 있는 데이터라고 간주하는겁니다.

위의 네이버 예시와 같이 인증서는 대부분 계층구조로 되어있습니다.(보통은 3계층)
RootCA가 DigiCert이고, 중간에 있는 DigiCert SHA2~CA도 인증기관입니다. RootCA와 구분짓기 위해 ICA(Intermidiate CA):중간인증기관이라고 부릅니다.

하지만 우리는 암묵적으로 RootCA들을 신뢰할 있다고 약속했지만 ICA 대해서는 약속하지 않았습니다. 그런데 어떻게 ICA에서 발급받은 인증서를 신뢰할 있다고 있을까요?

 

2. 인증서를 발급 받는 과정 

이미지는 https://gruuuuu.github.io/security/what-is-x509/ 참고

위에서 언급했다싶이, 우리는 이미 RootCA의 공개키로 복호화할 수 있는 데이터는 신뢰하기로 약속했습니다.
B회사가 인증서 발급요청을 하게되면, B회사 인증서해시값을 RootCA의 비밀키로 암호화하게 됩니다.

 

 

이미지는 https://gruuuuu.github.io/security/what-is-x509/ 참고

이렇게 하면 B회사의 인증서해시값은 RootCA의 공개키로 복호화가 가능할것이고, 만약 복호화 시의 해시값과 인증서 내용물의 해시값이

상이하다면 B회사 인증서 내용물은 누군가에 의해 변조되었음을 의미합니다.

즉, 상위기관의 공개키로 하위기관의 인증서 해시값을 복호화함으로써 쉽게 변조 유무를 확인할 수 있게 되니, 하위기관을 신뢰할 수 있다고 간주할 수 있습니다.

이미지는 https://gruuuuu.github.io/security/what-is-x509/ 참고

이러한 원리를 Chain of Trust라고 부르며 ICA에서 발급받은 인증서도 신뢰할 수 있게되는 근간이 됩니다.

3. 보안 연결 과정

 

신뢰할 수 있는 인증서를 발급받아서 개인 웹서버를 운영한다고 가정해봅시다.
해당 웹서버에 접근해서 데이터를 주고받는다고 할 때, 이 인증서가 보안 연결을 하는데에 어떤 역할을 하는지 알아보도록 하겠습니다.

  1. 웹서버에 접근 (클라이언트의 난수데이터, 지원하는 암호화 방식, 세션아이디 전송)
  2. 웹서버에서는 자신의 인증서와 서버의 난수데이터를 클라이언트에게 전송
  3. 클라이언트는 웹브라우저에 등록된신뢰할 있는 인증서목록에 있는 공개키로 인증서 해시값 비교
  4. 신뢰할 수 있는 사이트임을 확인
목표:

Background++
보통 유저가 받는 인증서는 RootCA가아니라 ICA에서 받을 것입니다. 그런데 모든 ICA 인증서가 브라우저의 신뢰할 있는 인증서 목록에 있을까요? 만약 없다면 어떻게 신뢰할 있는 인증서라고 판별할 있을까요?
ICA
브라우저의 신뢰할 있는 인증서 목록에 없을 경우를 대비하여 보통 ICA에서 인증서를 발급해줄때는 자신의 인증서를 이어붙여서 발급해줍니다.
그러면 ICA 인증서가 브라우저에 없더라도 같이 제출된 ICA 인증서를 RootCA 공개키로 인증할 있게되기 때문입니다.

비대칭키로도 암호화 통신을 있겠지만 비대칭키 방식은 많은 컴퓨터 파워를 소모하기때문에, 실제로 데이터를 주고받을 때에는 대칭키를 사용하여 암호화를 진행합니다.
그러면 대칭키를 서버와 클라이언트 모두 가지고 있어야 할텐데요,

클라이언트는 주고받은 랜덤데이터를 조합하여 PMS(Pre Master Secret)이라는 일종의 난수값 생성 -> 서버의 인증서 안에 들어있는 서버 공개키로 암호화해서 서버로 전송 -> 서버/클라이언트는 PMS, Client 난수, Server 난수 세가지 값을 바탕으로 대칭키 생성 -> 이 대칭키를 사용해 암호화 통신 시작

 

실습 kind 클러스터 배포 ( x509 인증서 확인 ) 

[운영서버2 EC2] kind(k8s) x.509 인증서 확인

1. Amazon EKS (myeks) 원클릭 배포 (20분 걸림)

# YAML 파일 다운로드
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/K8S/myeks-6week.yaml

# 변수 지정
CLUSTER_NAME=myeks
SSHKEYNAME=<SSH 키 페이 이름>
MYACCESSKEY=<IAM Uesr 액세스 키>
MYSECRETKEY=<IAM Uesr 시크릿 키>

# CloudFormation 스택 배포
aws cloudformation deploy --template-file myeks-6week.yaml --stack-name $CLUSTER_NAME --parameter-overrides KeyName=$SSHKEYNAME SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32  MyIamUserAccessKeyID=$MYACCESSKEY MyIamUserSecretAccessKey=$MYSECRETKEY ClusterBaseName=$CLUSTER_NAME --region ap-northeast-2

# CloudFormation 스택 배포 완료 후 작업용 EC2 IP 출력
aws cloudformation describe-stacks --stack-name myeks --query 'Stacks[*].Outputs[0].OutputValue' --output text

2. 인증서 정보 확인

#
sudo sysctl fs.inotify.max_user_watches=524288
sudo sysctl fs.inotify.max_user_instances=512

#
kind create cluster --name myk8s

# 인증서 확인
docker exec -it myk8s-control-plane ls -l /etc/kubernetes/pki
-rw-r--r-- 1 root root 1123 Mar  7 13:34 apiserver-etcd-client.crt
-rw------- 1 root root 1675 Mar  7 13:34 apiserver-etcd-client.key
-rw-r--r-- 1 root root 1176 Mar  7 13:34 apiserver-kubelet-client.crt
-rw------- 1 root root 1675 Mar  7 13:34 apiserver-kubelet-client.key
-rw-r--r-- 1 root root 1326 Mar  7 13:34 apiserver.crt # 루트인증서로부터 발급된 하위 인증서
-rw------- 1 root root 1675 Mar  7 13:34 apiserver.key
-rw-r--r-- 1 root root 1107 Mar  7 13:34 ca.crt # 루트인증서
-rw------- 1 root root 1675 Mar  7 13:34 ca.key # 루트인증서에 대응하는 비밀키
drwxr-xr-x 2 root root 4096 Mar  7 13:34 etcd
-rw-r--r-- 1 root root 1123 Mar  7 13:34 front-proxy-ca.crt
-rw------- 1 root root 1679 Mar  7 13:34 front-proxy-ca.key
-rw-r--r-- 1 root root 1119 Mar  7 13:34 front-proxy-client.crt
-rw------- 1 root root 1679 Mar  7 13:34 front-proxy-client.key
-rw------- 1 root root 1679 Mar  7 13:34 sa.key
-rw------- 1 root root  451 Mar  7 13:34 sa.pub
 
docker exec -it myk8s-control-plane cat /etc/kubernetes/pki/ca.crt
docker exec -it myk8s-control-plane openssl x509 -in /etc/kubernetes/pki/ca.crt -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 8736798006158023849 (0x793f577f3f63dca9)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = kubernetes
        Validity
            Not Before: Mar  7 13:29:06 2025 GMT
            Not After : Mar  5 13:34:06 2035 GMT
        Subject: CN = kubernetes
        ...
        X509v3 extensions:
            X509v3 Key Usage: critical #  클라이언트는 이 키 사용 용도를 반드시 준수
                Digital Signature, Key Encipherment, Certificate Sign
                # Digital Signature: 인증서가 디지털 서명에 사용됨.
                # Key Encipherment: 인증서가 키 암호화(예: TLS에서 세션 키 암호화)에 사용됨.
                # Certificate Sign: 이 인증서가 다른 인증서를 서명(즉, CA 역할)할 수 있음. 주로 인증 기관(CA) 인증서에서 사용됨.
            X509v3 Basic Constraints: critical # 인증서가 인증 기관(CA) 역할을 할 수 있는지를 나타냄.
                CA:TRUE
            X509v3 Subject Key Identifier:
                32:75:7F:9F:C2:C4:C8:25:8C:04:79:6A:B7:18:84:27:37:E2:4A:75
            X509v3 Subject Alternative Name: #  인증서가 적용되는 주체(Subject)의 대체 이름
                DNS:kubernetes
    ...
    Signature Value:
        18:9b:6f:ad:09:d1:ea:78:4a:3d:b7:93:cc:7e:e2:c1:94:30:
        ...

docker exec -it myk8s-control-plane cat /etc/kubernetes/pki/apiserver-kubelet-client.crt
docker exec -it myk8s-control-plane openssl x509 -in /etc/kubernetes/pki/apiserver-kubelet-client.crt -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 805610438108720721 (0xb2e1a6cd6d12e51)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = kubernetes
        Validity
            Not Before: Mar  7 13:29:06 2025 GMT
            Not After : Mar  7 13:34:06 2026 GMT
        Subject: O = kubeadm:cluster-admins, CN = kube-apiserver-kubelet-client
        ...
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Client Authentication # 클라이언트 인증용
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Authority Key Identifier:
                32:75:7F:9F:C2:C4:C8:25:8C:04:79:6A:B7:18:84:27:37:E2:4A:75

# CSR 확인 : EKS에서도 같이 확인해보자!
kubectl get certificatesigningrequests
NAME        AGE     SIGNERNAME                                    REQUESTOR                         REQUESTEDDURATION   CONDITION
csr-852t8   4m14s   kubernetes.io/kube-apiserver-client-kubelet   system:node:myk8s-control-plane   <none>              Approved,Issued
csr-t8hvk   4m4s    kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:abcdef           <none>              Approved,Issued

kubectl describe certificatesigningrequests
Name:               csr-852t8
...
Requesting User:    system:node:myk8s-control-plane
Signer:             kubernetes.io/kube-apiserver-client-kubelet
Status:             Approved,Issued
Subject:
         Common Name:    system:node:myk8s-control-plane
         Serial Number:
         Organization:   system:nodes
Events:  <none>


Name:               csr-t8hvk
...
Requesting User:    system:bootstrap:abcdef
Signer:             kubernetes.io/kube-apiserver-client-kubelet
Status:             Approved,Issued
Subject:
         Common Name:    system:node:myk8s-worker
         Serial Number:
         Organization:   system:nodes
Events:  <none>

3. kind 설치자의 kubeconfig 정보 확인

# 아래 출력되는 client-certificate-data 값을 위 사이트에 붙여넣고 DECODE : 끝에 == 빼먹지 말것!
# 참고로 '운영서버1(EKS 관리자)'에서도 .kube/config 확인해보고 비교해보자.
cat $HOME/.kube/config
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0...
    server: https://127.0.0.1:50032
  name: kind-myk8s
contexts:
- context:
    cluster: kind-myk8s
    user: kind-myk8s
  name: kind-myk8s
current-context: kind-myk8s
kind: Config
preferences: {}
users:
- name: kind-myk8s
  user:
    client-certificate-data: LS0tL...
    client-key-data: LS0tLS1CR....

# base64 디코딩 하자!
echo "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLVENDQWhHZ0F3SUJBZ0lJTldrNnpQYWh4UUl3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TlRBek1Ea3hNakE0TURsYUZ3MHlOakF6TURreE1qRXpNRGxhTUR3eApIekFkQmdOVkJBb1RGbXQxWW1WaFpHMDZZMngxYzNSbGNpMWhaRzFwYm5NeEdUQVhCZ05WQkFNVEVHdDFZbVZ5CmJtVjBaWE10WVdSdGFXNHdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFEa0VYcGcKZlF5WXFjVkZOOEJMM0w0NERQOFVaQ0tyaWhOV3JvV2dYblBMSjI4S01zVW1YOGFTZzNmSTExZko0b0c2UFpuTwpOQWJFajdWckM3NDM0WitNVDRhWkZTMlBpMHg0Q0p6RUlDWms0ZDV6eVhvbUZtd2tRTFM0N2Z1SkFDWERxZDc3CncyVVJUMWp1QlJvb1lRbnA1QUk3cjJBak9Selpxa1FEZkdtOGVYQWwvYnVJazcxYnlqeVRtUGRPZnRqRUtPbmcKeXptb2g1K2xLRCs5ZlI3SHhWdnFXZEFJR0NRaFVtWUFHY3VRaFdjdEpSSGFidUpNR3VGV2tqUmZlQVh5VjI2eAoraVZFdy8wbUtKWVZwTjJrWVJUenVEQnVxQ3dtd0RSNXFTaG9VRXJJTXVqakNmYnhhOGQwL0xSOFpwcTBUaWplCkE1clNSU3VodkNRaXFTZ0JBZ01CQUFHalZqQlVNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUsKQmdnckJnRUZCUWNEQWpBTUJnTlZIUk1CQWY4RUFqQUFNQjhHQTFVZEl3UVlNQmFBRktCZUJxai9NYnJTU1FEUApnV0tWTmMvZW5ySFVNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUFZenFOYjhHSVh0R0Vjbk10N21VNzM3NWFBClRYcE5HbFh3allYWUU2YkhFKzk2NDZudWlvRFE0ZGhiMGRPbFR5M1MyeVUrZE1LNHI0WkRBYU5tQm1HVkp6OXcKVVFyb3QzYi9nUmM3Ykd1bTJ5Z0hSdE5CNTlFYmVxa1BxR2hlcVVrQmZqd1BmMmJtY3NHRDQ2ZE5QaWJOS3JRYQozWG5xTjc2SmE5OGkxWDZhUGx3TnlXcnIrUzc0RlV4MGRtQ3FOSUFTQSt3cVJ3bUFuZkVqNm5nblZmVHZRZ2ovCkIwZGR6L2tYL1BUVzNNcURmWTQzRWV5alJhWGFacUJPUHF0akJ6bCtsWlBJcnc2TXhnVTM4TFp6NVVXRW1XYVcKaVdoQnRKb1RYOWhGRG1ZaERoOWx1K2QwMVh4dkRjYTluWGI2WlgvdE4yRjduK1lEZlVTdFRkL2phRU8wCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" | base64 -d
...

# 어떤 인증서인가요? 
vi myuser.crt
-----BEGIN CERTIFICATE-----
MIIDKTCCAhGgAwIBAgIIeKzXmvzBrkswDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
...

# 
(kind-myk8s:N/A) [root@operator-host ~]# openssl x509 -in myuser.crt -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 6601471395858758270 (0x5b9d234229103a7e)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=kubernetes
        Validity
            Not Before: Mar 15 04:57:33 2025 GMT
            Not After : Mar 15 05:02:33 2026 GMT
        Subject: O=kubeadm:cluster-admins, CN=kubernetes-admin
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:cd:6f:a7:ce:d1:ac:72:c3:68:96:44:08:c4:f3:
                    8d:a6:d7:69:79:1c:7d:f6:68:4a:f0:59:8e:7b:22:
                    c1:bc:77:da:bd:03:8f:58:16:c4:1a:c5:0e:fd:12:
                    25:09:63:68:6c:da:66:b0:6b:54:72:52:16:74:4f:
                    40:07:75:ff:88:c2:5a:ae:aa:74:4f:8a:48:2e:e2:
                    9e:3b:be:89:9f:56:bb:d2:9d:b1:4e:f7:8c:9b:e6:
                    da:20:39:91:81:37:98:20:60:01:30:4f:6e:7f:9d:
                    cb:e7:7f:d0:e6:3d:93:04:d1:ea:b8:c6:66:a4:6f:
                    26:fc:95:dc:d5:b3:c1:ad:d1:99:bc:3c:06:77:58:
                    ee:27:70:b8:52:ed:49:b7:09:25:e7:d1:c4:a0:02:
                    af:7e:02:62:bf:d2:4a:55:ca:60:b9:26:93:cf:9d:
                    e9:dc:ca:a0:a6:07:e4:3f:68:f5:79:79:d2:2d:36:
                    eb:dc:25:c6:e6:04:66:3f:da:83:f3:e8:f9:6e:bd:
                    a7:89:7d:03:95:ec:b1:84:00:76:9a:65:13:0d:3b:
                    17:e1:8c:a1:c9:85:50:8f:c7:25:09:79:69:ec:c8:
                    18:09:bc:1f:6a:fb:a7:21:a2:00:8b:87:77:e3:22:
                    9e:7e:76:e7:d1:11:61:ec:c6:81:c2:d3:52:54:87:
                    35:f3
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Client Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Authority Key Identifier:
                keyid:E3:2E:D9:9E:74:13:3E:95:1A:9B:4F:61:41:88:6B:87:36:16:EE:DC

    Signature Algorithm: sha256WithRSAEncryption
         b8:e5:df:b4:2f:f8:de:cd:12:3b:d0:94:9d:6e:4d:e3:75:cd:
         ed:e2:d9:90:46:bc:b7:34:23:22:86:7f:71:c5:67:b6:c2:dd:
         a8:d7:5b:65:e2:e4:7f:01:34:5a:48:d6:9e:15:80:7f:a6:0d:
         47:99:30:90:56:f9:c6:5b:69:da:cb:57:a2:76:07:8d:66:15:
         eb:f5:02:ed:d9:1a:da:9a:79:82:4b:12:8e:58:e2:91:5a:b3:
         46:e9:9d:1f:bb:01:9f:e4:ab:ac:77:07:2e:c0:79:26:89:7e:
         d4:be:83:67:34:c2:32:19:9c:42:4e:14:8c:b6:68:d6:be:7c:
         2f:a7:ec:34:9e:82:c2:fb:7b:da:24:4c:66:47:21:9e:5e:88:
         04:78:b3:3a:8e:11:6c:63:e0:39:55:50:67:4e:b5:48:19:4b:
         81:0f:a0:4c:d5:49:b3:7e:2e:7d:6e:6e:99:4e:85:e5:26:37:
         09:fc:d2:64:de:53:8c:a0:2f:dc:52:48:bd:a3:47:ad:f9:48:
         03:04:75:12:9b:af:0d:71:2d:d3:3a:4d:89:15:aa:33:f2:8f:
         07:74:d8:6b:13:1b:7f:77:ce:b9:49:45:fe:ff:90:32:aa:8f:
         42:a8:3e:f7:c2:8e:8b:65:47:65:b1:58:16:0a:b8:7c:c7:b2:
         5c:62:10:36
(kind-myk8s:N/A) [root@operator-host ~]#

# 아래 출력되는 client-key-data 값을 위 사이트에 붙여넣고 DECODE : 어떤 키인가요?
cat $HOME/.kube/config
    client-key-data: LS0tLS1CR....
    
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAzW+nztGscsNolkQIxPONptdpeRx99mhK8FmOeyLBvHfavQOP
WBbEGsUO/RIlCWNobNpmsGtUclIWdE9AB3X/iMJarqp0T4pILuKeO76Jn1a70p2x
TveMm+baIDmRgTeYIGABME9uf53L53/Q5j2TBNHquMZmpG8m/JXc1bPBrdGZvDwG
d1juJ3C4Uu1Jtwkl59HEoAKvfgJiv9JKVcpguSaTz53p3MqgpgfkP2j1eXnSLTbr
3CXG5gRmP9qD8+j5br2niX0DleyxhAB2mmUTDTsX4YyhyYVQj8clCXlp7MgYCbwf
avunIaIAi4d34yKefnbn0RFh7MaBwtNSVIc18wIDAQABAoIBAAnUjfMXlWjocNi/
6KuD/AM/y4xAEMb5tpxJrMe3og2irpTc1r8gV8HwLAdwFtWcLCMJUGCgwim2Q9zM
7gNtYgzpP+2bunUT6OBVd7zkITG+tL4fTZy5u8C6CzX/izbjsiPadDQbmO4CXv90
3komKCLS6Khu1fqIVxU/FpIjR+FJUF0Q1KoaszmciZtNd+CQCKhQlYVT1fm4dE3w
M4yt3PpJGB5Tk9xcZczB39ZlFNDDErn2haUZLp71ePSkMwg9m2M9UqAJ/KcKkn80
vMPEgIaK8iinfGZwB0Y21jXulUGhZwZQkGUwC5VT49j2L5cK68T0lfp3tMDc6hjL
Sa3RGgECgYEA7AVOgleuSwt0uuYpTwzY6J/tsni4q1cyQSpYOCgi8GCfxdbfxLtK
qTuWYrECz08VyGr8xxlnrS6U/8rDNC4V17h2Jv04N0M+rsIjB2oQ1rstdsV6Et7Y
nV9DXxavzgT7FK7KTo7xCC47FC3e2IVj+9H/kXlcs4/eHaUdvempnI0CgYEA3tOQ
o+JUpqz7uiwwILP92qPfBepxlVSnzXhf0702UvInQuq6DFHOKE0VDKLlO+SFtmin
48/mSWDlnH0o+I2b+nWReO0yyFIXBy79HDVzO2s9PttJALgHAlp3APzYXoAS1lEu
p+Z0WpgENxJkAY02kbRGHkGw04p8ZPTHqeDXvH8CgYEAm1RGvftshpEMirBNAWxo
GHigW7OdfY4OUdrHYnXvwJkmrXJjpDrKwSOpLlxmh/75TAQ1RecPV2dvwgQ0gdPO
pkEM6U3/QEduKl8z5H5GhLt9CUyfsWmdz7xRP3RT0Vdv0sXR+O+T65lZYkdqAL+Q
9LrY4mmnu7j0KjhvoXv1F0UCgYAQMNs/rUBtZABehLtyhOGbM3EPIvvh1+bhfS+p
WQRLfqDvsdKW9pK+RuuSoXt6oJ4+pNgeK4sWJd5JQqbpeJCu4EATw1h/Sce2k+l8
VT3sQVyP5qslTDnmJ+Chx72JEFFOFVQIiyxFMOqNfd6aZkJiz/CQXkGU/WkQhODF
LTs/zQKBgQDG2YQJlV5F7K8gZUf0ydU65CkVE748LcApinD4tLTf1tDjB9ZpwVrP
1fYLSU9UNEb799shCeFTWhPe3HZPZF1aeHvEcoYu5cDN2xuWdop1hqvYWBCFXQPz
VpwJ5UhZ0jciuIT19iJnk3zTObluwifPVN4B/WCT/4u/AwE4djF2Ag==
-----END RSA PRIVATE KEY-----



# 아래 출력되는 certificate-authority-data 값을 위 사이트에 붙여넣고 DECODE : 어떤 인증서인가요?
cat $HOME/.kube/config
    certificate-authority-data: LS0...

 

4. 신규 관리자를 위한 인증서 설정 

# 하위 인증서를 위한 비밀키 생성 : koo 대신 자신의 닉네임으로 변경해서 실습해보세요!
openssl genrsa -out koo.key 2048

# 확인
cat koo.key
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCpb0u8E7Km0CkX
...

# 인증서 사인 요청 파일(.csr) 파일 생성
openssl req -new -key koo.key -out koo.csr -subj "/O=kubeadm:cluster-admins/CN=koo-cert"

# 확인
cat koo.csr
-----BEGIN CERTIFICATE REQUEST-----
MIICczCCAVsCAQAwLjEWMBQGA1UECgwNY2xvdWRuZXRhLW9yZzEUMBIGA1UEAwwL
...

# 출력 값을 아래 request 에 붙여넣기 : 끝에 == 빼먹지 말것!
cat koo.csr | base64 | tr -d '\n'

# CSR 요청 : k8s 내부적으로 루트인증서의 비밀키로 서명해 반환. 즉 간접적으로 루트 인증서의 비밀키를 사용할 수 있음 셈.
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: koo-csr
spec:
  signerName: kubernetes.io/kube-apiserver-client
  groups:
  - system:masters
  - system:authenticated
  request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ2VUQ0NBV0VDQVFBd05ERWZNQjBHQTFVRUNnd1dhM1ZpWldGa2JUcGpiSFZ6ZEdWeUxXRmtiV2x1Y3pFUgpNQThHQTFVRUF3d0lhMjl2TFdObGNuUXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCCkFRQ3hteDhLaEl1ZkNETUgweWJRelI2Wm9QVk52T3NJS3czTGFkbCt0WnNQdGVwMFRQb3pCQXVtTVpsVHJkQVgKc1d3WFIycTdMbmFjM1BPR0pUM1JmRTdlNjF4UlBhQnYwUWJQM05CVjJrTURmdGxNZnhobFJCb256dDMvQUhKQgpWU1o4NkhhT1NiR2lweENZa3lsUWoxbVg2b1NJb1dIUVFLcTZpRDlKS1Fuek1Db2FxTFlOdGRvaXJjWkJJR0t2Cld6MWU0eVBVZHJEcEtvcHMzSTNPSlFQR3doQjlJN3hwTFV2bDRMZWdKUDhZRXlCZlpDdGpGWUJ1ckdZNlBBeUwKQk5RbnhSaGY4MG5SbUlnZERUWTNONWFsZFJQbHc0V3F5WkJ5cmlId01XYVJiV0xLbjI0TFdHY0J4d1gwV2laegphb0JpTGNtK1l6d29USnZ2Y0dYQVZTTW5BZ01CQUFHZ0FEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFHTkVvClh5UUJsNWFmcmRSSHlmQ0VuckQ4WW5MQmZzMTJVbU5rTXlxMXdZNzc5MDZUeVYrYTlGYW5QaDY4N0h5NzY4SDYKMnM4eTF0Q2xrNTBhaWZoYkVDdzNUK0VudFNLQkFGT04zWU9kQVlhQ3FZNDE4aXlqbEJ2Nkt1bmdZMWY0cE4xdwpPclNsaGk0U1hvYlZUemxIRWVMS0JTS2R6RzYzcE9IdnVaUVVVRFlRNytlbHJkU1NGZjVaNnV4dTFMVWtBREJtCkxwYU1Eak1adXFwaDJHREFkUGRCNEorQXZXL1EvcThXOGt6NHhYTVdPTWc1bkRrUlZ6SXg0MFlZVTFreTAya0MKQ0JDMjlOTkJucWgyWXQ5eWVLamtheTBGRkhnY2ZuNXpFQTVHdmk4amphMTBLSXl4Z1VWcGowVjg5ZWc3VWFzegp5V0NlcmNDVXdMRFk1U25NcXc9PQotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K
  usages:
  - digital signature
  - key encipherment
  - client auth
EOF

# csr 확인 : 아직은 펜딩 상테
kubectl get csr
NAME         AGE   SIGNERNAME                              REQUESTOR              REQUESTEDDURATION   CONDITION
koo-csr   1s    kubernetes.io/kube-apiserver-client     kubernetes-admin       <none>              Pending
...

# 'k8s 관리자' 입장에서 해당 서명 요청을 승인하자
kubectl certificate approve koo-csr
certificatesigningrequest.certificates.k8s.io/koo-csr approved

# 확인 : 정상적으로 하위 인증서가 발급됨
kubectl get csr
NAME         AGE    SIGNERNAME                              REQUESTOR             REQUESTEDDURATION   CONDITION
koo-csr   2m4s   kubernetes.io/kube-apiserver-client     kubernetes-admin      <none>              Approved,Issued
...

# csr 에서 하위 인증서 추출
kubectl get csr koo-csr -o jsonpath='{.status.certificate}' | base64 -d
kubectl get csr koo-csr -o jsonpath='{.status.certificate}' | base64 -d > koo.crt

#
openssl x509 -in koo.crt -noout -text
...
        Issuer: CN=kubernetes
        Validity
            Not Before: Mar  7 14:03:06 2025 GMT
            Not After : Mar  7 14:03:06 2026 GMT
        Subject: O=kubeadm:cluster-admins, CN=koo-cert
        ...
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Client Authentication

# kubeconfig 에 새로운 사용자 등록
kubectl config set-credentials koo-user --client-certificate=koo.crt --client-key=koo.key
kubectl config set-context kind-koo --cluster=kind-myk8s --user=koo-user
cat ~/.kube/config
kubectl config use-context kind-koo # 혹은 kubectl ctx kind-koo

# ctx kind-koo 로 k8s 정보 확인 시도
kubectl get node

 

실습 kind 클러스터 배포 ( Service account와 토큰 에 대해서  )

여기서 사용하는 토큰이 흔히 웹서버에서 사용하는 jwt 토큰

  • 파드 배포
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: netpod
spec:
  containers:
  - name: netshoot-pod
    image: nicolaka/netshoot
    command: ["tail"]
    args: ["-f", "/dev/null"]
  terminationGracePeriodSeconds: 0
EOF
  • 토큰이 마운트 된 포인트 확인 
kubectl exec -it netpod -- tree /var/run/secrets
/var/run/secrets
└── kubernetes.io
    └── serviceaccount
        ├── ca.crt -> ..data/ca.crt
        ├── namespace -> ..data/namespace
        └── token -> ..data/token

2 directories, 3 files
  • token 복사 
(kind-koo:N/A) [root@operator-host ~]# kubectl exec -it netpod -- cat /var/run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciOiJSUzI1NiIsImtpZCI6IjU2d3BZMEpMcHB6R1FuTndzYkRWU0N4ajJHVjgzR0FrOXp0YkxfWnR5YkkifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzczNTUzMTI0LCJpYXQiOjE3NDIwMTcxMjQsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwianRpIjoiN2JhNTUxNzctNTg3NC00YjMxLWJhMTAtN2JlNzVkZWM5ODgyIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0Iiwibm9kZSI6eyJuYW1lIjoibXlrOHMtY29udHJvbC1wbGFuZSIsInVpZCI6ImI5YzE4MDRiLWI3MDEtNDNkMi04ZDZjLTRhYjIzM2JkM2M2NyJ9LCJwb2QiOnsibmFtZSI6Im5ldHBvZCIsInVpZCI6IjBhMmI0NzMzLTIzZWYtNGNkOS04YjE3LTJmOTEwMTg4ZmViYSJ9LCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoiZGVmYXVsdCIsInVpZCI6IjBiYjkxZTc4LWVjMmUtNDdlMS05N2I3LTg2ODY2NjE3YjJlNCJ9LCJ3YXJuYWZ0ZXIiOjE3NDIwMjA3MzF9LCJuYmYiOjE3NDIwMTcxMjQsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.ipcuoAhif4VYB_gtbFv-FbMVRgSKMkn4hKAIcsR6vann8r9IPRVFlKuWoSrzee6NlQfyLza31LB5Ds2GZweInWv5g8EjnYHpq2jU6uvgj3tXDcPrcOa4axiIEwpUb_qlagi3v0b_nBDp50DrIWLtjNd7b0YKr9nJhdE28SlQpl6Vq2W4pFvpwdVtI8bwTwUDIN1DNHnMQmrD-O_tkx1YdGNas_ILpWigeKVvaz_4WzZw5kAjOa1nkfboENakaI-8YTf9F7zWOI8_gdE4IjlkOBggFjKLQfrKnzgW-sPSN3hL4-52njv7mtwPZRfOeTDleCylWuVxk2OtJzLeZhnIvw
(kind-koo:N/A)
  • JWT io 사이트를 통해 페이로드 분석
  •  payload 부분에는 ServiceAccount가 생성된 namespace, Secret 이름, ServiceAccount 이름 등 쿠버네티스의 다양한 세부 정보가 담긴 것을 확인할 수 있습니다.
  • 쿠버네티스에서는 이러한 사용자 정보를 활용하여 Bearer token을 통한 인증을 처리합니다.

  • JWT 방식 토큰을 입력한 후에 공개키를 전달해 주어야 인증절차를 통과할수 있습니다. 
  • 공개키는 서비스 어카운트의 공개키를 입력해주어야 합니다.
docker exec -it myk8s-control-plane cat /etc/kubernetes/pki/sa.pub

# sa.pub키를 같이 넣어줘야 valid signature 뜸

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtDUKF4asZsUG1sJDff3o
GucTDVBCtBUF9LYpCgicAtgm0vDW/OtTw4kakoUwZKqAkMs/NIbYbJVwNL8iN37S
6PY7s3pGhpRFS2G3pvwfulWjyjaxCOCE9qd0/sZhl1xoM4BHvKLWw5U64PxXVP5L
pQgL1FF5lzBNfe+H1nxG0hNovrI3CRqTe8HChbXwP77WT8mfnh9rBE0W3xdpA3MA
UL1MxqPswoKr9kSwxtk6MVRBl47/inIZetEF/IER1RKgIMu2jUW9ScH3o3NksQzU
OspsEcJYyPVqSPY2zX40yaQFzlV3wH7mnGTK4b30MEPBECReNuPvYeHeo2wDhdUA
EQIDAQAB
-----END PUBLIC KEY-----
  • 성공