# 4. ServiceAccount와 RBAC

# 보안을 위한 인증과 인가

  • 여러 명의 개발자가 쿠버네티스에 접근 가능
  • 각 개발자가 명령어를 통해 애플리케이션을 동시에 배포할 수도 있음
  • 그렇게 때문에 쿠버네티스도 보안을 고려해야 함
  • 여러 보안 기능이 있는데, RBAC 기반 Service Account라는 기능을 가장 자주 사용

# 쿠버네티스의 권한 인증 과정

  • kubectl 명령어가 실행되면 쿠버네티스 API 서버의 HTTP 핸들러에 요청 전송
  • API 서버에서는 인증 및 인가 과정 진행 (Service Account 외에도 OAuth, 인증서 등과 같은 다양한 방법 사용 가능)
  • 그 다음에는 어드미션 컨트롤러라는 별도의 단계 처리 후 요청 받은 기능 수행
    • 어드미션 컨트롤러 : 쿠버네티스 클러스터의 보안 강화 및 세부적인 정책 구현

# Service Account

  • 체계적으로 권한을 관리하기 위한 쿠버네티스 오브젝트
dgh0001@rpi4b:~$ kubectl get sa
NAME      SECRETS   AGE
default   0         72d

dgh0001@rpi4b:~$ kubectl get serviceaccount
NAME      SECRETS   AGE
default   0         72d
  • 사용자 또는 애플리케이션 하나에 해당
  • RBAC라는 기능을 통해 특정 명령을 실행할 수 있는 권한을 서비스 어카운트에 부여
  • 권한을 부여받은 서비스 어카운트는 해당 권한에 해당하는 기능만 사용할 수 있음
dgh0001@rpi4b:~$ kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.43.0.1    <none>        443/TCP   28d

dgh0001@rpi4b:~$ kubectl get svc --as system:serviceaccount:default:temp
Error from server (Forbidden): services is forbidden: User "system:serviceaccount:default:temp" cannot list resource "services" in API group "" in the namespace "default"
  • 기본적으로는 ~/.kube/config라는 파일에 설정된 인증 정보를 통해 쿠버네티스 클러스터를 제어
  • 두 번째 커맨드와 같이 --as로 임시 서비스 어카운트를 사용하여 kubectl 명령어를 실행하면 권한 오류 발생
  • 적절한 권한을 부여해야만 쿠버네티스 기능 사용 가능

# 권한 부여 방법

  • Role(네임스페이스에 속함), Cluster Role(네임스페이스에 속하지 않음)

# Role

  • 부여할 권한이 무엇인지를 나타내는 쿠버네티스 오브젝트
    • 디플로이먼트를 생성 가능하다, 서비스 목록을 조회한다 등
  • kubectl get role
  • service-reader-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: service-reader
rules:
  - apiGroups: [""] # 대상이 될 오브젝트의 API 그룹
    resources: ["services"] # 대상이 될 오브젝트의 이름
    verbs: ["get", "list"] # 어떠한 동작을 허용할 것인지 명시

# apiGroups

  • 쿠버네티스의 오브젝트가 가지는 목적에 따라 분류되는 일종의 카테고리
  • kubectl api-resources로 확인 가능 (APIVERSION 칼럼의 [APIGROUP]/[VERSION])
dgh0001@rpi4b:~$ kubectl api-resources
NAME                                SHORTNAMES   APIVERSION                          NAMESPACED   KIND
pods                                po           v1                                  true         Pod
services                            svc          v1                                  true         Service
deployments                         deploy       apps/v1                             true         Deployment
  • 현재 서비스는 코어 API 그룹에 속하기 때문에 apiGroup이 없음

# resources

  • 어떤 쿠버네티스 오브젝트에 대해 권한을 정의할 것인지

# verbs

  • 이 롤을 부여받은 대상이 resources에 지정된 오브젝트들에 대해 어떤 동작을 수행할 수 있는지 정의

# RoleBinding

  • 이렇게 만들어진 롤을 특정 대상에게 부여하려면 Role Binding이라는 오브젝트를 통해 특정 대상과 롤을 연결해야 함
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: service-reader-rolebinding
  namespace: default
subjects:
  - kind: ServiceAccount # 권한을 부여할 대상이 ServiceAccount임
    name: temp # temp라는 이름을 가진 서비스 어카운트에 권한 부여
    namespace: default
