스터디/AEWS

[AEWS] 6주차 Kubeconfig 이해하기 및 CSR을 통한 신규 인증서 발급

안녕유지 2025. 3. 11. 00:50
Cloudnet AWES 6주차 스터디를 진행하며 정리한 글입니다.

 
이번 포스팅에서는 사용자가 kubectl을 실행할 때 API 요청이 어떻게 전달되는지를 이해하고, kubeconfig의 역할에 대해 알아보겠습니다.
 

Kubeconfig

지난 포스팅에서 쿠버네티스에서 kubectl 명령을 실행하면 내부적으로 API 요청이 만들어지고, API 서버를 통해 요청이 처리되는 과정을 소개했습니다. kubeconfig는 kubectl이 클러스터와 통신하는 데 필요한 인증 정보를 포함하는 파일입니다.
 
kubeconfig 파일은 크게 다음과 같은 분류를 할 수 있습니다.

  • clusters : 클러스터의 정보를 포함 (API 서버 주소, Cluster CA 인증서)
  • contexts : 현재 사용자가 연결할 클러스터 및 사용자 정보
  • users : 인증을 위한 사용자 인증서 및 키
  • current-context : kubectl이 사용할 기본 컨텍스트

 

Kubeconfig 설정 확인 - Kind

아래 EKS에서 사용하는 kubeconfig와 비교해보면 cluster의 certificate authority data값은 동일하나, user에서 eks에는 없는 client-certificate-data와 client-key-data값이 있습니다.
각각 모두 키 값으로 생겨서 디코딩 하기 전까지는 어떤 값인지 알기 어려울 수도 있는데요. 각각 값은 다음 정보를 나타냅니다.
 
cluster.certificate-authority-data

  • API 서버의 TLS 인증서를 검증하는 CA인증서의 Base64 인코딩 값
  • 이 값을 통해 클라이언트가 API 서버의 신뢰성을 확인할 수 있음

user.client-certificate-data

  • 클라이언트(kubectl)의 X.509 인증서로 API 서버에 신원을 증명할 때 사용 (인증서를 인코딩)

user.client-key-data

  • 해당 인증서의 개인 키로 인증서의 무결성을 보장하고 서명하는데 사용 (개인키를 인코딩)
# kubeconfig 확인
❯ cat $HOME/.kube/config  
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ~~
    server: https://127.0.0.1:40969
  name: kind-myk8s
current-context: kind-myk8s
kind: Config
preferences: {}
users:
- name: kind-myk8s
  user:
     client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FU~~
     client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVkt~~=
  
# kubeconfig의 Cluster의 certificate data를 디코딩 시키면 다음과 같은 certificate 파일이 나옴
❯ echo "LS0tLS1CRUdJTiBDRVJUSUZJQ0UJFR0ExVU~~ ###cluster certificate-authority-data" | base64 --decode
-----BEGIN CERTIFICATE-----
MIIDBTCCAe2gAwIBAgIICC/BM1Kg8OEwDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
AxMKa3ViZXJuZXRlczAeFw0yNTAzMTAxNjIwMjJaFw0zNTAzMDgxNjI1MjJaMBUx
~~
y6mqCSJPB675HCRFo0tnUfkWYIcjAgMBAAGjWTBXMA4GA1UdDwEB/wQEAwICpDAP
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSeWHq40J7CVu6DDE+3N1JXDLPOLzAV
BgNVHREEDjAMggprdWJlcm5ldGVzMA0GCSqGSIb3DQEBCwUAA4IBAQCXqrBmwTXS
~~
s6KUlZ3iZlcJR1kZb9TxpkxCDaMUy2SUFVvPjPfhC/I63GDsj81//zUr7DttTbrh
Gl/DOZgjKrq7uUeMvV/5IphrJw3S4J5GR3YNNIl8az9yam8Biioqsx7HW+hP5nhp
NEGkGbjBSuuwxjtmTH06Q1e7iFRHcby04PaMlbHcvMtZ1LHYR+deGT0ghiK0+Cb3
tKDn7tj1waIN
-----END CERTIFICATE-----


