[kubernetes] 인증

728x90

인증

공식 문서: https://kubernetes.io/docs/reference/access-authn-authz/authentication/

쿠버네티스의 사용자

  • Service Account(SA): 쿠버네티스가 관리하는 SA 사용자
    • 사용자가 사용하지 않는다.
    • Pod 가 사용하는 계정이다.
  • Normal User: 일반 사용자(쿠버네티스가 관리하지 않는다.)
    • 사용자가 사용하는 계정이다.
    • Pod 는 사용하지 않는다.

인증 방법:

  • x509 인증서
  • static token
    • Bearer Token
      • http 헤더에 인증 정보가 있는 토큰을 담아서 보낸다.
    • Service Account Token
      • JSON Web Token: JWT
    • OpenID Connect(OIDC)
      • 외부 인증 표준화 인터페이스
      • okta 인증 서버 서비스가 있다.
      • OAuth Provider: EKS 에서 IAM 계정을 사용하는 방식이 바로 OIDC 를 사용한 방식이다.

Pod 는 SA 계정을 사용하고 SA 계정에 할당받은 Token 을 사용한다.

사용자(나)는 x509 를 사용하여 kubectl 을 사용한다.

RBAC: Role Based Access Control

공식 문서: https://kubernetes.io/docs/reference/access-authn-authz/rbac/, https://kubernetes.io/ko/docs/reference/access-authn-authz/authorization/

역할 기반 접근 제어(RBAC, Role-based access control)는 클러스터 내 개별 사용자의 역할을 기반으로 컴퓨터나 네트워크 리소스에 대한 접근을 규제하는 방식이다. 이 맥락에서 접근은 개별 사용자가 파일을 보거나 만들거나 수정하는 것과 같은 특정 작업을 수행할 수 있는 능력이다.

  • Role: 특정 Name Space 내에서만 권한 부여 가능
  • ClusterRole: 글로벌하게 권한 부여 가능
    • view: 읽을 수 있는 권한
    • edit: 생성/삭제/변경할 수 있는 권한
    • admin: 모든 것 관리(RBAC의 ClusterRole 제외)
    • cluster-admin: 모든 것 관리
  • RoleBinding
    • 특정 Name Space 내에서 Role 과 SA/User 사용자를 연결시켜 주는 것이 RoleBinding 이다.
  • ClusterRoleBinding
    • ClusterRole 과 SA/User 사용자를 연결시켜주는 것이 ClusterRoleBinding 이다.

$ kubectl get po -v=7
I0526 06:31:24.674874  163632 loader.go:372] Config loaded from file:  /home/vagrant/.kube/config
I0526 06:31:24.695368  163632 round_trippers.go:432] GET <https://127.0.0.1:6443/api/v1/namespaces/default/pods?limit=500>
I0526 06:31:24.695939  163632 round_trippers.go:438] Request Headers:
I0526 06:31:24.696880  163632 round_trippers.go:442]     Accept: application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json
I0526 06:31:24.697384  163632 round_trippers.go:442]     User-Agent: kubectl/v1.22.8 (linux/amd64) kubernetes/7061dbb
I0526 06:31:24.713208  163632 round_trippers.go:457] Response Status: 200 OK in 15 milliseconds
NAME                                      READY   STATUS    RESTARTS        AGE
nfs-client-provisioner-758f8cd4d6-rt2t8   1/1     Running   5 (4h25m ago)   2d1h

-v 옵션을 사용해서 Request, Response 를 자세하게 확인할 수 있다.

kubectl create 커맨드 → api-server 에 HTTP POST 요청

kubectl get, list, watch 커맨드 → api-server 에 HTTP GET 요청

kubectl update 커맨드 → api-server 에 HTTP PUT 요청

kubectl patch 커맨드 → api-server 에 HTTP PATCH 요청

kubectl delete, deletecollection 커맨드 → api-server 에 HTTP DELTE 요청

Role 예제

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

Cluster Role 예제

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # "namespace" omitted since ClusterRoles are not namespaced
  name: secret-reader
rules:
- apiGroups: [""]
  #
  # at the HTTP level, the name of the resource for accessing Secret
  # objects is "secrets"
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

RoleBinding 예제

