無知

갈 길이 먼 공부 일기

기술 공부/쿠버네티스

쿠버네티스 (12) | API 서버 보안

moozii 2022. 3. 20. 15:36
앞으로의 스터디 내용은 <Kubernetes in Action>을 기반으로 진행합니다.
자세한 내용은, 해당 책을 확인해주세요! 
http://www.yes24.com/Product/Goods/89607047 

 

인증 개념 정리

API 서버는 인증 - 인가 단계를 거치는 과정에서 인증 플러그인이 구성 상 포함됨을 이야기한 바 있다.
아래의 순서 및 과정으로 인증 작업이 진행됨을 참고하자. 

  1. API 서버가 요청을 받음
  2. 인증 플러그인이 요청인 정보를 추출해 검사
    1. 요청인 정보, 클라이언트 아이덴티티란 사용자 이름, 사용자 ID, 클라이언트 소속 그룹을 의미.
    2. 클라이언트 아이덴티티 습득 방법은 : 클라이언트 인증서 / HTTP 헤더를 통해 전달된 인증 토큰 / 기본 HTTP 인증
  3. 인증 플러그인이 API 서버 코어에 반환 -> 사용자가 작업 수행 권한이 있는지 확인
  4. API 서버의 인증 플러그인 호출 중지
  5. 인가 단계 진행

 

 

사용자와 그룹

쿠버네티스 API 서버에 접속하는 클라이언트는 2종류로 모두 인증 플러그인으로 인증.

실제 사용자이든, 서비스어카운트이든, 각 계정은 하나 이상의 그룹에 소속된다.

 

  • 사용자 (클라이언트)
    • 실제 사용자 (사람) : SSO(싱글사인온) 등 외부 시스템으로 인증 관리
      • 외부에 의해 관리되고, 사용자 계정 자원이 쿠버네티스에 없으므로 API 서버를 통한 사용자 생성, 업데이트, 삭제 불가
    • 파드, 파드 내부 애플리케이션 : 서비스 어카운트 메커니즘 사용한 인증
      • 쿠버네티스의 서비스 어카운트 리소스를 클러스터에 생성해 계정 정보 생성, 삭제, 변경 가능
  • 그룹
    • 목적 : 한번에 여러 사용자에게 권한을 부여하는 데에 사용
    • 의미 : 
      • 인증 플러그인이 반환하는 그룹 이름 = 임의의 문자열
      • 내장된 그룹의 의미
        • system:unauthenticated | 어떤 인증 플러그인에서도 인증할 수 없는 요청의 그룹
        • system: authenticated | 성공적으로 인증된 사용자 전체가 할당된 그룹
        • system:serviceaccounts | 시스템 내 모든 서비스 어카운트의 그룹
        • system:serviceaccounts:<namespace> | 특정 네임스페이스 내 모든 서비스 어카운트의 그룹

 

 

서비스 어카운트

  • 모든 네임스페이스 내 디폴트 서비스 어카운트가 있지만 파드별로 따로 생성해주는 이유
    • 클러스터 보안 때문. 파드가 수행해야 하는 작업에 맞게 해당 권한만 보유한 서비스 어카운트를 활용.
      파드는 클러스터 내 리소스를 검색/수정하지 못하는 계정으로 실행해야. 리소스의 메타데이터를 검색하는 파드는 해당 오브젝트의 메타데이터만 조회 가능한 서비스 어카운트로 실행. 오브젝트 수정해야 하는 파드는 API 오브젝트 수정 가능한 고유 서비스 어카운트로 실행. 
  • 생성 방법
    • kubectl create serviceaccount <service_account_name> 으로 생성
    • kubectl describe sa <service_account_name> 으로 생성 결과 확인
$ kubectl create serviceaccount foo
serviceaccount/foo created

