[Daily morning study] Kubernetes RBAC와 Service Account 보안 설정

#daily morning study

Image


Kubernetes RBAC와 Service Account 보안 설정

RBAC이란?

RBAC(Role-Based Access Control)은 역할(Role) 기반으로 리소스에 대한 접근 권한을 관리하는 메커니즘이다. Kubernetes에서는 1.8버전부터 안정적으로 지원되며, 현재는 클러스터 보안 설정에서 가장 핵심적인 요소다.

기본 개념은 간단하다.

  • 누가(Subject) — User, Group, Service Account
  • 무엇을(Resource) — Pod, Deployment, Secret, ConfigMap 등
  • 어떻게(Verb) — get, list, watch, create, update, patch, delete

이 세 가지를 조합해서 권한을 정의한다.


핵심 오브젝트 4가지

Kubernetes RBAC는 4가지 오브젝트로 구성된다.

오브젝트범위설명
Role네임스페이스특정 네임스페이스 내의 리소스에 대한 권한 정의
ClusterRole클러스터 전체모든 네임스페이스 또는 비네임스페이스 리소스(노드 등)에 대한 권한 정의
RoleBinding네임스페이스Role 또는 ClusterRole을 특정 주체에 바인딩
ClusterRoleBinding클러스터 전체ClusterRole을 클러스터 전체 범위로 특정 주체에 바인딩

Role과 ClusterRole 작성법

Role 예시 — 특정 네임스페이스 내에서 Pod를 읽을 수 있는 권한:

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

ClusterRole 예시 — 클러스터 전체에서 Node 정보를 읽을 수 있는 권한:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: node-reader
rules:
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get", "list", "watch"]

apiGroups는 Kubernetes API 그룹을 의미한다. "" 는 core 그룹(Pod, Service, ConfigMap 등), apps는 Deployment, StatefulSet 등, batch는 Job, CronJob 등을 나타낸다.


RoleBinding과 ClusterRoleBinding

Role을 정의했다면 주체(Subject)에 바인딩해야 실제로 권한이 적용된다.

RoleBinding 예시 — dev 네임스페이스에서 jane이라는 사용자에게 pod-reader 권한 부여:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: dev
subjects:
- kind: User
  name: jane
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

ClusterRole을 특정 네임스페이스에서만 적용하기:

ClusterRole은 ClusterRoleBinding 없이도 RoleBinding을 통해 특정 네임스페이스에만 적용할 수 있다.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-secrets
  namespace: staging
subjects:
- kind: User
  name: bob
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole   # ClusterRole을 참조하지만 RoleBinding이므로 staging 네임스페이스에만 적용
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

Service Account란?

Service Account는 파드(Pod) 내의 프로세스가 Kubernetes API 서버와 통신할 때 사용하는 ID다. 사람이 사용하는 User Account와 달리 애플리케이션/프로세스를 위한 계정이다.

각 네임스페이스에는 기본 Service Account (default)가 자동으로 생성되며, 파드를 생성할 때 명시적으로 지정하지 않으면 이 default Service Account가 자동으로 마운트된다.

# 현재 네임스페이스의 Service Account 목록 확인
kubectl get serviceaccounts

# Service Account 생성
kubectl create serviceaccount my-app-sa -n production

Service Account에 RBAC 적용하기

애플리케이션에 필요한 최소 권한만 부여하는 것이 보안의 핵심이다 (최소 권한 원칙, Principle of Least Privilege).

예시 — ConfigMap을 읽는 파드를 위한 Service Account 설정:

  1. Service Account 생성
apiVersion: v1
kind: ServiceAccount
metadata:
  name: config-reader-sa
  namespace: production
  1. 필요한 권한을 Role로 정의
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production
  name: configmap-reader
rules:
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["get", "list"]
  1. RoleBinding으로 Service Account에 Role 연결
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: config-reader-binding
  namespace: production
subjects:
- kind: ServiceAccount
  name: config-reader-sa
  namespace: production
roleRef:
  kind: Role
  name: configmap-reader
  apiGroup: rbac.authorization.k8s.io
  1. 파드에 Service Account 지정
apiVersion: v1
kind: Pod
metadata:
  name: my-app
  namespace: production
spec:
  serviceAccountName: config-reader-sa   # 여기서 지정
  containers:
  - name: app
    image: my-app:latest

Service Account 토큰 마운트 방식

파드 내에서 Service Account 토큰은 /var/run/secrets/kubernetes.io/serviceaccount/token 경로에 자동으로 마운트된다.

Kubernetes 1.21부터는 Bound Service Account Token이 기본값이 됐다. 이전 방식(long-lived token)과의 차이점은 다음과 같다.

구분기존 방식Bound Token (1.21+)
유효 기간무제한기본 1시간, 갱신됨
대상 제한없음특정 파드, 오디언스 제한
보안토큰 탈취 시 영구 유효만료/바인딩으로 위험 최소화

토큰 자동 마운트 비활성화:

API 서버와 통신할 필요가 없는 파드라면 토큰 마운트를 꺼두는 것이 좋다.

apiVersion: v1
kind: Pod
metadata:
  name: no-api-access-pod
spec:
  automountServiceAccountToken: false   # 토큰 마운트 비활성화
  containers:
  - name: app
    image: nginx

RBAC 디버깅

권한 확인 — can-i 명령어:

# jane이 dev 네임스페이스에서 파드를 생성할 수 있는지 확인
kubectl auth can-i create pods --namespace=dev --as=jane

# 현재 사용자(자신)의 권한 확인
kubectl auth can-i list deployments -n production

# 특정 Service Account의 권한 확인
kubectl auth can-i get secrets \
  --as=system:serviceaccount:production:my-app-sa \
  -n production

권한 목록 조회:

# 특정 사용자에게 부여된 RoleBinding 확인
kubectl get rolebindings,clusterrolebindings -A \
  -o wide | grep jane

# 특정 Role의 권한 상세 조회
kubectl describe role pod-reader -n dev

자주 하는 실수와 주의 사항

1. default Service Account에 과도한 권한 부여

# 절대 하면 안 되는 패턴
kind: ClusterRoleBinding
subjects:
- kind: ServiceAccount
  name: default          # 기본 SA에 cluster-admin 권한
  namespace: default
roleRef:
  kind: ClusterRole
  name: cluster-admin

모든 파드가 default SA를 사용하므로, 여기에 광범위한 권한을 주면 어느 파드에서든 클러스터 전체를 제어할 수 있게 된다.

2. wildcard 사용 자제

# 위험한 패턴 — 모든 리소스, 모든 동사
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]

실제 필요한 리소스와 동사만 명시적으로 나열하는 것이 원칙이다.

3. ClusterRoleBinding 범위 오해

ClusterRoleBinding은 모든 네임스페이스에 걸쳐 적용된다. namespace를 지정해도 ClusterRoleBinding 자체의 범위는 변하지 않는다. 특정 네임스페이스에만 제한하고 싶다면 RoleBinding을 사용해야 한다.


권장 보안 실천 방법 정리

  • 최소 권한 원칙: 애플리케이션에 필요한 최소한의 verb와 resource만 허용
  • 전용 Service Account 생성: default SA 재사용 금지, 워크로드별 전용 SA 생성
  • automountServiceAccountToken: false: API 서버 접근이 불필요한 파드에 적용
  • 정기적인 권한 감사: kubectl auth can-ikubectl get rolebindings -A로 정기 점검
  • 네임스페이스 분리: 환경(dev/staging/production)별 네임스페이스를 분리해 권한 범위를 최소화