# X509 형식의 인증서를 디코딩하여 사람이 읽을 수 있도록 출력
❯ openssl x509 -in myuser.crt -noout -text  
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 589902502382596321 (0x82fc13352a0f0e1)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=kubernetes
        Validity
            Not Before: Mar 10 16:20:22 2025 GMT
            Not After : Mar  8 16:25:22 2035 GMT
        Subject: CN=kubernetes                         # 쿠버네티스에서 자체적으로 생성한 CA
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption         # rsa 알고리즘
                Public-Key: (2048 bit)
                Modulus:
                    00:cd:fe:7f:44:50:db:cd:d8:09:d8:6d:eb:f5:59:
                    0d:2e:36:0c:97:fe:16:da:d1:9d:a1:c4:f3:b3:01:
                    05:e1:23:b6:9a:46:7b:87:55:85:27:d6:f1:05:ef:
                    45:f7:b0:eb:c1:8d:4d:2c:22:fc:9f:00:cd:d9:46:
                    ee:45:f9:82:dc:2c:d5:ed:6d:24:f7:59:c8:c1:01:
                    e8:8a:0f:37:1a:8e:f0:24:8c:72:ba:06:d7:ba:15:
                    4c:13:28:22:b4:87:e8:86:16:83:c4:2d:2b:3f:58:
                    1c:b0:5b:71:13:87:8f:78:ef:42:82:2b:8f:75:ff:
                    12:3a:e6:d0:5d:73:93:59:3a:f2:fb:ca:1b:ff:e9:
                    f9:03:67:82:7b:0b:6f:90:1a:d2:d0:4f:1d:2a:ea:
                    3f:0c:30:10:a4:ac:ae:5f:c9:3e:9d:13:1c:e5:91:
                    66:7f:fa:ac:77:2f:2a:8e:e5:a9:c1:56:0d:b9:e7:
                    ee:7b:f7:de:f2:53:39:70:de:97:45:e1:25:fe:4f:
                    29:0b:e0:93:91:d6:0a:0d:b3:1c:fc:0f:48:bd:10:
                    d0:4e:08:71:c5:aa:1c:97:82:b6:1e:e4:7c:4a:45:
                    fc:80:fe:34:73:85:bf:0e:c5:64:7a:cb:a9:aa:09:
                    22:4f:07:ae:f9:1c:24:45:a3:4b:67:51:f9:16:60:
                    87:23
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical                # 이 인증서는 CA로 사용될 수 있고, 쿠버네티스 내에 다른 인증서 발급할 수 있는 루트 인증서 만듦
                Digital Signature, Key Encipherment, Certificate Sign
            X509v3 Basic Constraints: critical
                CA:TRUE
            X509v3 Subject Key Identifier:
                9E:58:7A:B8:D0:9E:C2:56:EE:83:0C:4F:B7:37:52:57:0C:B3:CE:2F
            X509v3 Subject Alternative Name:
                DNS:kubernetes
    Signature Algorithm: sha256WithRSAEncryption
         97:aa:b0:66:c1:35:d2:95:97:5d:a2:88:bb:3e:a5:0d:0e:d9:
         03:5f:1a:a3:81:78:44:29:fe:f3:c7:82:51:09:06:c9:3d:b0:
         57:c3:1f:05:35:1d:4c:0d:12:e8:95:c6:af:a1:9a:e7:99:9d:
         26:10:ae:dc:07:23:4e:9c:17:a9:b7:ff:22:50:7a:38:2e:93:
         01:13:10:81:f3:cf:92:47:57:c9:eb:a2:ed:83:7b:68:ca:e6:
         09:4e:77:51:fd:07:81:d5:cf:37:55:61:63:b3:a2:94:95:9d:
         e2:66:57:09:47:59:19:6f:d4:f1:a6:4c:42:0d:a3:14:cb:64:
         94:15:5b:cf:8c:f7:e1:0b:f2:3a:dc:60:ec:8f:cd:7f:ff:35:
         2b:ec:3b:6d:4d:ba:e1:1a:5f:c3:39:98:23:2a:ba:bb:b9:47:
         8c:bd:5f:f9:22:98:6b:27:0d:d2:e0:9e:46:47:76:0d:34:89:
         7c:6b:3f:72:6a:6f:01:8a:2a:2a:b3:1e:c7:5b:e8:4f:e6:78:
         69:34:41:a4:19:b8:c1:4a:eb:b0:c6:3b:66:4c:7d:3a:43:57:
         bb:88:54:47:71:bc:b4:e0:f6:8c:95:b1:dc:bc:cb:59:d4:b1:
         d8:47:e7:5e:19:3d:20:86:22:b4:f8:26:f7:b4:a0:e7:ee:d8:
         f5:c1:a2:0d
         