$ kubectl describe sa foo
Name:                foo
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none> 	// 서비스 어카운트 사용 파드에 자동으로 해당 필드값 추가
Mountable secrets:   foo-token-h6g68 	// 마운트 가능한 시크릿이 강제된 경우 이 어카운트를 사용하는 파드만 해당 시크릿 마운트 가능
Tokens:              foo-token-h6g68 	// 인증 토큰. 컨테이너에 마운트됨.
Events:              <none>

 

  • 서비스 어카운트의 시크릿 항목들
    • 마운트 가능한 시크릿
      • 7장 복습 : 파드는 원하는 시크릿을 마운트할 수 있다
      • 12장 : 서비스 어카운트의 마운트 가능한 시크릿 목록에 있는 시크릿만 마운트하도록 파드의 서비스어카운트를 설정할 수 있다. kubernetes.io/enforce-mountable-secrets="true " 라는 어노테이션을 포함해야 한다.
    • 이미지 풀 시크릿
      • 프라이빗 이미지 레포에서 컨테이너 이미지를 가져오는 데 필요한 자격증명을 보유한 시크릿
      • 서비스 어카운트를 사용해 모든 파드에 특정 이미지 풀 시크릿을 자동으로 추가 (서비스 어카운트에 추가하면 자동으로 각 파드에 추가되어 개별 작업을 할 필요 없음)
  • 파드에 서비스 어카운트 할당
    • 파드 정의 내 spec.service.AccountName 필드에서 이름을 설정
    • 파드를 생성할 때 서비스어카운트를 설정해야 한다. 추후 변경 불가능.

 

$ cat curl-custom-sa.yaml
apiVersion: v1
kind: Pod
metadata:
  name: curl-custom-sa
spec:
  serviceAccountName: foo
  containers:
  - name: main
    image: tutum/curl
    command: ["sleep", "9999999"]
  - name: ambassador
    image: luksa/kubectl-proxy:1.6.2
    
$ kubectl create -f curl-custom-sa.yaml
pod/curl-custom-sa created


$ kubectl exec -it curl-custom-sa -c main -- cat /var/run/secrets/kubernetes.io/serviceaccount/token
error: unable to upgrade connection: container not found ("main")

$ kubectl get po
NAME             READY   STATUS             RESTARTS   AGE
curl-custom-sa   1/2     ImagePullBackOff   0          86s
kubia-0          1/1     Running            1          7d15h
kubia-1          1/1     Running            1          7d16h
kubia-2          1/1     Running            1          7d16h

$ kubectl describe po curl-custom-sa
(중략)
Events:
  Type     Reason     Age                 From               Message
  ----     ------     ----                ----               -------
(중략)
  Warning  Failed     25s (x5 over 97s)   kubelet            Error: ImagePullBackOff
  Normal   Pulling    10s (x4 over 101s)  kubelet            Pulling image "tutum/curl"
  Warning  Failed     7s (x4 over 98s)    kubelet            Error: ErrImagePull
  Warning  Failed     7s (x4 over 98s)    kubelet            Failed to pull image "tutum/curl": rpc error: code = Unknown desc = Error response from daemon: pull access denied for tutum/curl, repository does not exist or may require 'docker login': denied: requested access to the resource i

$ vim curl-custom-sa.yaml
$ cat curl-custom-sa.yaml
apiVersion: v1
kind: Pod
metadata:
  name: curl-custom-sa
spec:
  serviceAccountName: foo
  containers:
  - name: main
    image: curlimages/curl 	// tutum/curl 이미지에서 변경
    command: ["sleep", "9999999"]
  - name: ambassador
    image: luksa/kubectl-proxy:1.6.2
  
$ kubectl delete po curl-custom-sa
pod "curl-custom-sa" deleted
$ kubectl create -f curl-custom-sa.yaml
pod/curl-custom-sa created

$ kubectl exec -it curl-custom-sa -c main -- cat /var/run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciOiJSUzI1NiIsImtpZCI6Il9nMFVJUjlpMWJBYk9fOGt1dG5PYmZLUEFMaGRnUEo0eFZ0VTBpYlZrbW8ifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjc5MDEzMDM5LCJpYXQiOjE2NDc0NzcwMzksImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJjdXJsLWN1c3RvbS1zYSIsInVpZCI6ImQ3MWRjM2UxLTM4NTMtNDlmMy05N2U1LTc0MTFmMGFiMzg1MSJ9LCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoiZm9vIiwidWlkIjoiYmYzODNmNzQtNDBkNi00YmMwLTliMDYtNzJjODhkMTYzYTc0In0sIndhcm5hZnRlciI6MTY0NzQ4MDY0Nn0sIm5iZiI6MTY0NzQ3NzAzOSwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6Zm9vIn0.c3RkExZR27sumwlulR6tezeYnaxEh34mko3GY5nN2r07JgszvUDW1ciaEwPeeDQ3pjaOsnUWkoc91T6pI6LKSwI-D4RIvUapKGYX_lb47Pl85hB8wviDa6A4aglkbFNbYGU6OwDTH2ri9CfzST_spXb8cTk0Pd6RR29vnjGrMKV6NwORb7V_H0VC1MmykfCRNulypARksT8EOCk5wx5jXqg-7PMl3m7BNZhaCqiFDy4bZWVhxa9DXKn6bNMK241LxTdfL3m0Xbq4Rr_PbmWQRN9G1sy4wASpfKX-u_MEbyQ_flHyPX-VHwy3_U_1lD_akcSKnYiFarUd2HT4XDBMjQ%

 

  • API 서버와 통신하기 위한 서비스어카운트 토큰 활용
    • 앰배서더 컨테이너가 서버와 통신 시 토큰을 사용하므로 이를 활용해 실습을 진행
