쿠버네티스는 API Sever가 제공하는 리소스(Deployment, Service, Pod, ...)를 생성, 수정, 삭제하면서 어플리케이션을 운영하게 됩니다.
이때 kubectl 도구를 많이 이용하는데, 이는 K8S API Server에게 REST Call을 하는 클라이언트 프로그램입니다.
node 목록을 조회하는 아래 명령을 수행할때 verbose 레벨을 6으로 조정하면 호출되는 REST API 엔드포인트를 확인 할 수 있습니다.
| [root@k8s-cp ~]# kubectl get no --v 6 I0315 21:54:38.318179 440925 loader.go:395] Config loaded from file: /root/.kube/config I0315 21:54:38.340374 440925 round_trippers.go:553] GET https://192.168.10.50:6443/api/v1/nodes?limit=500 200 OK in 13 milliseconds NAME STATUS ROLES AGE VERSION k8s-cp Ready control-plane 94d v1.31.3 k8s-w1 Ready <none> 94d v1.31.3 k8s-w2 Ready <none> 94d v1.31.3 |
위의 엔드포인트를 curl을 이용하여 호출해보면 아래와 같은 응답을 받게 됩니다.
| [root@k8s-cp ~]# curl -k https://192.168.10.50:6443/api/v1/nodes { "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Failure", "message": "nodes is forbidden: User \"system:anonymous\" cannot list resource \"nodes\" in API group \"\" at the cluster scope", "reason": "Forbidden", "details": { "kind": "nodes" }, "code": 403 } |
API Server 입장에서 노드 목록을 조회하려는 사람이 누구인지 인증(Authentication) 하여야 하고, 인증이 되었다면 노드 목록을 조회할 수 있는 권한이 있는지 인가(Authorization)를 통과해야 정상적인 노드 목록에 대한 응답을 반환할 것입니다.