# client-certificate-data 디코딩
echo "LS0tLS1CRUdJTiBDRVJUSUZJQ~~" | base64 --decode
-----BEGIN CERTIFICATE-----
MIIDKTCCAhGgAwIBAgIIT9vdcltmX8IwDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
AxMKa3ViZXJuZXRlczAeFw0yNTAzMTAxNjIwMjJaFw0yNjAzMTAxNjI1MjJaMDwx
HzAdBgNVBAoTFmt1YmVhZG06Y2x1c3Rlci1hZG1pbnMxGTAXBgNVBAMTEGt1YmVy
bmV0ZXMtYWRtaW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3Wo+w
~~
S4KM8bx8Qb8LjZzp11k0+r8pskTOAddCs75kDWZHMUgkBJJwYct63WZn63J4wV0K
h258i97G2TuLsoZXAgMBAAGjVjBUMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAK
BggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFJ5YerjQnsJW7oMM
~~
NYGbq6zr1wSuaYHlYIoAzwiIYQvI5fjJMtT3XvS31TsnrUp6+Y6EyZFS1DpM7roo
YDFEG6o/R7tlJAwH5VBqX/8sqtiWZVsvQViPXCqrdpae9LuSifLKdYfQ+ZyE5vS1
pxI0M7O4cinzO79FC0ThEMeBmP5DHPm5/eZMzkTXZzF7OUXM+2lkftDDi+51
-----END CERTIFICATE-----


# client-key-data 디코딩
echo "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVk~~" | base64 --decode
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAt1qPsHdYOuE+9Wl2ptaMkFr8hryl5K6wmWadoH/k6WuXQVPC
KqOun+vfKExstDac/c0hwGuRGZVNjHlUSmzyKLaOBYtZh3Pw4v9pNOGeuGyD7CFT
~~
+t2fLgAxTCsmOwQUgZ06RUwcEyd6/D1NhUUI0wEmQNusNwL0SzIUB4IzAqNWSSO9
~~~
r5zoqOtT7V1jK/v26cPUngUprR/e9CoabcoyGy2PPvFTo6Ol26a/Nk83+QkFtms6
EV33ssrNfEo6MiOPgYdhqisfxfJ7BqLxcWb3v3VRQaqcn2a+kIUoqJIGSaUPPbZV
ocy81JUCgYACvpea9Die1k1UJZMyufuaecdlQer5aFKFk8MaCvM0pNspkf5wOieG
2wqZl2yJyEfdiU3ksibz+7EnnXsvrQnafHasYzdNE9NtbsGC4//iV8wsQZ+Kbgr1
QeYLZAfdS9P2jGGu878CQWYUZg/NlLq4t0eshonaqka3Q8weMRW1Nw==
-----END RSA PRIVATE KEY-----

 
 

Kubeconfig 설정 확인 - EKS

eks에 접근하기 위해 kubectl 명령줄을 사용할 때 쓰이는 kubeconfig 파일은 어떤 점이 다른지 확인해보겠습니다.
기본적인 Kubeconfig 구조는 동일하지만 클라이언트를 인증하는 방식이 기존 인증서와 개인키가 아닌 aws에 명령줄을 호출하여 토큰을 받아오는 방식인 것을 확인할 수 있습니다.
EKS에서의 인증/인가는 다음 포스팅에서 자세히 다루도록 하겠습니다.

# kubeconfig 확인
❯ cat $HOME/.kube/config                       
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURCVENDQW~~~
    server: https://8FA477A1~~.~~.ap-northeast-2.eks.amazonaws.com
  name: arn:aws:eks:ap-northeast-2:xxx:cluster/myeks
contexts:
- context:
    cluster: arn:aws:eks:ap-northeast-2:xxx:cluster/myeks
    user: admin
  name: admin
current-context: admin
kind: Config
preferences: {}
users:
- name: admin
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      args:
      - --region
      - ap-northeast-2
      - eks
      - get-token
      - --cluster-name
      - myeks
      - --output
      - json
      command: aws