$ kubectl exec -it curl-custom-sa -c main -- curl localhost:8001/api/v1/pods

 

 

RBAC을 통한 클러스터 보안

  • RBAC, 역할 기반 액세스 제어를 통해, 권한이 없는 사용자가 클러스터 상태를 조회/수정하지 못하도록 한다

 

RBAC 인가 플러그인

  • 인가 플러그인을 통해 액션 요청자의 액션 수행 가능 여부를 점검한다
    • API 서버가 REST 인터페이스를 통해 사용자의 HTTP 요청을 받아 액션을 수행하도록 한다
    • 사용자는 요청에 자격증명 내용 (인증 토큰, 사용자명, 암호 혹은 클라이언트 인증서) 을 포함시켜 인증한다
  • 액션의 종류
    • Get, 파드 가져오기 (=HTTP Method GET, HEAD)
    • Create, 서비스 생성 (=HTTP Method POST)
    • Update, 시크릿 업데이트 (=HTTP Method PUT)
    • Patch (=HTTP Method Patch)
    • Delete (=HTTP Method DELETE)
  • RBAC 규칙 용도
    • 전체 리소스 유형에 보안 권한을 적용
    • 특정 리소스 인스턴스에 보안 권한을 적용
    • 리소스가 아닌 URL 경로에 보안 권한을 적용
  • RBAC 플러그인 메커니즘
    • 사용자 롤, User Role
      • 인가 플러그인의 인가 여부를 결정하는 핵심 요소
      • 주체(사람, 서비스 어카운트, 그룹)는 하나 이상의 롤과 연계되어 있다
      • 각 롤은 특정 리소스에 특정 액션(동사)을 수행할 수 있다

 

RBAC 리소스

  • RBAC 인가 규칙은 2개의 그룹, 4개의 리소스로 구성된다
    • 롤과 클러스터롤 (Role & ClusterRole) :
      리소스에 수행할 수 있는 동사를 지정
    • 롤바인딩과 클러스터롤바인딩 (RoleBinding & ClusterRoleBinding) :
      롤을 특정 사용자, 그룹, 서비스 어카운트 등 액션 주체에 바인딩
  수행할 수 있는 작업, 동사를 정의 누가 수행하는지 주체를 정의
네임스페이스가 지정된 리소스 롤바인딩
네임스페이스가 지정되지 않는 클러스터 수준의 리소스 클러스터롤 클러스터롤바인딩

 

  •  특징
    • 하나의 네임스페이스에 여러 롤, 롤바인딩 존재 가능
    • 클러스터롤, 클러스터롤바인딩도 복수로 존재 가능
    • 롤바인딩이 네임스페이스가 지정되어도, 클러스터롤도 참조 가능

https://livebook.manning.com/concept/kubernetes/clusterroles

 

$ kubectl delete clusterrolebinding permissive-binding
clusterrolebinding.rbac.authorization.k8s.io "permissive-binding" deleted

$ kubectl create ns foo
namespace/foo created

$ kubectl run test --image=luksa/kubectl-proxy -n foo
pod/test created

$ kubectl create ns bar
namespace/bar created

$ kubectl run test --image=luksa/kubectl-proxy -n bar
pod/test created

$ kubectl get po -n foo
NAME   READY   STATUS    RESTARTS   AGE
test   1/1     Running   0          77s