apiVersion: rbac.authorization.k8s.io/v1
# This role binding allows "jane" to read pods in the "default" namespace.
# You need to already have a Role named "pod-reader" in that namespace.
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
# You can specify more than one "subject"
- kind: User 
  name: jane # .kube/config 에 users.user.name 에 jane 이 있어야 한다.
  apiGroup: rbac.authorization.k8s.io
roleRef:
  # "roleRef" specifies the binding to a Role / ClusterRole
  kind: Role #this must be Role or ClusterRole
  name: pod-reader # this must match the name of the Role or ClusterRole you wish to bind to
  apiGroup: rbac.authorization.k8s.io

ClusterRoleBinding 예제

apiVersion: rbac.authorization.k8s.io/v1
# This cluster role binding allows anyone in the "manager" group to read secrets in any namespace.
kind: ClusterRoleBinding
metadata:
  name: read-secrets-global
subjects:
- kind: Group
  name: manager # Name is case sensitive
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

Service Account(SA)

kubectl craete sa <SA_NAME>
$ kubectl create sa myuser1
serviceaccount/myuser1 created

$ kubectl describe sa myuser1
Name:                myuser1
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   myuser1-token-lgpsj
Tokens:              myuser1-token-lgpsj
Events:              <none>

$ kubectl get secret
NAME                                 TYPE                                  DATA   AGE
default-token-jw8gl                  kubernetes.io/service-account-token   3      2d4h
myuser1-token-lgpsj                  kubernetes.io/service-account-token   3      14s
nfs-client-provisioner-token-bgdtf   kubernetes.io/service-account-token   3      2d1h

사용자 생성을 위한 x509 인증서

Private Key 생성

openssl genrsa -out myuser.key 2048

x509 인증서 요청 생성

openssl req -new -key myuser.key -out myuser.csr -subj "/CN=myuser"

/CN=myuser 을 작성한 이유는 인증서의 Common Name 과 ~/.kube/config 의 users.name 과 똑같아야 한다. 그 때문에 /CN=myuser 를 하면 간단하게 Common Name 을 지정할 수 있다.

인증서 base64 인코딩

cat myuser.crt | base64 | tr -d "\\n"

csr.yml

apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: myuser-csr
spec:
  usages:
  - client auth
  signerName: kubernetes.io/kube-apiserver-client
  request: LS0tLS1CRUdJTiB
kubectl create -f csr.yaml
kubectl get csr

상태: Pending

kubectl certificate approve myuser-csr
kubectl get csr

상태: Apporved, Issued

kubectl get csr myuser-csr -o yaml

spec.status.certificate 확인

kubectl get csr myuser-csr -o jsonpath='{.status.certificate}' | base64 -d > myuser.crt
openssl x509 -in myuser.crt --text

Kubeconfig 사용자 생성

kubectl config set-credentials myuser --client-certificate=myuser.crt --client-key=myuser.key --embed-certs=true

Kubeconfig 컨텍스트 생성

kubectl config set-context myuser@cluster.local --cluster=cluster.local --user=myuser --namespace
=default
kubectl config get-users
kubectl config get-clusters
kubectl config get-contexts
kubectl config use-context myuser@cluster.local

ClusterRole view 권한을 myuser 사용자에게 부여

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: myuser-view-crb
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: view
subjects:
  - apiGroup: rbac.authorization.k8s.io
    kind: User
    name: myuser
kubectl create -f myuser-view-crb.yml

kubectl describe clusterrolebindings.rbac.authorization.k8s.io myuser-view-crb
kubectl config use-context myuser@cluster.local
Switched to context "myuser@cluster.local".

kubectl config get-contexts
CURRENT   NAME                             CLUSTER         AUTHINFO           NAMESPACE
          kubernetes-admin@cluster.local   cluster.local   kubernetes-admin
*         myuser@cluster.local             cluster.local   myuser             default

kubectl get pods
NAME                                      READY   STATUS    RESTARTS      AGE
nfs-client-provisioner-758f8cd4d6-rt2t8   1/1     Running   6 (23m ago)   2d19h
kubectl auth can-i get pod
yes

만약 새로운 ClusterRole 만들고 싶을 때는 아래처럼 하면 된다.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  namespace: default
  name: myuser-role
rules:
- apiGroups: ["*"] # "" indicates the core API group
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]
728x90