最小権限でロールを設計する
한국어 원문으로 표시합니다.
목표
역할과 바인딩을 직접 만들어 최소 권한을 설계하고, kubectl auth can-i 로 권한의 경계를 검증하는 습관을 들입니다.
왜 중요한가
RBAC 에서 사람들이 가장 많이 헷갈리는 지점은 스코프를 정하는 것이 역할이 아니라 바인딩이라는 사실입니다. 같은 ClusterRole 이라도 ClusterRoleBinding 으로 걸면 클러스터 전체, RoleBinding 으로 걸면 그 네임스페이스에서만 유효합니다. 이 성질 덕분에 공통 권한 묶음을 ClusterRole 로 한 번만 정의하고 팀마다 자기 네임스페이스에서 재사용할 수 있습니다. 두 번째 함정은 서브리소스입니다. pods 와 pods/log, pods/exec 는 서로 다른 리소스 이름이라 권한이 자동으로 따라오지 않습니다. 로그만 읽는 봇에게 셸 접속 권한까지 딸려 가지 않게 하려면 이 구분이 필요합니다. 마지막으로 권한은 작성하는 것이 아니라 판정되는 것이므로, 매니페스트를 눈으로 읽는 대신 impersonation 으로 물어보세요. yes 만 확인하지 말고 no 도 함께 확인해야 권한이 필요 이상으로 넓은지 알 수 있습니다.
단계
- 네임스페이스
rbac-lab을 만들고 그 안에 서비스 어카운트app-reader,inspector,log-bot세 개를 만드세요. rbac-lab에 Rolepod-reader를 만드세요. 규칙은 하나이며apiGroups는 코어 그룹(빈 문자열),resources는pods,verbs는get,list,watch세 개입니다. 와일드카드*는 어디에도 쓰면 안 됩니다.rbac-lab에 RoleBindingread-pods를 만드세요.roleRef는 kindRole, namepod-reader이고, 주체는 kindServiceAccount, nameapp-reader, namespacerbac-lab입니다.app-reader로 impersonation 해서 권한을 확인하고 결과를/root/ops/rbac/out/can-i.txt에 저장하세요. 이 파일에는yes응답과no응답이 모두 들어 있어야 합니다. 확인할 항목은 최소한 다음 셋입니다 —rbac-lab에서 파드 목록 조회(yes),rbac-lab에서 파드 삭제(no),default네임스페이스에서 파드 목록 조회(no).- ClusterRole
node-viewer를 만드세요.resources에nodes가 들어가고 모든 규칙의verbs는get,list,watch뿐이어야 합니다. 이어서 ClusterRoleBindingnode-viewer-binding으로 이 역할을rbac-lab의app-reader에게 주세요. 결과적으로app-reader는 노드를 조회할 수 있고 삭제할 수는 없어야 합니다. - ClusterRole
ns-inspector를 만드세요(ConfigMap 을 읽을 수 있어야 합니다). 그리고rbac-lab에 RoleBindinginspect-here를 만들어roleRef.kind를ClusterRole, name 을ns-inspector로 하고 주체는rbac-lab의inspector로 하세요. 결과적으로inspector는rbac-lab에서는 ConfigMap 을 읽지만default에서는 읽지 못해야 합니다. rbac-lab에 Rolelog-reader를 만드세요.resources에는pods/log만 넣고pods는 넣지 마세요. 이 역할을log-bot에게 RoleBinding 으로 거세요. 결과적으로log-bot은pods/log를 읽을 수 있고,pods자체는 읽지 못하며,pods/exec도 쓰지 못해야 합니다./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 으로는 접근 권한이 생기지 않습니다.
- 실습 파드는 실습마다 새로 뜨므로 앞 실습에서 만든 클러스터 상태는 남아 있지 않습니다. 네임스페이스와 서비스 어카운트는 이 실습 안에서 직접 만드세요. 운영 절차를 기억이 아니라 런북과 매니페스트로 남겨야 하는 이유가 바로 이것입니다.
네임스페이스와 서비스 어카운트 준비하기
네임스페이스 rbac-lab 을 만들고 그 안에 서비스 어카운트 app-reader, inspector, log-bot 세 개를 만드세요.
주체가 있어야 권한을 줄 수 있습니다. 서비스 어카운트는 네임스페이스에 속하며 이름만으로 만들 수 있습니다.
읽기 전용 Role 만들기
rbac-lab 에 Role pod-reader 를 만드세요. 규칙은 하나이며 apiGroups 는 코어 그룹(빈 문자열), resources 는 pods, verbs 는 get, list, watch 세 개입니다. 와일드카드 * 는 어디에도 쓰면 안 됩니다.
코어 리소스의 API 그룹 이름이 무엇인지 확인하세요. 읽기 셋은 세 개이고 와일드카드는 쓰지 않습니다.
Role 을 서비스 어카운트에 바인딩하기
rbac-lab 에 RoleBinding read-pods 를 만드세요. roleRef 는 kind Role, name pod-reader 이고, 주체는 kind ServiceAccount, name app-reader, namespace rbac-lab 입니다.
주체가 서비스 어카운트일 때는 이름만으로 부족합니다. 어느 네임스페이스의 어카운트인지까지 적어야 합니다.
impersonation 으로 권한 경계 확인하기
app-reader 로 impersonation 해서 권한을 확인하고 결과를 /root/ops/rbac/out/can-i.txt 에 저장하세요. 이 파일에는 yes 응답과 no 응답이 모두 들어 있어야 합니다. 확인할 항목은 최소한 다음 셋입니다 — rbac-lab 에서 파드 목록 조회(yes), rbac-lab 에서 파드 삭제(no), default 네임스페이스에서 파드 목록 조회(no).
서비스 어카운트의 정식 이름 형식을 기억하세요. 되는 것과 안 되는 것을 모두 확인해야 경계가 드러납니다.
클러스터 범위 리소스용 ClusterRole 만들기
ClusterRole node-viewer 를 만드세요. resources 에 nodes 가 들어가고 모든 규칙의 verbs 는 get, list, watch 뿐이어야 합니다. 이어서 ClusterRoleBinding node-viewer-binding 으로 이 역할을 rbac-lab 의 app-reader 에게 주세요. 결과적으로 app-reader 는 노드를 조회할 수 있고 삭제할 수는 없어야 합니다.
노드는 네임스페이스가 없는 리소스라 Role 로는 다룰 수 없습니다. 클러스터 전체에 걸려면 바인딩도 클러스터 범위여야 합니다.
ClusterRole 을 RoleBinding 으로 걸어 보기
ClusterRole ns-inspector 를 만드세요(ConfigMap 을 읽을 수 있어야 합니다). 그리고 rbac-lab 에 RoleBinding inspect-here 를 만들어 roleRef.kind 를 ClusterRole, name 을 ns-inspector 로 하고 주체는 rbac-lab 의 inspector 로 하세요. 결과적으로 inspector 는 rbac-lab 에서는 ConfigMap 을 읽지만 default 에서는 읽지 못해야 합니다.
스코프를 정하는 것은 역할의 종류가 아니라 바인딩의 종류입니다. 같은 역할이 어느 네임스페이스에서만 유효해지는지 확인하세요.
서브리소스만 여는 역할 만들기
rbac-lab 에 Role log-reader 를 만드세요. resources 에는 pods/log 만 넣고 pods 는 넣지 마세요. 이 역할을 log-bot 에게 RoleBinding 으로 거세요. 결과적으로 log-bot 은 pods/log 를 읽을 수 있고, pods 자체는 읽지 못하며, pods/exec 도 쓰지 못해야 합니다.
로그는 파드와 다른 리소스 이름을 갖습니다. 상위 리소스까지 함께 열면 이 단계의 의미가 사라집니다.
권한 감사 보고서 만들기
/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 는 최소 권한 위반으로 판단한 항목 배열입니다.
손으로 세지 말고 클러스터에서 뽑으세요. cluster-admin 바인딩 수는 실제 값과 정확히 일치해야 합니다.