$ kubectl exec -it test -n foo -- sh
/ # curl localhost:8001/api/v1/namespaces/foo/services
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "services is forbidden: User \"system:serviceaccount:foo:default\" cannot list resource \"services\" in API group \"\" in the namespace \"foo\"",
  "reason": "Forbidden",
  "details": {
    "kind": "services"
  },
  "code": 403
 $ kubectl exec -it test -n bar -- sh
$ cat service-reader.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: foo 	// 롤에 네임스페이스를 지정 (생략 시 현재 네임스페이스)
  name: service-reader
rules:
- apiGroups: [""] 	// 서비스는 이름 없는 core apiGroup 리소스이므로 ""
  verbs: ["get", "list"]
  resources: ["services"] // 리소스 지정 시 복수형을 사용해야 함

$ kubectl create -f service-reader.yaml -n foo
role.rbac.authorization.k8s.io/service-reader created

$ kubectl create rolebinding test --role=service-reader --serviceaccount=foo:default -n foo
rolebinding.rbac.authorization.k8s.io/test created

**role을 생성하는 방법은 위의 yaml 파일 사용 외에도 kubectl create role <service-name> --verb=<verb_name> --resource=<resource_name_in_plural> -n <namespace_name>과 같이 명령어를 이용하는 방법이 있다.

**서비스 어카운트 대신 사용자에게 롤을 바인딩하려면 --user 인수로 사용자 이름을 지정하자.

**서비스 어카운트 대신 그룹에 롤을 바인딩하려면 --group 인수를 사용하자.

 

$ kubectl get rolebinding test -n foo -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  creationTimestamp: "2022-03-17T04:41:11Z"
  name: test
  namespace: foo
  resourceVersion: "249977"
  uid: 8eb6ace7-0201-4d51-a7b7-fdf0d2ca6bbc
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: service-reader
subjects:
- kind: ServiceAccount
  name: default
  namespace: foo
$ kubectl exec -it test -n foo -- sh
/ # curl localhost:8001/api/v1/namespaces/foo/services
{
  "kind": "ServiceList",
  "apiVersion": "v1",
  "metadata": {
    "resourceVersion": "250253"
  },
  "items": []
}

**롤바인딩을 편집해, 다른 네임스페이스에서도 다른 파드의 서비스 어카운트를 추가해서 액션을 수행할 수 있게 할 수 있다. (명령어 : kubectl edit rolebinding <role_binding_name> -n <namespace_name> )

 

  • 클러스터 수준의 RBAC 리소스의 필요성 (클러스터롤, 클러스터롤바인딩) 
    • 롤은 롤이 위치한 동일 네임스페이스에만 접근 가능. 다른 네임스페이스 리소스에 접근 가능하게 하기 위해서는 해당 네임스페이스마다 롤, 롤바인딩을 생성. 즉, 모든 네임스페이스로 확장하려면 각각 롤, 롤바인딩을 모두 생성해주어야 함.
    • 네임스페이스를 지정하지 않는 리소스인, 노드, 퍼시스턴트볼륨, 네임스페이스 등은 일반적인 롤로 권한 부여가 불가능

 

$ kubectl create clusterrole pv-reader --verb=get,list --resource=persistentvolumes
clusterrole.rbac.authorization.k8s.io/pv-reader created

$ kubectl get clusterrole pv-reader -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  creationTimestamp: "2022-03-17T05:05:39Z"
  name: pv-reader
  resourceVersion: "251205"
  uid: 1eb5de54-7748-432b-ae96-dff66ab7e534
rules:
- apiGroups:
  - ""
  resources:
  - persistentvolumes
  verbs:
  - get
  - list
$ kubectl exec -it test -n foo -- sh
/ # curl localhost:8001/api/v1/persistentvolumes
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "persistentvolumes is forbidden: User \"system:serviceaccount:foo:default\" cannot list resource \"persistentvolumes\" in API group \"\" at the cluster scope",
  "reason": "Forbidden",
  "details": {
    "kind": "persistentvolumes"
  },
  "code": 403
}/ # exit

$ kubectl create rolebinding pv-test --clusterrole=pv-reader --serviceaccount=foo:default -n foo
rolebinding.rbac.authorization.k8s.io/pv-test created

