쿠버네티스 운영 실무 · RBAC — Role·ClusterRole·바인딩 · 실습
최소 권한으로 역할 설계하기
목표
역할과 바인딩을 직접 만들어 최소 권한을 설계하고, kubectl auth can-i 로 권한의 경계를 검증하는 습관을 들입니다.
왜 중요한가
RBAC 에서 사람들이 가장 많이 헷갈리는 지점은 스코프를 정하는 것이 역할이 아니라 바인딩이라는 사실입니다. 같은 ClusterRole 이라도 ClusterRoleBinding 으로 걸면 클러스터 전체, RoleBinding 으로 걸면 그 네임스페이스에서만 유효합니다. 이 성질 덕분에 공통 권한 묶음을 ClusterRole 로 한 번만 정의하고 팀마다 자기 네임스페이스에서 재사용할 수 있습니다. 두 번째 함정은 서브리소스입니다. pods 와 pods/log, pods/exec 는 서로 다른 리소스 이름이라 권한이 자동으로 따라오지 않습니다. 로그만 읽는 봇에게 셸 접속 권한까지 딸려 가지 않게 하려면 이 구분이 필요합니다. 마지막으로 권한은 작성하는 것이 아니라 판정되는 것이므로, 매니페스트를 눈으로 읽는 대신 impersonation 으로 물어보세요. yes 만 확인하지 말고 no 도 함께 확인해야 권한이 필요 이상으로 넓은지 알 수 있습니다.
단계
1. 네임스페이스 rbac-lab 을 만들고 그 안에 서비스 어카운트 app-reader, inspector, log-bot 세 개를 만드세요.
2. rbac-lab 에 Role pod-reader 를 만드세요. 규칙은 하나이며 apiGroups 는 코어 그룹(빈 문자열), resources 는 pods, verbs 는 get, list, watch 세 개입니다. 와일드카드 * 는 어디에도 쓰면 안 됩니다.
3. rbac-lab 에 RoleBinding read-pods 를 만드세요. roleRef 는 kind Role, name pod-reader 이고, 주체는 kind ServiceAccount, name app-reader, namespace rbac-lab 입니다.
4. app-reader 로 impersonation 해서 권한을 확인하고 결과를 /root/ops/rbac/out/can-i.txt 에 저장하세요. 이 파일에는 yes 응답과 no 응답이 모두 들어 있어야 합니다. 확인할 항목은 최소한 다음 셋입니다 — rbac-lab 에서 파드 목록 조회(yes), rbac-lab 에서 파드 삭제(no), default 네임스페이스에서 파드 목록 조회(no).
5. ClusterRole node-viewer 를 만드세요. resources 에 nodes 가 들어가고 모든 규칙의 verbs 는 get, list, watch 뿐이어야 합니다. 이어서 ClusterRoleBinding node-viewer-binding 으로 이 역할을 rbac-lab 의 app-reader 에게 주세요. 결과적으로 app-reader 는 노드를 조회할 수 있고 삭제할 수는 없어야 합니다.
6. ClusterRole ns-inspector 를 만드세요(ConfigMap 을 읽을 수 있어야 합니다). 그리고 rbac-lab 에 RoleBinding inspect-here 를 만들어 roleRef.kind 를 ClusterRole, name 을 ns-inspector 로 하고 주체는 rbac-lab 의 inspector 로 하세요. 결과적으로 inspector 는 rbac-lab 에서는 ConfigMap 을 읽지만 default 에서는 읽지 못해야 합니다.
7. rbac-lab 에 Role log-reader 를 만드세요. resources 에는 pods/log 만 넣고 pods 는 넣지 마세요. 이 역할을 log-bot 에게 RoleBinding 으로 거세요. 결과적으로 log-bot 은 pods/log 를 읽을 수 있고, pods 자체는 읽지 못하며, pods/exec 도 쓰지 못해야 합니다.
8. /root/ops/rbac/out/rbac-audit.json 을 만드세요. 필드는 네 개입니다. cluster_admin_bindings 는 roleRef.name 이 cluster-admin 인 ClusterRoleBinding 이름 배열이며 실제 클러스터의 개수와 정확히 일치해야 하고 기본 바인딩인 cluster-admin 이 포함돼야 합니다. wildcard_roles 는 * 를 쓰는 역할 이름 배열(1개 이상), secret_readers 는 secrets 를 다루는 역할 이름 배열(1개 이상), least_privilege_violations 는 최소 권한 위반으로 판단한 항목 배열입니다.
참고
- 서비스 어카운트의 정식 주체 이름은
system:serviceaccount:<네임스페이스>:<이름>입니다.kubectl auth can-i <동사> <리소스> -n <네임스페이스> --as=<주체>형태로 물어보세요. kubectl create role/create clusterrole/create rolebinding에--dry-run=client -o yaml을 붙이면 올바른 매니페스트 뼈대를 얻을 수 있습니다.--serviceaccount=<네임스페이스>:<이름>을 쓰면 주체의 namespace 필드가 자동으로 채워집니다.- 8번은 손으로 세면 거의 틀립니다.
kubectl get clusterrolebindings -o json | jq로 뽑아서 만드세요. 와일드카드 역할은kubectl get roles,clusterroles -A -o json에서verbs나resources에*가 있는 것을 거르면 됩니다. - 흔한 실수 1:
apiGroups에"v1"이나"core"를 적는 것. 코어 그룹의 이름은 빈 문자열입니다. - 흔한 실수 2: 7번에서
pods와pods/log를 함께 넣는 것. 그러면 파드 자체도 읽히게 되어 서브리소스 분리 연습이 되지 않습니다. - 흔한 실수 3: 5번에서 ClusterRole 을 만들고 RoleBinding 으로 거는 것. 노드는 네임스페이스가 없어 RoleBinding 으로는 접근 권한이 생기지 않습니다.
- 실습 파드는 실습마다 새로 뜨므로 앞 실습에서 만든 클러스터 상태는 남아 있지 않습니다. 네임스페이스와 서비스 어카운트는 이 실습 안에서 직접 만드세요. 운영 절차를 기억이 아니라 런북과 매니페스트로 남겨야 하는 이유가 바로 이것입니다.
단계 8개
- 네임스페이스와 서비스 어카운트 준비하기
- 읽기 전용 Role 만들기
- Role 을 서비스 어카운트에 바인딩하기
- impersonation 으로 권한 경계 확인하기
- 클러스터 범위 리소스용 ClusterRole 만들기
- ClusterRole 을 RoleBinding 으로 걸어 보기
- 서브리소스만 여는 역할 만들기
- 권한 감사 보고서 만들기