GCP IAM 권한 감사하기
사용 시기
- GCP 조직 또는 프로젝트 IAM 구성의 보안 평가를 수행할 때
- 과도한 권한이나 사용되지 않는 액세스 권한이 있는 서비스 계정을 식별할 때
- 컴플라이언스 요구 사항으로 액세스 제어 및 역할 할당 검토가 필요할 때
- IAM 구성 오류를 통한 잠재적 측면 이동을 조사할 때
- 손상된 자격 증명의 폭발 반경을 줄이기 위해 권한 범위를 축소할 때
사용하지 말아야 할 경우: VPC 방화벽 규칙 감사(네트워크 보안 도구 사용), GKE RBAC 감사(Kubernetes 전용 RBAC 도구 사용), IAM 작업에 대한 실시간 위협 탐지(SCC 이벤트 위협 탐지 사용).
사전 요구 사항
roles/iam.securityReviewer및roles/cloudAsset.viewer역할이 있는 GCP 조직 또는 프로젝트- 적절한 권한으로 인증된 gcloud CLI
- Cloud Asset API 활성화 (
gcloud services enable cloudasset.googleapis.com) - IAM Recommender API 활성화 (
gcloud services enable recommender.googleapis.com) - Policy Analyzer API 활성화 (
gcloud services enable policyanalyzer.googleapis.com)
워크플로
1단계: 조직 전체의 IAM 바인딩 열거
조직, 폴더, 프로젝트 수준의 모든 IAM 바인딩을 나열하여 전체 액세스 현황을 파악합니다.
# 조직 수준 IAM 바인딩
gcloud organizations get-iam-policy ORG_ID \
--format=json > org-iam-policy.json
# 조직 전체 IAM 정책 검색
gcloud asset search-all-iam-policies \
--scope=organizations/ORG_ID \
--format="table(resource, policy.bindings.role, policy.bindings.members)" \
--limit=500
# Owner 역할이 있는 모든 사용자 및 서비스 계정 찾기
gcloud asset search-all-iam-policies \
--scope=organizations/ORG_ID \
--query="policy:roles/owner" \
--format="table(resource, policy.bindings.members)"
# 기본 역할(Owner, Editor, Viewer)을 사용하는 모든 바인딩 찾기
gcloud asset search-all-iam-policies \
--scope=organizations/ORG_ID \
--query="policy:roles/owner OR policy:roles/editor" \
--format=json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for result in data:
resource = result.get('resource', '')
for binding in result.get('policy', {}).get('bindings', []):
role = binding.get('role', '')
if role in ['roles/owner', 'roles/editor']:
for member in binding.get('members', []):
print(f'{resource} | {role} | {member}')
"
2단계: 서비스 계정 및 키 감사
과도한 권한, 사용자 관리 키, 사용되지 않는 계정이 있는 서비스 계정을 식별합니다.
# 프로젝트의 모든 서비스 계정 나열
gcloud iam service-accounts list \
--project=PROJECT_ID \
--format="table(email, displayName, disabled)"
# 사용자 관리 키 확인 (최소화해야 함)
for sa in $(gcloud iam service-accounts list --project=PROJECT_ID --format="value(email)"); do
keys=$(gcloud iam service-accounts keys list \
--iam-account="$sa" \
--managed-by=user \
--format="table(name.basename(),validAfterTime,validBeforeTime)")
if [ -n "$keys" ]; then
echo "=== $sa ==="
echo "$keys"
fi
done
# 모든 프로젝트에서 관리자 역할이 있는 서비스 계정 찾기
gcloud asset search-all-iam-policies \
--scope=organizations/ORG_ID \
--query="policy.bindings.members:serviceAccount AND (policy:roles/owner OR policy:roles/editor OR policy:admin)" \
--format="table(resource, policy.bindings.role, policy.bindings.members)"
# 서비스 계정 IAM 정책 확인 (가장할 수 있는 사용자)
for sa in $(gcloud iam service-accounts list --project=PROJECT_ID --format="value(email)"); do
echo "=== $sa ==="
gcloud iam service-accounts get-iam-policy "$sa" --format=json 2>/dev/null
done
3단계: IAM Recommender를 사용하여 과도한 권한 식별
GCP의 IAM Recommender를 활용하여 실제 사용량보다 더 많은 액세스 권한을 부여하는 역할을 찾습니다.
# 프로젝트의 IAM 역할 권장 사항 나열
gcloud recommender recommendations list \
--project=PROJECT_ID \
--recommender=google.iam.policy.Recommender \
--location=global \
--format="table(name, description, priority, stateInfo.state)"
# 자세한 권장 사항 보기
gcloud recommender recommendations describe RECOMMENDATION_ID \
--project=PROJECT_ID \
--recommender=google.iam.policy.Recommender \
--location=global \
--format=json
# IAM 사용량에 대한 인사이트 나열
gcloud recommender insights list \
--project=PROJECT_ID \
--insight-type=google.iam.policy.Insight \
--location=global \
--format="table(name, description, severity, category)"
# 권장 사항 적용 (검토 후)
gcloud recommender recommendations mark-claimed RECOMMENDATION_ID \
--project=PROJECT_ID \
--recommender=google.iam.policy.Recommender \
--location=global \
--etag=ETAG
4단계: Policy Analyzer로 유효 권한 분석
Policy Analyzer를 사용하여 특정 주체 또는 리소스에 대한 유효 액세스 권한을 확인합니다.
# 특정 리소스에 액세스할 수 있는 사용자 확인
gcloud asset analyze-iam-policy \
--organization=ORG_ID \
--full-resource-name="//storage.googleapis.com/projects/_/buckets/sensitive-data-bucket" \
--format="table(identityList.identities, accessControlLists.accesses.role)"
# 특정 사용자가 액세스할 수 있는 리소스 확인
gcloud asset analyze-iam-policy \
--organization=ORG_ID \
--identity="user:[email protected]" \
--format="table(accessControlLists.resources.fullResourceName, accessControlLists.accesses.role)"
# 특정 작업을 수행할 수 있는 사용자 확인
gcloud asset analyze-iam-policy \
--organization=ORG_ID \
--full-resource-name="//cloudresourcemanager.googleapis.com/projects/PROJECT_ID" \
--permissions="iam.serviceAccounts.actAs,iam.serviceAccountKeys.create" \
--format="table(identityList.identities, accessControlLists.accesses.permission)"
# allUsers 또는 allAuthenticatedUsers 액세스 권한이 있는 모든 주체 찾기
gcloud asset search-all-iam-policies \
--scope=organizations/ORG_ID \
--query="policy:allUsers OR policy:allAuthenticatedUsers" \
--format="table(resource, policy.bindings.role, policy.bindings.members)"
5단계: 도메인 위임 및 가장 위험 확인
도메인 위임 및 가장 기능이 있는 서비스 계정을 식별합니다.
# 도메인 위임이 설정된 서비스 계정 확인
# (위임된 계정을 나열하려면 Admin SDK 액세스 필요)
gcloud iam service-accounts list --project=PROJECT_ID --format=json | python3 -c "
import json, sys
accounts = json.load(sys.stdin)
for sa in accounts:
email = sa.get('email', '')
# SA에 도메인 위임이 활성화되어 있는지 확인
# Admin SDK API 액세스 필요
print(f'SA: {email} - admin.google.com에서 위임 상태 확인')
"
# 다른 ID가 가장할 수 있는 서비스 계정 찾기
for sa in $(gcloud iam service-accounts list --project=PROJECT_ID --format="value(email)"); do
policy=$(gcloud iam service-accounts get-iam-policy "$sa" --format=json 2>/dev/null)
if echo "$policy" | python3 -c "
import json, sys
p = json.load(sys.stdin)
for b in p.get('bindings', []):
if b['role'] in ['roles/iam.serviceAccountTokenCreator', 'roles/iam.serviceAccountUser']:
print(f' {b[\"role\"]}: {b[\"members\"]}')
" 2>/dev/null; then
echo "=== 가장 위험: $sa ==="
fi
done
6단계: 감사 보고서 생성 및 수정 적용
조사 결과를 컴파일하고 권장 권한 축소를 구현합니다.
# 기본 역할 제거 및 사전 정의된 역할로 교체
gcloud projects remove-iam-policy-binding PROJECT_ID \
--member="user:[email protected]" \
--role="roles/editor"
gcloud projects add-iam-policy-binding PROJECT_ID \
--member="user:[email protected]" \
--role="roles/compute.viewer"
gcloud projects add-iam-policy-binding PROJECT_ID \
--member="user:[email protected]" \
--role="roles/storage.objectViewer"
# 사용되지 않는 서비스 계정 키 삭제
gcloud iam service-accounts keys delete KEY_ID \
--iam-account=SA_EMAIL
# 사용되지 않는 서비스 계정 비활성화
gcloud iam service-accounts disable SA_EMAIL --project=PROJECT_ID
주요 개념
| 용어 | 정의 |
|---|---|
| 기본 역할(Primitive Role) | 레거시 GCP 역할(Owner, Editor, Viewer)로 모든 서비스에 광범위한 권한을 부여하며, 프로덕션 환경에 권장되지 않음 |
| 사전 정의된 역할(Predefined Role) | GCP 관리 역할로 특정 서비스 및 작업에 범위가 지정되어 기본 역할보다 세분화된 액세스 제공 |
| IAM Recommender | GCP ML 기반 서비스로 실제 권한 사용량을 분석하고 최소 권한 달성을 위한 역할 축소를 제안 |
| Policy Analyzer | 조직 계층 전반의 유효 IAM 액세스를 분석하여 누가 무엇에 액세스할 수 있는지 질문에 답하는 도구 |
| 서비스 계정 키 | 서비스 계정 인증을 위한 사용자 관리 자격 증명으로, 키를 내보낼 수 있고 자동 만료되지 않아 보안 위험 |
| 도메인 위임 | 서비스 계정에 Google Workspace 도메인의 모든 사용자를 가장할 수 있는 기능을 부여하며, 상당한 권한 상승 위험 |
도구 및 시스템
- gcloud CLI: GCP IAM 정책, 서비스 계정, 역할 바인딩을 쿼리하고 관리하는 기본 도구
- IAM Recommender: 실제 사용량을 기반으로 과도한 권한을 줄이기 위한 ML 기반 권장 엔진
- Policy Analyzer: 조직 전체의 유효 액세스 분석 도구로 누가 무엇에 액세스할 수 있는지 이해
- Cloud Asset Inventory: IAM 정책 및 리소스 메타데이터에 대한 프로젝트 간 검색
- ScoutSuite: 역할 할당 및 서비스 계정에 대한 GCP IAM 관련 검사가 포함된 멀티 클라우드 감사 도구
일반적인 시나리오
시나리오: GCP 조직 전체의 기본 역할 사용량 줄이기
컨텍스트: 감사 결과 조직 전체 IAM 바인딩의 60%가 기본 역할(Owner/Editor)을 사용하는 것으로 나타났습니다. 보안 팀은 개발자 워크플로를 방해하지 않고 사전 정의된 역할로 마이그레이션해야 합니다.
접근 방식:
gcloud asset search-all-iam-policies를 실행하여 모든 기본 역할 바인딩을 인벤토리화- IAM Recommender를 사용하여 교체할 사전 정의된 역할에 대한 ML 기반 제안을 얻음
- 각 바인딩에 대해 Policy Analyzer를 사용하여 주체가 실제로 액세스하는 대상을 이해
- 매핑 문서 생성: 기본 역할 -> 필요한 특정 사전 정의된 역할
- 테스트 기간 동안 기본 역할과 함께 사전 정의된 역할 적용
- Cloud Audit Logs를 사용하여 액세스 거부 오류 모니터링
- 2주 동안 액세스 문제가 없음을 확인한 후 기본 역할 제거
함정: 기본 역할에는 모든 GCP 서비스의 권한이 포함되므로 이를 대체하려면 여러 사전 정의된 역할이 필요합니다. Recommender는 관찰 기간이 모든 사용 사례를 포착하지 못하면 지나치게 제한적인 역할을 제안할 수 있습니다. 필요한 정확한 권한 집합과 일치하는 사전 정의된 역할이 없는 경우 사용자 지정 역할로 간격을 채울 수 있습니다.
출력 형식
GCP IAM 권한 감사 보고서
===================================
조직: acme-org (ORG_ID: 123456789)
감사 대상 프로젝트: 25개
감사일: 2026-02-23
IAM 바인딩 요약:
총 바인딩: 342개
기본 역할 사용: 205개 (60%)
사전 정의된 역할 사용: 112개 (33%)
사용자 지정 역할 사용: 25개 (7%)
심각한 발견 사항:
[IAM-001] Owner 역할이 있는 서비스 계정
SA: [email protected]
역할: 프로젝트 prod-project에 대한 roles/owner
사용자 관리 키: 3개 (가장 오래된 키: 14개월 전)
수정: 특정 사전 정의된 역할로 교체, 오래된 키 삭제
[IAM-002] allAuthenticatedUsers 바인딩
리소스: gs://public-data-bucket
역할: roles/storage.objectViewer
위험: 모든 Google 계정 소유자가 버킷 내용을 읽을 수 있음
수정: 특정 사용자 그룹 또는 서비스 계정으로 제한
서비스 계정 상태:
총 서비스 계정: 67개
사용자 관리 키가 있는 계정: 23개
90일 이상 된 키: 18개
사용되지 않는 계정(90일 이상): 12개
도메인 위임이 설정된 계정: 2개
Recommender 제안:
총 제안 수: 45개
우선순위 높음: 12개
예상 축소된 권한: 2,847개 개별 권한