# kubeconfig의 Cluster의 certificate data를 디코딩 시키면 다음과 같은 certificate 파일이 나옴
❯ echo "LS0tLS1CRUdJ~" | base64 --decode > myuser.crt
-----BEGIN CERTIFICATE-----
MIIDBTCCAe2gAwIBAgIIbtKOrG36yDMwDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
~~~
Ni9pqirXnrCcAN6G1oGb7gjbcsczAgMBAAGjWTBXMA4GA1UdDwEB/wQEAwICpDAP
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQ6yzTozsHOuMtUdtU3O+u82z17MzAV
~~~
gojje2bZTpSdOAPntgRitpbmMsWHq+I+y0zBTqTZ/G2rE3pzS4mlnt/zZ4orowhm
RLDJmOf8o6YVk82demHasW5+IUUUd5E62EMsrgL2UMnHJpaCLihvWnwsa6kcN66P
uf3bRFwfTcoa
-----END CERTIFICATE-----


# X509 형식의 인증서를 디코딩하여 사람이 읽을 수 있도록 출력
❯ openssl x509 -in myuser.crt -noout -text     
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 7985601960511981619 (0x6ed28eac6dfac833)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=kubernetes
        Validity
            Not Before: Mar 10 14:37:00 2025 GMT
            Not After : Mar  8 14:42:00 2035 GMT
        Subject: CN=kubernetes
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:ab:a5:27:91:3e:74:76:5c:73:32:8a:63:48:9d:
                    62:c1:eb:f2:3f:1d:84:64:46:05:48:04:e8:4a:6b:
                    02:4c:cd:4b:a0:19:8a:bf:0b:fa:0d:92:e0:67:33:
                    af:d1:1d:a7:83:fa:14:a5:62:a5:fc:4d:12:61:97:
                    f7:2b:ef:47:92:6b:76:19:37:b3:8c:df:8e:99:b4:
                    2e:ba:21:c1:5f:30:73:fc:19:a6:be:15:c9:e4:e0:
                    aa:57:f0:1d:72:db:50:50:c6:18:96:dd:95:fe:73:
                    1b:0a:a8:6d:52:ee:f5:ac:41:06:77:6d:e2:0e:c0:
                    b8:11:4f:73:aa:ef:60:f3:a7:61:d8:91:a4:17:5c:
                    17:e9:4a:51:b6:4d:04:45:c9:1d:aa:de:d3:54:9b:
                    bb:9d:24:01:df:6f:61:98:de:16:73:d6:12:6f:a6:
                    af:e7:6b:87:bb:eb:d2:19:38:c6:a1:42:f8:72:36:
                    9c:d4:e5:e9:0d:1e:cc:2f:d2:b4:f6:78:63:3d:9c:
                    5a:38:57:e8:70:4c:28:e3:e1:ea:66:64:53:57:e2:
                    36:52:d0:a4:5b:f6:ad:a4:aa:be:38:4d:59:f7:b8:
                    7e:4a:7f:8b:57:1d:f4:fe:21:9c:eb:36:2f:69:aa:
                    2a:d7:9e:b0:9c:00:de:86:d6:81:9b:ee:08:db:72:
                    c7:33
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment, Certificate Sign
            X509v3 Basic Constraints: critical
                CA:TRUE
            X509v3 Subject Key Identifier:
                3A:CB:34:E8:CE:C1:CE:B8:CB:54:76:D5:37:3B:EB:BC:DB:3D:7B:33
            X509v3 Subject Alternative Name:
                DNS:kubernetes
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        88:25:1d:fd:79:57:1f:fa:9c:ba:4b:6c:ed:f9:4d:da:82:ea:
        52:67:54:0f:2d:8d:84:67:d8:ef:67:9f:7e:75:4e:af:a6:85:
        64:e3:59:d8:8f:e5:f5:2d:76:fa:ba:3a:96:20:7c:6e:80:2e:
        d6:67:2d:73:cc:9a:25:6c:1b:95:ff:17:d2:b0:24:d0:b9:9c:
        25:f6:aa:fa:98:df:fb:1a:c2:0d:9e:76:dc:b6:08:4e:e4:e1:
        e0:d9:8a:cf:93:0e:a3:86:80:c4:15:40:b8:20:69:71:e0:65:
        a9:a7:5a:3c:08:42:15:7e:2c:c0:44:ba:76:a8:b3:4c:3c:59:
        fe:c5:e7:bc:bc:2a:08:c8:6e:96:8e:56:9c:db:0c:52:45:93:
        32:b9:19:26:69:f7:17:82:88:e3:7b:66:d9:4e:94:9d:38:03:
        e7:b6:04:62:b6:96:e6:32:c5:87:ab:e2:3e:cb:4c:c1:4e:a4:
        d9:fc:6d:ab:13:7a:73:4b:89:a5:9e:df:f3:67:8a:2b:a3:08:
        66:44:b0:c9:98:e7:fc:a3:a6:15:93:cd:9d:7a:61:da:b1:6e:
        7e:21:45:14:77:91:3a:d8:43:2c:ae:02:f6:50:c9:c7:26:96:
        82:2e:28:6f:5a:7c:2c:6b:a9:1c:37:ae:8f:b9:fd:db:44:5c:
        1f:4d:ca:1a

 
 