이때 kubectl 명령은 OS 계정의 홈경로밑에 ~/.kube/config 파일을 이용하여 Authentication과 Authorization을 위한 정보를 API Sever에게 제공합니다.
~/.kube/config 파일 내용
|
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURCVENDQWUyZ0F3SUJBZ0lJU3ZkcHFYeWMwMGd3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TkRFeU1URXdNVFV3TkRKYUZ3MHpOREV5TURrd01UVTFOREphTUJVeApFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLCkFvSUJBUUM1VXhocmRCNTFwY2JvUGRSamd1NGttUXQveVN3RjFtRDRVYllESXVsSXcvYUoybVRzclZCa1gwcE8KaEJ1a0N0TWh0ajRxOGVkb2dFdzI5ZVRKeTVvNEZwL1lHODVUdlY0bjJlWkE1YWsvOFFrOGNVQ0YzemdYZWFJbQpreUhMSE90bGxVTEdaRlI4UWMrcU5ROGJFeHd0d0MwM0JaTzVnWTd4VXo3ZzZEQk1pM3JRYUd6Z0ZjcG1yZTdwClliTnhFZ0l0b1AxSlhIbTJqMFRTRVQ2VUNZaDk0eE9KZXJsbTQyUHNIMTU3OHJ2WGExeDZoeU5XdzVGQkRsYXMKZXFTaGRPWXA0aGNmMlM4Q3prWWtTWCtCME4wUVROYmJCdktEbEE4MkhvaXk4dTR3NkRibmZTNWw1WEZxdVczOQpsSWVhZnNJMHFSeTZzV05qZy9BYUxtVkJscW9iQWdNQkFBR2pXVEJYTUE0R0ExVWREd0VCL3dRRUF3SUNwREFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUIwR0ExVWREZ1FXQkJUQXVGL1dYQmNJQnFOSE9YbVBic1VPYVRsZjN6QVYKQmdOVkhSRUVEakFNZ2dwcmRXSmxjbTVsZEdWek1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQm9VOFhhWjhZQgpDYnV4RmtJUXhPc3paemxLT2Jxam5pZERTQmxlUUsxMVdWeDNiMTljYjlWUXpTeFlaS0JqWkdaRHVsazhFVEM3CnhxVUcyWHlaamd5aUgwYi9KQzR5dE9BL2VVUFVQQ3NtRTdjSVR3amY3dzc5N1hQVjh4Z2NSMHJqT1g1ZlFxZHQKYVhjRnVwZmtLQjNmTkMzVEF3eURnWEtQbW01ZUVCenRrT09YRldMM1NrcExBRDVnZ3JpSXVNMUVqTjZMc285Zwo0dFhGTWhIVjVTZ05zcmxRd3QxWWkrSDBkVmFQRDhPMGR6TTFSTU9URXBnVDZPYjJycjBaRTVLN0VoZHhjREE5CllyZXNZSDJFbExCU0FLU2dvdmcyY2Fmb0tkcm1jZE44RTdHMWNheXZsWkR5V1I2d2Y4UlBJQ2pmS3hFeE1CalAKWFNRWGpEbDEzT3BuCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
server: https://192.168.10.50:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLVENDQWhHZ0F3SUJBZ0lJT0hvUHl2T2ozOEl3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TkRFeU1URXdNVFV3TkRKYUZ3MHlOVEV5TVRFd01UVTFOREphTUR3eApIekFkQmdOVkJBb1RGbXQxWW1WaFpHMDZZMngxYzNSbGNpMWhaRzFwYm5NeEdUQVhCZ05WQkFNVEVHdDFZbVZ5CmJtVjBaWE10WVdSdGFXNHdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDaWQ2Y1EKbU1PajdmTW9VV0Vac1RuTU83UUE1S0RuMlVQKzJFQ2JOTSt0bmN1WTJ1dVQ1dTYyUE9iUDRQV1N4KzBHak5xcQptMkxkcW90OVVSSzJLczZSQWg2QmZUVFNmQktZTDFOaU9MRjdnMC9jaVQzRHk1bm52TFRZdW9yR25FcElseE1aCnk5TVR2WmNFbktha0ovTUJpbGF3MlczdjlucC9JemxaR2kyaUdmaG9LTmZXRk5KWUE2Mm84Z3IrQThzb29PKzYKb2tFRUpyMEZEYzlIYjRyNHdTRUZUU1N0dnJVOC9JTjZEV2VsOXY5dFd6dUt0b211aUducFI0cW9YLzZLLzJsMQp4Qks0enJ3TGFxaHVZYUU1TWl2VU00a0tNa0JBRWROYkxIME5QaW55Z01DZC9JVG1OajBESE1QcW1QM04rQnV1CjRBRUJwcC90UHRqNHNVQkhBZ01CQUFHalZqQlVNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUsKQmdnckJnRUZCUWNEQWpBTUJnTlZIUk1CQWY4RUFqQUFNQjhHQTFVZEl3UVlNQmFBRk1DNFg5WmNGd2dHbzBjNQplWTl1eFE1cE9WL2ZNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUNDZWRXTTNEeHNhR1dISm1sUmtndFVxRTl3CnNwT1FxOUJVdEplWXE0WXVEUlVRNTV5UFdHSmNJMUoxeEVOOFQ5ZEwzdENrQW91ZG9zWFdoUWVxTzNKeXUxV0gKR0hTajMzendUMkZXODVMdWFiS2NtTXpDcEhSVDhNVmgvZVBhSjVPbHA3Z1I4RHpXTGNtUzJUNTdYbm0rZVQ0NApTTjFHSWhnems3QzQ0MHFiU2YzRHlRRURFRFlOWGUyeVZOOXJFTkNTYWtFZWJrNm9EQ2U4STBTVTZPcDBYT0JpCis4a1MzTTlRN2hQcUI4ZFhuOE1VY1JCUFNtRXkzdDBBbjFDRnZvSU42aXdCTFM0Yit1UGNPRnZ5Q2UvYm5NZmUKa1NsajBRT0JDUHBhekdMNW4yQitOUUI2UzFVamxub0U4ZHhXVW5TYXJ1NjNLTUdNUTNzTGEwdGxBUGw2Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBb25lbkVKakRvKzN6S0ZGaEdiRTV6RHUwQU9TZzU5bEQvdGhBbXpUUHJaM0xtTnJyCmsrYnV0anpteitEMWtzZnRCb3phcXB0aTNhcUxmVkVTdGlyT2tRSWVnWDAwMG53U21DOVRZaml4ZTROUDNJazkKdzh1WjU3eTAyTHFLeHB4S1NKY1RHY3ZURTcyWEJKeW1wQ2Z6QVlwV3NObHQ3L1o2ZnlNNVdSb3RvaG40YUNqWAoxaFRTV0FPdHFQSUsvZ1BMS0tEdnVxSkJCQ2E5QlEzUFIyK0srTUVoQlUwa3JiNjFQUHlEZWcxbnBmYi9iVnM3CmlyYUpyb2hwNlVlS3FGLytpdjlwZGNRU3VNNjhDMnFvYm1HaE9USXIxRE9KQ2pKQVFCSFRXeXg5RFQ0cDhvREEKbmZ5RTVqWTlBeHpENnBqOXpmZ2JydUFCQWFhZjdUN1krTEZBUndJREFRQUJBb0lCQUJvdHJYMi9IOGNLVUdQdQp1UGFxMStWUXVYQnJab0gxUUQrUUdOanBhWTFRSDc1QmlEUU13ZW9iWmhXWTZmajh2ZlNRUGF1LzNlNVp6S0FrCnNCOHFScDZXK05Oa21WNVJINjNsOGttaFdQZk44TkJZVE50L3N3emtHei9Rend1eG8wYVBFVVRXMHV3YllIb2QKdzd3dnM3aEwwaXdzM01vTnJTOVBQYTVkeVh5VThPL096ekN4MGE5VThuUVJOdzRvNm1SSVgyWVpRdEdua1RwUAo3QWlzdGNVR1VvQ2lEUlc5SDZIcDE5UjF4b2prb296b1NsZHNINFJqaXZzay9lejNxOTRoRlhGclhmd0doakdZCkFOWENhS2FNVENCTVpNQ3VRTDQrdlAyNzVqM3RuTHlCbThmanE5UUtRenYvOW5aR1ZtYllTQWQ3aU1ZeUF3MFYKK052aS9nRUNnWUVBMHJSMFQxWXdkVklCOCtQNHJQcWovUm5xMzJid2Y0SDFUSUpPOEUzREZweFVuN1NPR2tZWgozZ2VZczlKNUpuQUFBeE5vZGhRUHNoWFRNb000V2hqL0FDdmpaalgySS8xUEw2YmNPdHNvanJFTUF4Zy9heFRYClloMVdmd1FrcVltWGpOUTRjd3NkNGx5amV5RkJ4c2ZPUWJ1UFQrR28wSGJFbGR5UXU3a09aSTBDZ1lFQXhXU1YKaHZYSVlOL1ZkdFh6cXRRTndWTk1lTFFROVRnK2pyZyt0NWRVRGs2T0VYQU4xZG8xWTZUZWlGTjNyRXd3NCtDcQoxb21BUmlFcXdrcUZSZGlOWXJFR2w3OENUNFhjbGVTWm5oMDZxWlpoY0pNRkQ2MkdSbzlac3hGaWZsU2Z3dUtXCjEyMmxocytodFZGOHJMR2I0Y096cnhxMGQ5N0tpdHpmbmwzOXhTTUNnWUJ4OGRab1JSTGxqeGl4UE5weEtRWGYKek5GQVNObk1Db3FOK25ZWDYrV1JaNjgzd3B1S1I5aWJRbjVvMkd4ZHhmbXJzQ1l3bkw2MExxdE15THVEdGJySQo2L01JaGl2NjRIU2ZMMXd2ays4RjQyYThrYk5TQkM1Sng5WEwwSURIRWpwYmxUU0Z1a0JKOXBFTitEa3E5MGhxCk1iVFpuUTMrMWd1UGczemRsOERaelFLQmdRQ04vRVVHV0NNemM2NVRsYUI1WDZFcFQ2YXhLQzBPaHMrUXozemwKaUdmQkJzWndTcDdaRmVYVGNCTldFbHdCeHFoZ01nb1EyY1U0TE1GYUVrcDlMRUMvSGNFMVJBTUFlclJwNlk2SwpTbElaREgrNGZ6aGp4NWpQaG11cVA3WU9Vd2E4STBzSFdPcDQ1ejlWY25Ed3M2MENIMGhQaXpFSERHMjZweGYvCkRYTHQ2d0tCZ1FERFByWW1SbnI2dVNjVmtoY1ZkQWZBUFMrTXNhb0tjR25BdUpjZzNlMlpzTi9EZWNMRWpTajMKdEFudXZPNmIxaXZHOEJaSnZnb2thYms3RTVETGwya1NROGJBSjFDeEFDcC90YzU5cnpMMktIQUJ6Z1FLcWcyRgpRVHEvTEc4N2Vra0liL0h5SkpXSks4cmZGcnprdVI3eXZxTy9wM3ZLK2JnS1ZuVXRXcUNqOEE9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
|
K8S 사용자와 그룹