$ kubectl exec -it test -n foo -- sh
/ # curl localhost:8001/api/v1/persistentvolumes
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "persistentvolumes is forbidden: User \"system:serviceaccount:foo:default\" cannot list resource \"persistentvolumes\" in API group \"\" at the cluster scope",
  "reason": "Forbidden",
  "details": {
    "kind": "persistentvolumes"
  },
  "code": 403
}/ # exit

$ kubectl get rolebindings pv-test -o yaml
Error from server (NotFound): rolebindings.rbac.authorization.k8s.io "pv-test" not found
$ kubectl get rolebindings pv-test -n foo -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  creationTimestamp: "2022-03-17T05:07:24Z"
  name: pv-test
  namespace: foo
  resourceVersion: "251293"
  uid: 167748e6-98f8-4117-a10d-74fab2c2f841
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: pv-reader
subjects:
- kind: ServiceAccount
  name: default
  namespace: foo


$ kubectl delete rolebinding pv-test
Error from server (NotFound): rolebindings.rbac.authorization.k8s.io "pv-test" not found
$ kubectl delete rolebinding -n foo pv-test
rolebinding.rbac.authorization.k8s.io "pv-test" deleted

$ kubectl create clusterrolebinding pv-test --clusterrole=pv-reader --serviceaccount=foo:default
clusterrolebinding.rbac.authorization.k8s.io/pv-test created

