# 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로 인증해 쿠버네티스 사용)