API 서버는 2가지 유형의 클라이언트로 구분합니다.
- Human User
- 실제 사람으로 LDAP, SSO 같은 별도의 외부 계정 시스템을 통해 관리
- 쿠버네티스에는 사용자계정을 나타내는 리소스는 없음
- Machine User
- POD 에서는 Service Accounts 라는 메커니즘을 사용하고, ServcieAccount 리소스로 생성되고 저장
그룹
- 사용자 및 ServiceAccount는 하나 이상의 그룹에 속할 수 있다
- 인증 플러그인이 사용자 이름/ID와 함께 그룹을 반환한다
- 그룹에 속한 사용자에게 한 번에 사용 권한을 부여하는데 사용
- 시스템에서 제공하는 기본 그룹

인증(Authentication) 절차
- 클러스터의 API에 접근하기 위해서는 우선 유효한 사용자인지 인증(authentication)을 거쳐야 한다
- API 서버는 하나 이상의 인증 플러그인으로 구성될 수 있음
- API 서버가 요청을 받으면 인증 플러그인 목록의 각각에게 요청을 전달해 요청을 보낸 사람이 누구인지 확인한다
- 해당 요청에서 정보 추출이 가능한 첫번째 플러그인은 사용자 이름, ID, 클라이언트가 속한 그룹을 API 서버 코어에 반환한다
- API 서버는 나머지 인증 플러그인의 호출을 중지하고 승인(Authorization) 단계로 넘어간다
- 쿠버네티스는 자체적으로 사용자 계정을 관리하고 이를 인증(Authenticate)하는 시스템을 가지고 있지 않다
- 별도의 외부 계정 시스템을 사용해야 하며, 계정 시스템 연동을 위해서 OAuth(Google Account, ...)나 Webhook, LDAP과 같은 계정 연동 방식을 지원한다
- API 서버를 시작할 때 명령행 옵션을 통해 인증 플러그인을 활성화할 수 있다
쿠버네티스에서 지원하는 사용자 인증 메커니즘
- https://kubernetes.io/docs/reference/access-authn-authz/authentication/
- Client 인증서를 이용한 인증 - 바닐라 쿠버네티스의 디폴트 인증 방법
- Webhook Token 인증
- 외부 OIDC를 이용한 인증
쿠버네티스 내부 인증서 관리
kubeadm init 명령을 이용하여 바닐라 쿠버네티스를 구성할 때 아래와 같이 여러가지 인증서가 생성됩니다.
기본적인 인증서의 유효기간은 1년이므로, 1년이 지나면 인증서 갱신 작업이 필요합니다.