위의 kubeconfig 값들은 기본적으로 생성된 config에 대해 설명했지만, Config를 발급받아서 클러스터를 접근하려는 사용자가 많은 환경이거나, 새로운 클라이언트의 config의 인증서 기간을 연장해주고 싶거나 한다면, 어떻게 하면 좋을까요?
 
만약, 새로운 관리자가 이 쿠버네티스 클러스터에 접근할 수 있도록 새로운 인증서를 생성하려고 하는 과정을 통해 알아보겠습니다.
 

신규 요청자를 위한 인증서 설정 (CSR)

CSR(Certificate Signing Request)은 클라이언트가 인증서를 요청할 때 생성하는 데이터입니다.
쿠버네티스에는 CSR을 통해 클러스터 내에서 새로운 사용자(관리자, 개발자 등)의 인증서를 발급할 수 있습니다.
 
CSR에 포함되는 정보는 다음과 같습니다.

  • 요청자의 공개 키 (Public Key)
  • 요청자의 주체 정보 (CN=Common Name)
  • 사용 목적 (Client Authentication 등)
  • 서명 요청을 한 엔터티의 디지털 서명

 
아래 과정은 CSR을 발급하여 승인 받는 과정입니다.
처음에 사용자가 인증서를 위한 개인 비밀키를 생성합니다. 개인키를 이용하여 CSR 파일을 생성한 후 해당 CSR 값을 쿠버네티스 CertificateSigningRequest 매니페스트에 추가하여 실제 API 서버에 요청을 보낼 수 있도록 형식을 작성합니다.
이 CertificateSigningRequest은 쿠버네티스에 제출 후 관리자의 승인을 기다립니다.
 
++ 참고) CSR 상태

  • pending : CSR이 제출되었지만 아직 승인되지 않음
  • approved : 관리자가 승인하여 인증서가 발급될 수 있음
  • denied : 관리자가 거부하여 인증서가 발급되지 않음

 
system:masters 그룹에 속한 사용자는 CSR 승인을 받게 되면 정상적으로 하위 인증서가 발급되게 됩니다.

# 하위 인증서를 위한 비밀키 생성 
openssl genrsa -out hellouz818.key 2048
Generating RSA private key, 2048 bit long modulus
..............................................................................................................................+++
..................+++
e is 65537 (0x10001)

# 확인
cat hellouz818.key
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAu1IYiNRJVi7HrOW9tlMziyDAv4+vUO2BWHN2x1FhakYwtZnW
8WlotRjgfl6lOJUIREjr5qAZIPFg9cMLjwA6JQ7No2kEto/8Hm6gewWCoYE66ZDZ
~~
enJiaeTm8Rtf/d1K3bLM8iKM+Kfr1UdnO06jSPKNBhlReTxminBmpxaOr2IsXpCg
LaXg4qLrRqh7r3I/9A3h2T3KEuur8kNjP33EY6xjJ+5jC+bgtz///g==
-----END RSA PRIVATE KEY-----


# CSR 파일 생성
openssl req -new -key hellouz818.key -out hellouz818.csr -subj "/O=kubeadm:cluster-admins/CN=hellouz818"

# 확인
cat hellouz818.csr
-----BEGIN CERTIFICATE REQUEST-----
MIICezCCAWMCAQAwNjEfMB0GA1UECgwWa3ViZWFkbTpjbHVzdGVyLWFkbWluczET
MBEGA1UEAwwKaGVsbG91ejgxODCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
~~~
Kw6HjWjy/4u1lECE0bg5zLdNF9UGx52eqrOoSNFfStnVQ94LaMprVLKsezmdBj2O
bNid9xul3zUJuxTo/z2EeQF5KGai8OBqCVZg588AIi4zvmwJxe+CYjESZSU0fsAo
iXV2JrAUMmJ04zGOw3S9
-----END CERTIFICATE REQUEST-----