roleRef:
  kind: Role # Role에 정의된 권한 부여
  name: service-reader # service-reader라는 이름의 Role을 대상에 연결
  apiGroup: rbac.authorization.k8s.io
  • 롤 바인딩 적용 후
dgh0001@rpi4b:~$ kubectl apply -f rolebinding-service-reader.yaml
rolebinding.rbac.authorization.k8s.io/service-reader-rolebinding created

dgh0001@rpi4b:~$ kubectl get svc --as system:serviceaccount:default:temp
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.43.0.1    <none>        443/TCP   28d
  • 서비스 목록을 조회하는 권한을 부여받았기 때문에 정상적으로 명령어 사용 가능

# Cluster Role

  • 클러스터 단위의 권한을 정의할 때 사용
  • 여러 네임스페이스에서 사용되는 권한을 클러스터 롤로 만들어 쓸 수 있음
  • kubectl get clusterrole
  • 롤을 사용할 때 처럼 클러스터 롤도 클러스터 롤 바인딩이라는 쿠버네티스 오브젝트를 사용해야 함
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  namespace: default
  name: nodes-reader
rules:
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: nodes-reader-clusterrolebinding
  namespace: default
subjects:
  - kind: ServiceAccount
    name: temp
    namespace: default
roleRef:
  kind: ClusterRole
  name: nodes-reader
  apiGroup: rbac.authorization.k8s.io
  • 클러스터 롤 생성 및 바인딩 후
dgh0001@rpi4b:~$ kubectl apply -f nodes-reader-clusterrole.yaml
clusterrole.rbac.authorization.k8s.io/nodes-reader created

dgh0001@rpi4b:~$ kubectl apply -f clusterrolebinding-nodes-reader.yaml
clusterrolebinding.rbac.authorization.k8s.io/nodes-reader-clusterrolebinding created

dgh0001@rpi4b:~$ kubectl get nodes --as system:serviceaccount:default:temp
NAME    STATUS   ROLES                  AGE   VERSION
rpi4b   Ready    control-plane,master   72d   v1.33.4+k3s1
  • 정상적으로 실행 가능

# 쿠버네티스 API 서버 접근

  • 쿠버네티스 API 서버도 HTTP 요청을 통해 쿠버네티스 기능 사용 가능
dgh0001@rpi4b:~$ curl https://localhost:6443/apis -k
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "Unauthorized",
  "reason": "Unauthorized",
  "code": 401
}
  • 하지만 일반적인 방식으로는 권한 부족으로 접근 불가능
  • 별도의 인증 정보를 HTTP 페이로드에 포함시켜야 함
dgh0001@rpi4b:~$ kubectl create token temp
...

dgh0001@rpi4b:~$ curl https://localhost:6443/apis --header "Authorization: Bearer ..." -k
{
  "kind": "APIGroupList",
  "apiVersion": "v1",
  "groups": [
    {

# 클러스터 내부에서 쿠버네티스 서비스를 통해 API 서버에 접근

  • 쿠버네티스에 기본적으로 존재하고 있는 kubernetes라는 이름의 서비스를 통해 API 사용

# 쿠버네티스 SDK를 이용해 포드 내부에서 API 서버에 접근

  • 포드 내부에서 실행되는 어플리케이션의 경우 특정 언어로 바인딩 된 쿠버네티스 SDK 방식으로도 API 서버에 접근 가능
try:
    kubernetes.config.load_kube_config()
except kubernetes.config.config_exception.ConfigException:
    logging.warning("Failed to load kubeconfig.")
    exit(1)

api_client = kubernetes.client.CoreV1Api()

# kubeconfig 파일에 서비스 어카운트 인증 정보 설정

  • kubectl 명령어를 통해 쿠버네티스 클러스터를 제어할 때는 kubeconfig라는 파일을 통해 인증 진행
  • 크게 clusters, users, contexts로 이루어져 있음
    • clusters : 쿠버네티스 API 서버의 접속 정보 목록
    • users : 쿠버네티스 API 서버에 접속하기 위한 사용자 인증 정보 목록
    • contexts: cluster와 users를 조합해 컨텍스트 정의 (ex. cluster A에 user a로 인증해 쿠버네티스 사용)