인증서 만료기간은 kubeadm certs 명령을 이용하여 확인이 가능합니다.
| [root@k8s-cp ~]# kubeadm certs check-expiration [check-expiration] Reading configuration from the cluster... [check-expiration] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' CERTIFICATE EXPIRES RESIDUAL TIME CERTIFICATE AUTHORITY EXTERNALLY MANAGED admin.conf Jan 13, 2026 09:03 UTC 364d ca no apiserver Jan 13, 2026 09:03 UTC 364d ca no apiserver-etcd-client Jan 13, 2026 09:03 UTC 364d etcd-ca no apiserver-kubelet-client Jan 13, 2026 09:03 UTC 364d ca no controller-manager.conf Jan 13, 2026 09:03 UTC 364d ca no etcd-healthcheck-client Jan 13, 2026 09:03 UTC 364d etcd-ca no etcd-peer Jan 13, 2026 09:03 UTC 364d etcd-ca no etcd-server Jan 13, 2026 09:03 UTC 364d etcd-ca no front-proxy-client Jan 13, 2026 09:03 UTC 364d front-proxy-ca no scheduler.conf Jan 13, 2026 09:03 UTC 364d ca no super-admin.conf Jan 13, 2026 09:03 UTC 364d ca no CERTIFICATE AUTHORITY EXPIRES RESIDUAL TIME EXTERNALLY MANAGED ca Jan 11, 2035 09:03 UTC 9y no etcd-ca Jan 11, 2035 09:03 UTC 9y no front-proxy-ca Jan 11, 2035 09:03 UTC 9y no |
쿠버네티스 내부에서 사용하는 인증서는 kube-system 네임스페이스의 kubeadm-config 라는 컨피그맵에 기록됩니다.