# 출력 값을 아래 request 에 붙여넣기
cat hellouz818.csr | base64 | tr -d '\n'

# CSR 요청 : k8s 내부적으로 루트인증서의 비밀키로 서명해 반환. 간접적으로 루트 인증서의 비밀키를 사용할 수 있음
vi csr.yaml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: hellouz818-csr
spec:
  signerName: kubernetes.io/kube-apiserver-client
  groups:
  - system:masters
  - system:authenticated
  request: FBd05qRWZNQjBHQTFVRUNnd~~
  usages:
  - digital signature
  - key encipherment
  - client auth

kubectl apply -f csr.yaml
certificatesigningrequest.certificates.k8s.io/hellouz818-csr created

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


# csr 승인할 수 있는 사용자인지 확인
kubectl get clusterrolebinding | grep certificates
kubeadm:node-autoapprove-bootstrap                              ClusterRole/system:certificates.k8s.io:certificatesigningrequests:nodeclient       25h
kubeadm:node-autoapprove-certificate-rotation                   ClusterRole/system:certificates.k8s.io:certificatesigningrequests:selfnodeclient   25h


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

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

 
 
이제 정상적으로 CSR가 승인 받았다면 CA가 인증서를 발급해줍니다.
이제 해당 인증서와 개인 키파일을 가지고 kubeconfig에 새로운 사용자를 등록해주면 새로운 사용자는 kubectl를 통해 클러스터에 접근할 수 있습니다.