$ kubectl exec -it test -n foo -- sh
/ # curl localhost:8001/api/v1/persistentvolumes
{
  "kind": "PersistentVolumeList",
  "apiVersion": "v1",
  (후략)

**클러스터 단위의 리소스인 퍼시스턴트볼륨을 조회하는 클러스터롤을 생성 후, 롤바인딩을 시도했으나, 클러스터롤바인딩이 아닌 롤바인딩 리소스로는 클러스터 수준 액세스 권한을 부여할 수 없어 여전히 오류가 발생함을 확인하였고, 클러스터롤바인딩까지 무사히 생성한 뒤에는 원활히 접근됨을 확인할 수 있다. 즉, 롤바인딩은 클러스터롤을 참조해도 클러스터롤바인딩을 대체할 수 없다.

 

 

리소스가 아닌 URL에 액세스 허용하기

  • API 서버는 리소스 외에 URL로도 노출됨. URL 액세스 권한도 명시적으로 부여해야 클라이언트 요청을 받을 수 있다. 
  • URL 권한의 명시적 부여는 일반적으로 system:discovery 클러스터롤과 클러스터롤바인딩을 통해 자동 수행된다.
$ kubectl get clusterrole system:discovery -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: "2022-01-25T08:15:15Z"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:discovery
  resourceVersion: "86"
  uid: 2da59d58-cfc6-4c66-961e-33445f9af0a3
rules:
- nonResourceURLs:
  - /api
  - /api/*
  - /apis
  - /apis/*
  - /healthz
  - /livez
  - /openapi
  - /openapi/*
  - /readyz
  - /version
  - /version/
  verbs:
  - get

**상기 클러스터롤이 리소스 대신 URL을 참조.

**URL의 경우 액션 동사가 create, update 대신 post, put, patch가 활용됨. (소문자)

 

$ kubectl get clusterrolebinding system:discovery -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: "2022-01-25T08:15:15Z"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:discovery
  resourceVersion: "151"
  uid: 752e4706-6643-462d-91fe-44a0a6c07c7d
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:discovery
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:authenticated

** 책의 예시에는 해당 클러스터롤바인딩이 인증 사용자와 미인증 사용자 모두를 바인드하지만, 실제 실습의 경우 인증사용자만을 바인드하는 것으로 보인다. 그래서 아래의 실습의 경우에도, 원래대로라면 미인증 사용자로서의 접근을 허용해서 아래 요청도 성공적이어야 하지만, 이 경우에는 미인증 사용자 접근 권한이 막혀있으므로 요청이 거절되었다. 아래 표를 통해 더 자세히 오류 원인을 확인할 수 있다.

 

Default ClusterRole Default ClusterRoleBinding Description
system:basic-user system:authenticated group Allows a user read-only access to basic information about themselves. Prior to v1.14, this role was also bound to system:unauthenticated by default.
system:discovery system:authenticated group Allows read-only access to API discovery endpoints needed to discover and negotiate an API level. Prior to v1.14, this role was also bound to system:unauthenticated by default.
system:public-info-viewer system:authenticated and 
system:unauthenticated groups
Allows read-only access to non-sensitive information about the cluster. Introduced in Kubernetes v1.14.

https://kubernetes.io/docs/reference/access-authn-authz/rbac/

 

 

$ curl https://192.168.59.100:8443/api -k
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "forbidden: User \"system:anonymous\" cannot get path \"/api\"",
  "reason": "Forbidden",
  "details": {},
  "code": 403
}%

 

특정 네임스페이스 리소스에 액세스 권한을 부여하는 데에 클러스터롤 사용하는 방법도 알아보자.

클러스터롤- 일반롤바인딩 연결을 진행해본다.

그 예시로는 아래의 클러스터롤이 존재한다.

 

$ kubectl get clusterrole view -o yaml
aggregationRule:
  clusterRoleSelectors:
  - matchLabels:
      rbac.authorization.k8s.io/aggregate-to-view: "true"
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: "2022-01-25T08:15:15Z"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
    rbac.authorization.k8s.io/aggregate-to-edit: "true"
  name: view
  resourceVersion: "384"
  uid: 27c0961d-1d06-4452-a476-c2200ed3a91d
rules:
- apiGroups:
  - ""
  resources:
  - configmaps
  - endpoints
  - persistentvolumeclaims
  - persistentvolumeclaims/status
  - pods
  - replicationcontrollers
  - replicationcontrollers/scale
  - serviceaccounts
  - services
  - services/status
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - bindings
  - events
  - limitranges
  - namespaces/status
  - pods/log
  - pods/status
  - replicationcontrollers/status
  - resourcequotas
  - resourcequotas/status
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - namespaces
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - discovery.k8s.io
  resources:
  - endpointslices
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - apps
  resources:
  - controllerrevisions
  - daemonsets
  - daemonsets/status
  - deployments
  - deployments/scale
  - deployments/status
  - replicasets
  - replicasets/scale
  - replicasets/status
  - statefulsets
  - statefulsets/scale
  - statefulsets/status
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - autoscaling
  resources:
  - horizontalpodautoscalers
  - horizontalpodautoscalers/status
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - batch
  resources:
  - cronjobs
  - cronjobs/status
  - jobs
  - jobs/status
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - extensions
  resources:
  - daemonsets
  - daemonsets/status
  - deployments
  - deployments/scale
  - deployments/status
  - ingresses
  - ingresses/status
  - networkpolicies
  - replicasets
  - replicasets/scale
  - replicasets/status
  - replicationcontrollers/scale
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - policy
  resources:
  - poddisruptionbudgets
  - poddisruptionbudgets/status
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - networking.k8s.io
  resources:
  - ingresses
  - ingresses/status
  - networkpolicies
  verbs:
  - get
  - list
  - watch

 

  • 클러스터롤바인딩 생성 + 클러스터롤 참조 = 바인딩 주체가 모든 네임스페이스 내 지정 리소스 확인 가능
  • 롤바인딩 생성 + 클러스터롤 참조 = 바인딩 주체가 롤바인딩 네임스페이스 내 리소스만 확인 가능

 

 

롤, 클러스터롤, 롤바인딩, 클러스터롤바인딩의 조합

접근 롤 타입 사용할 바인딩 타입
클러스터 수준 리소스 (노드, 퍼시스턴트볼륨 등) 클러스터롤 클러스터롤바인딩
리소스가 아닌 URL 클러스터롤 클러스터롤바인딩
모든 네임스페이스의 네임스페이스로 지정된 리소스 클러스터롤 클러스터롤바인딩
특정 네임스페이스의 네임스페이스로 지정된 리소스
(여러 네임스페이스에 동일한 클러스터롤 재사용)
클러스터롤 롤바인딩
특정 네임스페이스의 네임스페이스로 지정된 리소스
(각 네임스페이스에 별도 롤을 정의)
롤바인딩

 

 

디폴트 클러스터롤과 클러스터롤바인딩

  • 쿠버네티스는 API 서버 시작 시 업데이트되는 클러스터롤, 클러스터롤바인딩의 디폴트 세트 제공
  • 확인방법 : kubectl get clusterroles OR kubectl get clusterrolebindings
  • 디폴트 클러스터롤의 종류
    • view 클러스터롤을 사용해 리소스에 읽기 전용 액세스 허용
      • 롤, 롤바인딩, 시크릿 제외 거의 모든 리소스를 네임스페이스 내에서 읽을 수 있음
    • edit 클러스터롤을 사용해 리소스에 변경 허용
      • 네임스페이스 내 리소스 + 시크릿까지 수정 가능. 
      • 롤, 롤바인딩의 경우 조회 및 수정 불허 (권한 상승 방지)
    • admin 클러스터롤을 사용해 네임스페이스 제어 권한 허용
      • 클러스터롤 주체에 리소스쿼터, 네임스페이스 리소스 제외 모든 리소스의 조회 및 수정 허용
      • edit과 달리 롤, 롤바인딩도 조회 및 수정 대상임이 차이
    • cluster-admin 클러스터롤을 사용해 완전 제어 허용
      • 롤바인딩이 생성된 네임스페이스의 모든 측면을 완전 제어
    • 그외 system: 이라는 접두사로 시작하는 클러스터롤
      • system:kube-scheduler ) 스케줄러에서 사용. 해당 롤은 동일 이름의 롤바인딩으로 사용자에게 할당되어 인증됨. 
      • system:node ) kubelet에서 사용하는 롤
      • system:controller ) 컨트롤러매니저가 사용하는 롤

 

 

인가 권한 부여 가이드

  • 네임스페이스의 디폴트 서비스 어카운트에는 미인증 사용자의 권한 외 없어 사용자가 전적으로 권한 부여해야.
  • 최소 권한의 원칙 : 모든 사람에게 꼭 필요한 권한만 부여하고, 한 가지 초과의 권한을 부여하지 않아야 한다.
  • 각 파드를 위한 특정 서비스 어카운트를 생성한 후 롤바인딩으로 맞춤 롤과 연계하자
    • 클러스터롤바인딩 사용시 타 네임스페이스 리소스가 접근 가능하므로 사용 지양
  • 애플리케이션이 탈취될 가능성을 염두에 두고 서비스어카운트를 제한해야

 

 

 

실전 지식

  • 쿠버네티스의 사용자 관리란?
    • 쿠버네티스에는 사실 사용자, 유저라는 개념이 따로 정해지지 않았다. 어떤 인증방법으로 인증을 통과할지, 어떤 권한을 받아 리소스에 접근할 지 정도의 차이가 명세된 것이 전부이다. 유저 기준이 명확히 정해진 바가 없다
    • 유저는 리소스로 등록되지 않고, 설정 파일 내의 라벨링이다. 
    • 쿠버네티스 외부의 인증서비스 상의 사용자 개념을 연결지어 사용할 수 있다
  • 실전 서비스 상의 인증 과정
    • 키클락과 같은 외부 인증 서비스로부터 사용자가 토큰을 받아온다
      • 해당 토큰 내에는 해당 외부 인증 서비스 내에 선언된 유저에 대한 그룹 정보를 포함한다
    • 받은 토큰을 기반으로 API 요청을 보낸다
    • 쿠버네티스는 토큰을 받고 인증을 판단한다
  • 실전 서비스 상의 인가 과정
    • EKS의 경우, 토큰으로 인증이 통과되면, 기존 정의된 클러스터롤을 확인한다
      • 롤에 대한 확인은, 먼저 앞선 인증 토큰에 포함된 그룹 정보를 확인한다
      • 토큰 내 그룹 정보를 기반으로 정해진 롤을 롤바인딩한다 
      • 예를 들어 다음과 같은 롤을 개발 및 상용환경에 생성해둘 수 있다
        • 리드온리 롤 : 기본 파드나 서비스의 리스트 권한만 보유
        • 데브옵스 롤 : 생성, 삭제, 업데이트, 패치 권한 등 보유
        • 어드민 롤 : 전체 권한 보유
    • 인증된 유저는 다음 롤들에 따라 권한이 부여되고 리소스 접근이 제한된다
  • 참고자료 : https://velog.io/@nigasa12/kubectl-sso-%EC%84%A4%EC%A0%95-%EC%82%BD%EC%A7%88-%EC%9D%BC%EA%B8%B0

 

 

 

 

참고 문헌

https://kubernetes.io/docs/reference/access-authn-authz/rbac/

https://livebook.manning.com/concept/kubernetes/clusterroles