위 인증서 파일중에서 Root CA 인증서와 “kube-apiserver” 에서 사용하는 인증서 파일 정보를 확인해 보겠습니다.

API Server
Authentication 과 Authorization은 API Server가 담당하며, API 서버는 kubelet이 관리하는 Static POD로 실행됩니다.
- 인증을 관리하는 API Server도 kubelet이 관리하는 Static POD
- /etc/kubernetes/manifests/kube-apiserver.yaml 에 POD 매니페스트가 정의 되어 있음

인증서(Certificate)와 Private Key
- 암호화 통신을 위해 필요한 2가지 파일
- 인증서
- SSL 암호화 통신에 사용할 공개키(Public Key)를 포함
- 무엇을 인증하고 있는지에 대한 정보 포함
- Private key
- Public-Key를 암호화한 데이터를 복호화할 수 있는 유일한 수단


Client Certificate Authentication
~/.kube/config 파일에는 API 서버 인증을 위한 정보가 아래와 같이 포함되어 있습니다.

위에 언급한 내용중 "Client Certifacate" 내용을 확인해보면 Organization 정보와, CN(Common Name)을 확인할 수 있는데 이부분이 API Server 가 인식하는 GROUP명과, USER 명에 해당되며, 이 정보를 이용하여 RBAC 제어를 하게 됩니다.


쿠버네티스 Client Certificate 인증 실습
실습 개요
- 일반유저(honggildong) 에게 자신만의 쿠버네티스 네임스페이스에서만 애플리케이션 배포 및 테스트 할 수 있도록 환경 구축
- 그 외의 네임스페이스는 요청 거부

| # “honggildong” 개발자의 작업영역인 namespace 생성 [root@k8s-cp ~]# kubectl create ns honggildong namespace/honggildong created # “honggildong” 리눅스 계정 생성하고 암호는 “jadecross”로 설정 [root@k8s-cp ~]# useradd -G wheel honggildong [root@k8s-cp ~]# passwd honggildong Changing password for user honggildong. New password: jadecross Retype new password: jadecross passwd: all authentication tokens updated successfully. |
일반유저용 CSR 생성
| # “honggildong” 리눅스 계정으로 쉘로그인후, RSA 알고리즘을 사용하는 Private Key 파일 생성 [honggildong@k8s-cp ~]$ openssl genrsa -out honggildong.key 2048 [honggildong@k8s-cp ~]$ cat honggildong.key -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCzJ9wqd654PSnS ~~~ -----END PRIVATE KEY----- # 생성된 PrivateKey를 이용하여 CSR(Certificat Signing Request) 파일 생성 [honggildong@k8s-cp ~]$ openssl req -new \ -key honggildong.key \ -subj "/O=DEV/CN=honggildong" \ -out honggildong.csr [honggildong@k8s-cp ~]$ cat honggildong.csr -----BEGIN CERTIFICATE REQUEST----- MIICaTCCAVECAQAwJDEMMAoGA1UECgwDREVWMRQwEgYDVQQDDAtob25nZ2lsZG9u ~~~ -----END CERTIFICATE REQUEST----- |
CSR 파일으 O, CN 정보가 올바른지 확인합니다.

CertificateSigningRequest

개별사용자의 CSR 서명은 쿠버네티스 클러스터의 Root CA 를 이용하여 서명해야 합니다.
Root CA를 통하여 인증서 생성을 위한 CSR 리소스를 아래와 같이 생성합니다.