# csr 파일 확인
kubectl get csr hellouz818-csr -o yaml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"certificates.k8s.io/v1","kind":"CertificateSigningRequest","metadata":{"annotations":{},"name":"hellouz818-csr"},"spec":{"groups":["system:masters","system:authenticated"],"request":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ2V6Q0NBV01DQVFBd05qRWZNQjBHQTFVRUNnd1dhM1ZpWldGa2JUcGpiSFZ6ZEdWeUxXRmtiV2x1Y3pFVApNQkVHQTFVRUF3d0thR1ZzYkc5MWVqZ3hPRENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DCmdnRUJBTHRTR0lqVVNWWXV4NnpsdmJaVE00c2d3TCtQcjFEdGdWaHpkc2RSWVdwR01MV1oxdkZwYUxVWTRINWUKcFRpVkNFUkk2K2FnR1NEeFlQWERDNDhBT2lVT3phTnBCTGFQL0I1dW9Ic0ZncUdCT3VtUTJValVVWnE1bTAvKwozYXdxcDVISEM2eVdRQXB3OUZzeTM3MVM0ZEVJSkRlQWVBaE5MM2s3OEY4UGdzYXNyNWZVZjYzL3JxS050czA1Cm1GTytyRnZvcjAyRGd2amcvd3JMTGpFcWlTM2VZNXhMNHRBZ0h3NU9UZHNONlN4M25NMWt5SzBDSElvQmxVZHYKbm5qMmIxTHRneFdpeEdDTTJ4eklHclpmUUpNakJNV1BFd3BnQVI2Y3ZCWVplZlg1eGdBRUhndUpYTnhtenQ0ZQpZRnowSEIrSXhDdmpleWpCdm9MdndySFI4djhDQXdFQUFhQUFNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUFUCnR0MVprWThjakFBV2pkbDBQYmZ6dk1LSWdRMHlwTzU0RTNxWHVVekVIdFlMcnhpSm40VzV0SDcrOXp2MmhFVk8Kd0IyV1NXc3VmL3hBV1VEblB4bG5FMkhuKzRxeDNwMW1VdHJQQjBOemJmRWFSV0E3Q3dqYysvTVZseGJpTFYyWQpObUhhY2RZWG83TFl1YXNUMFdlRy9BajF3Y1A5cCs1SGl4WFBFSHk5TjhiOERnVHBzUzkya3g4aXk5N3p6T3ZUCkt3NkhqV2p5LzR1MWxFQ0UwYmc1ekxkTkY5VUd4NTJlcXJPb1NORmZTdG5WUTk0TGFNcHJWTEtzZXptZEJqMk8KYk5pZDl4dWwzelVKdXhUby96MkVlUUY1S0dhaThPQnFDVlpnNTg4QUlpNHp2bXdKeGUrQ1lqRVNaU1UwZnNBbwppWFYySnJBVU1tSjA0ekdPdzNTOQotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K","signerName":"kubernetes.io/kube-apiserver-client","usages":["digital signature","key encipherment","client auth"]}}
  creationTimestamp: "2025-03-11T18:06:15Z"
  name: hellouz818-csr
  resourceVersion: "120775"
  uid: 60ce34fa-c60d-44df-9072-1923db4d3d86
spec:
  extra:
    authentication.kubernetes.io/credential-id:
    - X509SHA256=8d42b8f5d2f8a801150684a46485cb908839ef092832f7a8bf64e0db6eafe1f3
  groups:
  - kubeadm:cluster-admins
  - system:authenticated
  request: ## 이건 hellouz818.csr 파일 인코딩 LS0tLS1CRUdJTiBDRVJUSU
  signerName: kubernetes.io/kube-apiserver-client
  usages:
  - digital signature
  - key encipherment
  - client auth
  username: kubernetes-admin
status:
  certificate: ## 이게 발급받은 인증서 LS0tLS1CRUdJTiBDRVJUSUZJQ0Fg==
  conditions:
  - lastTransitionTime: "2025-03-11T18:08:09Z"
    lastUpdateTime: "2025-03-11T18:08:09Z"
    message: This CSR was approved by kubectl certificate approve.
    reason: KubectlApprove
    status: "True"
    type: Approved


# csr 에서 인증서 추출
kubectl get csr hellouz818-csr -o jsonpath='{.status.certificate}' | base64 -d
-----BEGIN CERTIFICATE-----
MIIDLDCCAhSgAwIBAgIRAJuC/kiWnI7V6mNpJaZ8lNUwDQYJKoZIhvcNAQELBQAw
FTETMBEGA1UEAxMKa3ViZXJuZXRlczAeFw0yNTAzMTExODAzMDlaFw0yNjAzMTEx
~~
5S1nU5RVzYkvoBWZq4EvSlzj+D1D0kKFD1iBd7jCOtVO4Ywegi+PDN9JIXz6LZfM
Rit3ysr8ih4TRV6qvglYJEcPFPtJnnFC6scgIIGVvkwEhqR+zk8bOOx+NktQNn3v
-----END CERTIFICATE-----

# crt 파일로 인증서 추출
kubectl get csr hellouz818-csr -o jsonpath='{.status.certificate}' | base64 -d > hellouz818.crt

# crt 파일 확인
openssl x509 -in hellouz818.crt -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            9b:82:fe:48:96:9c:8e:d5:ea:63:69:25:a6:7c:94:d5
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=kubernetes
        Validity
            Not Before: Mar 11 18:03:09 2025 GMT
            Not After : Mar 11 18:03:09 2026 GMT
        Subject: O=kubeadm:cluster-admins, CN=hellouz818 # 아까 csr 생성 시 넣었던 O, CN 값
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:bb:52:18:88:d4:49:56:2e:c7:ac:e5:bd:b6:53:
                    33:8b:20:c0:bf:8f:af:50:ed:81:58:73:76:c7:51:

# kubeconfig 에 새로운 사용자 등록
kubectl config set-credentials hellouz818-user --client-certificate=hellouz818.crt --client-key=hellouz818.key
User "hellouz818-user" set.

kubectl config set-context kind-hellouz818 --cluster=kind-myk8s --user=hellouz818-user
Context "kind-hellouz818" created.

cat ~/.kube/config
...
contexts:
- context:
    cluster: kind-myk8s
    user: hellouz818-user
  name: kind-hellouz818
- context:
    cluster: kind-myk8s
    user: kind-myk8s
  name: kind-myk8s
current-context: kind-myk8s
kind: Config
preferences: {}
users:
- name: hellouz818-user
  user:
    client-certificate: /root/hellouz818.crt
    client-key: /root/hellouz818.key
...
# 사용한 crt, key 파일이 user 정보에 존재

# kubectl ctx kind-hellouz818도 동일
kubectl config use-context kind-hellouz818 
Switched to context "kind-hellouz818".

# ctx kind-hellouz818 로 k8s 정보 확인 시도
kubectl get node
NAME                  STATUS   ROLES           AGE   VERSION
myk8s-control-plane   Ready    control-plane   26h   v1.32.2
kubeconfig