kubectl get pods를 쳤는데 다음 같은 메시지가 뜨면 RBAC 권한이 막힌 것입니다.
Error from server (Forbidden): pods is forbidden: User "dev"
cannot list resource "pods" in API group "" in the namespace "app"
RBAC는 누가(subject) 무엇을(resource) 어떻게(verb) 할 수 있는지를 Role과 RoleBinding 두 객체로 정의합니다. Forbidden은 대부분 권한이 "없어서"가 아니라 연결이 잘못돼서 납니다.
권한이 실제로 있는지부터 확인
추측 대신 auth can-i로 직접 물어봅니다.
# 내 권한 확인
kubectl auth can-i list pods -n app
# 특정 사용자/서비스어카운트 권한 확인
kubectl auth can-i list pods -n app \
--as=system:serviceaccount:app:deployer
no가 나오면 Role이나 RoleBinding 둘 중 하나가 어긋난 것입니다.
Role과 RoleBinding의 역할
| 객체 | 정의하는 것 | 범위 |
|---|---|---|
| Role | 권한 규칙(어떤 resource에 어떤 verb) | 단일 네임스페이스 |
| ClusterRole | 동일하되 클러스터 전역 | 전체 클러스터·노드·PV |
| RoleBinding | Role을 subject에 연결 | 단일 네임스페이스 |
| ClusterRoleBinding | ClusterRole을 전역 연결 | 전체 클러스터 |
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: app
name: pod-reader
rules:
- apiGroups: [""] # 코어 그룹은 빈 문자열
resources: ["pods"]
verbs: ["get", "list", "watch"]
원인별 해결
① apiGroups를 빼먹거나 틀림 — Pod·Service·ConfigMap은 코어 그룹이라 apiGroups: [""](빈 문자열)입니다. Deployment는 ["apps"], Ingress는 ["networking.k8s.io"]. 그룹이 틀리면 규칙이 매칭되지 않아 조용히 Forbidden이 됩니다.
② RoleBinding의 namespace 불일치 — Role은 app 네임스페이스인데 Pod는 prod에 있으면 적용되지 않습니다. Role·RoleBinding·대상 리소스가 같은 네임스페이스에 있어야 합니다.
③ subjects의 name·kind 오타 — ServiceAccount 이름 오타, kind: User를 써야 할 곳에 ServiceAccount를 쓰는 실수가 흔합니다. SA 주체는 반드시 namespace 필드도 필요합니다.
④ 클러스터 범위 리소스에 Role 사용 — Node, PersistentVolume, Namespace 자체는 네임스페이스에 속하지 않습니다. Role로는 절대 안 되고 ClusterRole + ClusterRoleBinding이 필요합니다.
⑤ roleRef는 수정 불가 — RoleBinding의 roleRef는 생성 후 변경할 수 없습니다. 잘못 연결했다면 삭제 후 다시 만들어야 합니다.
점검 체크리스트
kubectl auth can-i --list -n app --as=system:serviceaccount:app:deployer
kubectl get rolebinding,role -n app
kubectl describe rolebinding <name> -n app # roleRef·subjects 확인
이 3개로 "권한 규칙이 맞는지"와 "주체에 제대로 연결됐는지"를 동시에 좁힐 수 있습니다.
ServiceAccount에 최소 권한을 직접 부여해보며 Forbidden을 재현·해결하는 실습은 쿠버네티스 트랙에서 회원가입 없이 무료로 해볼 수 있습니다.