클러스터 관리자는 개별 사용자용 CSR 리소스를 생성하고 승인하여 클라이언트 인증서를 생성합니다.
| [root@k8s-cp ~]# kubectl get csr No resources found [root@k8s-cp ~]# kubectl apply -f ~honggildong/honggildong-csr.yaml certificatesigningrequest.certificates.k8s.io/honggildong-csr created [root@k8s-cp ~]# kubectl get csr NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION honggildong-csr 11s kubernetes.io/kube-apiserver-client kubernetes-admin <none> Pending [root@k8s-cp ~]# kubectl get csr honggildong-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":"honggildong-csr"},"spec":{"groups":["system:authenticated"],"request":"LS0tLS~~DATA+OMITTED~~LQo=","signerName":"kubernetes.io/kube-apiserver-client","usages":["digital signature","key encipherment","client auth"]}} creationTimestamp: "2025-03-02T06:19:36Z" name: honggildong-csr resourceVersion: "20943" uid: f667e749-5d73-4f76-a69f-d15db2f1f299 spec: groups: - kubeadm:cluster-admins - system:authenticated request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ2FUQ0NBVkVDQVFBd0pERU1NQW~~DATA+OMITTED~~Qo= signerName: kubernetes.io/kube-apiserver-client usages: - digital signature - key encipherment - client auth username: kubernetes-admin status: {} |
클러스터 관리자는 제출된 CSR 을 Approve 하여, 디지털 서명 후 클라이언트 인증서를 생성합니다.
| [root@k8s-cp ~]# kubectl certificate approve honggildong-csr certificatesigningrequest.certificates.k8s.io/honggildong-csr approved [root@k8s-cp ~]# kubectl get csr NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION honggildong-csr 6m20s kubernetes.io/kube-apiserver-client kubernetes-admin <none> Approved,Issued # certificate 필드에 있는 부분이 생성된 인증서 정보입니다. [root@k8s-cp ~]# kubectl get csr honggildong-csr -o yaml apiVersion: certificates.k8s.io/v1 kind: CertificateSigningRequest metadata: ~~~ spec: groups: - kubeadm:cluster-admins - system:authenticated request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ2FUQ0NBVkVDQVFBd0pERU1NQW9HQTFVRUNnd0RSRVZ~~DATA+OMITTED~~XTVJRdLS0tLQo= signerName: kubernetes.io/kube-apiserver-client usages: - digital signature - key encipherment - client auth username: kubernetes-admin status: certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURHVENDQWdHZ0F3SUJBZ0lRZHJKeTFOeTVuKzFKNFNNVklZRZ~~DATA+OMITTED~~JQ0FURS0tLS0tCg== conditions: - lastTransitionTime: "2025-03-02T06:23:03Z" lastUpdateTime: "2025-03-02T06:23:03Z" message: This CSR was approved by kubectl certificate approve. reason: KubectlApprove status: "True" type: Approved |

디지털 서명된 CSR로부터 클라이언트 인증서 추출 후 인증서 정보 확인합니다.
| [root@k8s-cp ~]# k get csr honggildong-csr -o jsonpath='{.status.certificate}' | base64 -d > ~honggildong/honggildong.crt [root@k8s-cp ~]# openssl x509 -text -noout -in ~honggildong/honggildong.crt Certificate: Data: Version: 3 (0x2) Serial Number: 8a:de:cb:e1:29:2d:a5:e3:d4:bb:02:64:8d:7a:2a:a0 Signature Algorithm: sha256WithRSAEncryption Issuer: CN = kubernetes Validity Not Before: Mar 10 01:20:02 2025 GMT Not After : Mar 10 01:20:02 2025 GMT Subject: O = DEV, CN = honggildong Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:cf:36:87:05:d7:5e:b5:7e:a8:e2:dc:0f:2c:97: ~~~ 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: 0B:34:FC:FB:AD:98:38:6E:E8:A4:78:5A:B4:5D:13:4A:E1:2D:DD:14 Signature Algorithm: sha256WithRSAEncryption Signature Value: 24:44:5b:ea:80:d6:62:db:c6:ea:eb:fb:5c:90:9c:99:a9:0c: ~~~ |
일반 사용자를 위한 Kube Config 작업 - Set a cluster entry in kubeconfig
| # “hongildong” 사용자를 위한 Kubernetes Configuation File 이 생성되었는지 확인 [honggildong@k8s-cp ~]$ cat ~/.kube/config cat: /home/honggildong/.kube/config: No such file or directory # “hongildong” 사용자를 위한 K8S Cluster 추가하고 목록 확인 [honggildong@k8s-cp ~]$ kubectl config set-cluster edu-k8s \ --server=https://172.31.1.10:6443 \ --certificate-authority=/etc/kubernetes/pki/ca.crt Cluster "edu-k8s" set. [honggildong@k8s-cp ~]$ kubectl config get-clusters NAME edu-k8s # Kube Config 파일에 등록된 클러스터 확인 [honggildong@k8s-cp ~]$ cat ~/.kube/config apiVersion: v1 clusters: - cluster: certificate-authority: /etc/kubernetes/pki/ca.crt server: https://172.31.1.10:6443 name: edu-k8s contexts: null current-context: "" kind: Config preferences: {} users: null # “honggildong” 사용자를 위한 Credential 등록 [honggildong@k8s-cp ~]$ kubectl config get-users NAME [honggildong@k8s-cp ~]$ kubectl config set-credentials honggildong \ --client-certificate=/home/honggildong/honggildong.crt \ --client-key=/home/honggildong/honggildong.key User "honggildong" set. [honggildong@k8s-cp ~]$ kubectl config get-users NAME honggildong # Kube Config 파일에 등록된 사용자 확인 [honggildong@k8s-cp ~]$ cat ~/.kube/config apiVersion: v1 clusters: - cluster: certificate-authority: /etc/kubernetes/pki/ca.crt server: https://172.31.1.10:6443 name: edu-k8s contexts: null current-context: "" kind: Config preferences: {} users: - name: honggildong user: client-certificate: /home/honggildong/honggildong.crt client-key: /home/honggildong/honggildong.key # “honggildong” 사용자를 위한 Context 등록 [honggildong@k8s-cp ~]$ kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE [honggildong@k8s-cp ~]$ kubectl config set-context honggildong-context --cluster=edu-k8s --user=honggildong Context "honggildong-context" created. [honggildong@k8s-cp ~]$ kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE honggildong-context edu-k8s honggildong # Kube Config 파일에 등록된 Context 확인 [honggildong@k8s-cp ~]$ cat ~/.kube/config apiVersion: v1 clusters: - cluster: certificate-authority: /etc/kubernetes/pki/ca.crt server: https://172.31.1.10:6443 name: edu-k8s contexts: - context: cluster: edu-k8s user: honggildong name: honggildong-context current-context: "" kind: Config preferences: {} users: - name: honggildong user: client-certificate: /home/honggildong/honggildong.crt client-key: /home/honggildong/honggildong.key # “honggildong” 사용자를 위한 Current Context 설정 [honggildong@k8s-cp ~]$ kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE honggildong-context edu-k8s honggildong [honggildong@k8s-cp ~]$ kubectl config use-context honggildong-context Switched to context "honggildong-context". [honggildong@k8s-cp ~]$ kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE * honggildong-context edu-k8s honggildong # Kube Config 파일에 등록된 Current Context 확인 [honggildong@k8s-cp ~]$ cat ~/.kube/config apiVersion: v1 clusters: - cluster: certificate-authority: /etc/kubernetes/pki/ca.crt server: https://172.31.1.10:6443 name: edu-k8s contexts: - context: cluster: edu-k8s user: honggildong name: honggildong-context current-context: honggildong-context kind: Config preferences: {} users: - name: honggildong user: client-certificate: /home/honggildong/honggildong.crt client-key: /home/honggildong/honggildong.key |
이제 honggildong 사용자는 Client Certificate 를 통해 API Server에 인증을 통과할 수 있는 상태입니다.
| # “honggildong” 사용자로 pod 목록조회 명령을 실행하고 실패하는 원인을 파악 [honggildong@k8s-cp ~]$ kubectl get po --v=6 I0302 16:19:49.146930 113364 loader.go:395] Config loaded from file: /home/honggildong/.kube/config I0302 16:19:49.151587 113364 cert_rotation.go:137] Starting client certificate rotation controller I0302 16:19:49.171599 113364 round_trippers.go:553] GET https://172.31.1.10:6443/api/v1/namespaces/default/pods?limit=500 403 Forbidden in 7 milliseconds I0302 16:19:49.172043 113364 helpers.go:246] server response object: [{ "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Failure", "message": "pods is forbidden: User \"honggildong\" cannot list resource \"pods\" in API group \"\" in the namespace \"default\"", "reason": "Forbidden", "details": { "kind": "pods" }, "code": 403 }] Error from server (Forbidden): pods is forbidden: User "honggildong" cannot list resource "pods" in API group "" in the namespace "default" ![]() |
root 계정(클러스터 관리자)으로 “honggildong” 사용자에게 “Deployment, ReplicaSet, Pod” 리소스에 대한 RBAC 권한 부여하겠습니다.
| [root@k8s-cp ~]# kubectl apply -f - <<EOF apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: honggildong name: honggildong-role rules: - apiGroups: ["", "extensions", "apps"] resources: ["deployments", "replicasets", "pods"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: namespace: honggildong name: honggildong-rolebinding roleRef: kind: Role name: honggildong-role apiGroup: rbac.authorization.k8s.io subjects: - kind: User name: honggildong EOF role.rbac.authorization.k8s.io/honggildong-role created rolebinding.rbac.authorization.k8s.io/honggildong-rolebinding created # “honggildong” 사용자에게 부여된 RBAC 리소스 정보 확인 [root@k8s-cp ~]# kubectl -n honggildong describe rolebindings honggildong-rolebinding Name: honggildong-rolebinding Labels: <none> Annotations: <none> Role: Kind: Role Name: honggildong-role Subjects: Kind Name Namespace ---- ---- --------- User honggildong [root@k8s-cp ~]# kubectl -n honggildong describe role honggildong-role Name: honggildong-role Labels: <none> Annotations: <none> PolicyRule: Resources Non-Resource URLs Resource Names Verbs --------- ----------------- -------------- ----- deployments [] [] [get list watch create update patch delete] pods [] [] [get list watch create update patch delete] replicasets [] [] [get list watch create update patch delete] deployments.apps [] [] [get list watch create update patch delete] pods.apps [] [] [get list watch create update patch delete] replicasets.apps [] [] [get list watch create update patch delete] deployments.extensions [] [] [get list watch create update patch delete] pods.extensions [] [] [get list watch create update patch delete] replicasets.extensions [] [] [get list watch create update patch delete] |
이제 RBAC 설정을 마쳤으므로 “honggildong” 사용자 쉘에서 nginx Deployment 리소스 생성이 가능합니다.
| [honggildong@k8s-cp ~]$ kubectl -n honggildong create deploy nginx --image=nginx deployment.apps/nginx created [honggildong@k8s-cp ~]$ kubectl -n honggildong get all NAME READY STATUS RESTARTS AGE pod/nginx-7854ff8877-cjd9v 1/1 Running 0 2m25s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/nginx 1/1 1 1 2m25s NAME DESIRED CURRENT READY AGE replicaset.apps/nginx-7854ff8877 1 1 1 2m25s Error from server (Forbidden): replicationcontrollers is forbidden: User "honggildong" cannot list resource "replicationcontrollers" in API group "" in the namespace "honggildong" Error from server (Forbidden): services is forbidden: User "honggildong" cannot list resource "services" in API group "" in the namespace "honggildong" Error from server (Forbidden): daemonsets.apps is forbidden: User "honggildong" cannot list resource "daemonsets" in API group "apps" in the namespace "honggildong" Error from server (Forbidden): statefulsets.apps is forbidden: User "honggildong" cannot list resource "statefulsets" in API group "apps" in the namespace "honggildong" Error from server (Forbidden): horizontalpodautoscalers.autoscaling is forbidden: User "honggildong" cannot list resource "horizontalpodautoscalers" in API group "autoscaling" in the namespace "honggildong" Error from server (Forbidden): cronjobs.batch is forbidden: User "honggildong" cannot list resource "cronjobs" in API group "batch" in the namespace "honggildong" Error from server (Forbidden): jobs.batch is forbidden: User "honggildong" cannot list resource "jobs" in API group "batch" in the namespace "honggildong“ |
'Kubernetes' 카테고리의 다른 글
| AEWS [3기] 8주차 - K8S CI/CD 와 kustomize (1) | 2025.03.29 |
|---|---|
| AEWS [3기] 7주차 - EKS Mode - Fargate (0) | 2025.03.22 |
| AEWS [3기] 5주차 - EKS Autoscaling (0) | 2025.03.08 |
| AEWS [3기] 4주차 - OpenTelemetry (0) | 2025.03.01 |
| AEWS [3기] 3주차 - EKS Storage, Managed Node Groups (1) | 2025.02.22 |
