평면: 열쇠, 자물쇠, 금지 표지판, 돋보기, 드라이버 — IAM 액세스 거부 디버깅 도구
글 요약
AWS IAM AccessDenied 오류는 단순히 정책을 추가한다고 해결되지 않더라고요. 이 글에서는 CloudTrail → IAM Policy Simulator → Access Analyzer 순서로 10분 안에 원인을 추적하는 디버깅 워크플로우와, 실제 현장에서 자주 발생하는 정책 충돌 사례, 그리고 도구별 비교 분석을 한 번에 정리해드릴게요.
“분명 권한을 줬는데 왜 계속 AccessDenied가 뜨는지 모르겠어요.”
IAM 정책 디버깅의 핵심은 한참 헤매지 않고 거부 이벤트가 발생한 정확한 지점을 찾는 거예요. 이 글에서 CloudTrail 이벤트 코드 해석법, SCP·리소스 정책 충돌 판독법, IAM Policy Simulator 활용법을 익히면 같은 오류에서 더 이상 2시간을 날리지 않게 됩니다.
실제로 많은 분들이 IAM 정책 디버깅에서 가장 큰 착각을 하시거든요. 정책 하나 추가했는데 안 되면 또 추가하고, 그러다 보면 사용자 권한이 20개가 넘어가는데도 여전히 AccessDenied가 떠 있는 경우가 더러 있더라고요. 진짜 원인은 대부분 정책이 모자라서가 아니라 어딘가에서 Explicit Deny가 걸려 있거나, Condition 블록의 조건이 맞지 않아서인 경우가 대부분이에요. 콘솔에서 권한 추가하는 것 자체는 1분이면 되지만, 거부된 이유를 추적하는 데 반나절이 걸리는 건 진단 순서를 모르기 때문이거든요.
📚 목차
AWS 환경이 복잡해질수록 IAM 권한 디버깅은 더 어려워지거든요. 멀티 계정 구조, SCP(Service Control Policy), 리소스 기반 정책, 세션 태그까지 얽히면 단순히 사용자 정책만 봐서는 절대 답이 안 나와요. 그래서 이 글에서는 단계별 진단 순서와 도구 조합 전략, 그리고 실전 노하우를 한 번에 풀어볼게요.
📌 이 글의 핵심 정리
- AccessDenied는 “권한 부족”이 아니라 “어딘가의 Explicit Deny 또는 Condition 불일치”일 가능성이 더 높거든요.
- 진단은 CloudTrail Event Record → Policy Simulator → Access Analyzer 순서로 진행하면 10분 안에 원인이 잡혀요.
- 정책은 많이 붙일수록 위험해요. 최소 권한 원칙을 지키면서도 거부 원인을 빠르게 찾는 게 핵심이에요.
- SCP, 리소스 정책, IAM 정책, 세션 정책이 동시에 평가된다는 사실을 모르면 디버깅이 끝나지 않거든요.
- EventBridge + Lambda로 거부 이벤트를 자동 알림으로 받으면 사후 대응 시간까지 줄어들어요.
- IAM Policy Simulator는 dry-run이 가능한 유일한 도구라서, 실 배포 전에 미리 확인할 수 있어요.
- Access Analyzer는 외부 공유 권한을 시각화해서 보여주는 도구라서 보안 점검과 동시에 활용할 수 있어요.
1. AccessDenied 오류가 뜨는 진짜 이유
AWS는 API 호출이 들어오면 5단계 평가 로직을 거치면서 허용 여부를 결정하거든요. 이 순서를 모르고 “권한 추가 = 해결”이라는 공식만 외우면 같은 오류에 반복적으로 갇히게 돼요.
가장 흔한 착각: “권한이 있는데 안 된다”
콘솔에서 권한 탭을 열어보면 분명 s3:GetObject가 Allow로 표시되어 있는데, 실제 호출에서는 거부되는 경우가 더러 있더라고요. 이건 표시되는 권한과 실제 평가되는 권한이 다르기 때문이에요. 콘솔의 “권한” 탭은 사용자/역할에 직접 부착된 정책만 보여주거든요. 리소스 정책, SCP, 세션 정책은 그 어디에서도 한눈에 보여주지 않아요.
AWS IAM 평가 로직의 핵심
AWS는 평가 시점에 Explicit Deny를 최우선으로 처리해요. Allow가 100개 있어도 Deny가 단 하나라도 있으면 즉시 거부되거든요. 그리고 모든 정책에서 Allow가 하나도 없으면 Implicit Deny로 처리되고, 이때만 다시 Default Deny가 작동해요. 즉, “권한이 있어 보여서 안 되는” 상황은 거의 대부분 보이지 않는 곳의 Deny 때문이에요.
⚠️ AccessDenied 진단 시 주의
- 콘솔의 “권한” 탭에 Allow가 보여도 안 된다고 안심하지 마세요. 실제 평가는 다층 구조로 일어나거든요.
- SCP(Service Control Policy)는 Organizations 환경에서 상위 계정이 권한을 제한하는 도구예요. 권한 추가보다 SCP 확인이 우선이에요.
2. 10분 안에 원인 찾는 진단 워크플로우
제대로 된 도구 조합과 순서만 알면 대부분의 AccessDenied는 10분 안에 원인이 잡혀요. 임의로 정책을 추가하면서 시간을 쓰는 것보다 훨씬 빠르거든요.
1단계: CloudTrail에서 거부 이벤트 확인 (3분)
CloudTrail 콘솔에서 “이벤트 기록 → 이벤트 이름 Lookup”으로 거부된 호출을 찾아요. errorCode: AccessDenied 또는 errorMessage: User ... is not authorized로 필터링하면 정확한 시점의 거부 이벤트가 떠요. 여기서 어떤 ARN이, 어떤 액션을, 어떤 리소스에 대해 거부됐는지 3가지 정보만 캡처하면 절반은 해결됐어요.
2단계: 실 사용자·역할·리소스 ARN 추적 (3분)
CloudTrail 이벤트 안의 userIdentity 섹션에서 누가 호출했는지 확인할 수 있어요. AssumedRole로 들어왔다면 역할 ARN, IAM User라면 사용자 ARN을 그대로 복사해서 다음 단계 도구에 넣어주면 돼요. 리소스 ARN도 이벤트에서 그대로 확인 가능하거든요.
3단계: IAM Policy Simulator로 dry-run 검증 (4분)
IAM Policy Simulator는 실제 호출 없이 권한 평가만 해보는 도구예요. 콘솔의 “IAM → 액션 선택 → 시뮬레이터”에서 사용자/역할 ARN과 액션을 넣으면 Allowed / Implicit Deny / Explicit Deny 3가지로 결과를 알려줘요. Explicit Deny가 떴다면 그 정책이 범인이고, Implicit Deny라면 Allow 정책이 없는 거라서 정책 추가가 답이 되거든요.
💡 진단 시간 단축 꿀팁
- CloudTrail Lake를 사용 중이라면 SQL 한 줄로 거부 이벤트만 추출할 수 있어요.
WHERE errorCode = 'AccessDenied'만 외우면 충분해요. - Policy Simulator 결과를 스크린샷 대신 JSON으로 복사해두면, 후속 정책 수정 시 비교가 빨라져요.
3. 실패 사례 — 권한 10개를 추가해도 안 풀린 2시간
실제로 제가 맡았던 케이스 중에 가장 흔한 패턴이 있거든요. 바로 “S3 버킷 다운로드가 안 됩니다”라는 한 줄짜리 이슈였어요. 이 사례가 왜 실패했는지, 그리고 어떻게 해결했는지 풀어볼게요.
사건 개요: S3 GetObject가 계속 거부됨
한 개발자가 EC2에서 돌아가는 애플리케이션으로 S3 버킷에서 로그 파일을 다운로드하려 했어요. 처음에는 단순히 s3:GetObject 권한을 IAM 역할에 추가했는데 안 되더라고요. 그 다음에 s3:ListBucket도 추가하고, s3:GetObjectVersion, s3:GetBucketLocation까지 추가해서 총 10개 권한이 들어간 상태였어요. 그래도 여전히 AccessDenied.
전문가의 진단: 보이지 않는 Deny를 추적
CloudTrail 이벤트를 열어보니 errorMessage에 “explicit deny in xxx policy”라는 문구가 명확히 적혀 있었어요. 콘솔에서는 절대 안 보이는 정보거든요. 해당 정책 ID를 IAM 콘솔에서 검색했더니, 회사의 보안팀이 모든 S3 호출에 대해 VPC Endpoint가 아닌 호출을 차단하는 SCP를 걸어둔 게 원인이었어요. 개발자는 EC2가 퍼블릭 서브넷에 있어서 인터넷을 통해 S3에 접근하고 있었거든요.
해결 노하우: SCP를 먼저 확인하는 습관
이 케이스의 핵심 교훈은 두 가지예요. 첫째, SCP는 Organizations 관리자만 볼 수 있으므로 개발자는 자기가 모르는 Deny가 있을 수 있다는 사실을 인지해야 해요. 둘째, 진단할 때는 CloudTrail의 errorMessage를 그대로 읽으면 어느 정책이 Deny를 내렸는지 바로 알 수 있어요. 콘솔에서 정책을 추가하는 것보다, errorMessage를 먼저 읽는 게 빠르거든요. 결과적으로 SCP에 aws:SourceVpce 조건을 추가해 허용된 엔드포인트에서만 호출되도록 수정하니 즉시 해결됐어요.
⚠️ IAM 정책 디버깅 함정
- Allow를 계속 추가하는 방식은 Deny가 어디 있는지 모를 때만 하는 임시 방편이에요. 영구 해결책이 아니에요.
- 조직 단위 SCP는 콘솔의 사용자 권한 탭에서 절대 보이지 않거든요. 반드시 Organizations 콘솔에서 별도로 확인해야 해요.
4. 디버깅 도구별 비교 분석
AWS는 IAM 권한을 디버깅할 수 있는 여러 도구를 제공하거든요. 각 도구의 역할과 한계가 명확히 다르기 때문에, 어떤 상황에서 어떤 도구를 써야 하는지 비교 정리해드릴게요.
디버깅 도구 비교표
| 도구 | 핵심 기능 | 강점 | 약점 | 추천 상황 |
|---|---|---|---|---|
| CloudTrail Event Lookup | 실제 거부 이벤트 기록 조회 | 실제 호출 기록, errorMessage 노출 | 실 시간 알림 불가, 콘솔 검색 느림 | 과거 거부 사건 사후 추적 |
| IAM Policy Simulator | dry-run 권한 평가 | 실 호출 없이 검증, Explicit/Implicit Deny 구분 | 리소스 정책 평가 한계 | 정책 수정 전 사전 검증 |
| IAM Access Analyzer | 외부 공유 권한 시각화 | 퍼블릭/크로스 계정 권한 자동 탐지 | 내부 호출 디버깅엔 부적합 | 보안 감사, 외부 노출 점검 |
| AWS CLI dry-run (–dry-run) | CLI 호출 사전 검증 | 로컬에서 빠른 테스트, 터미널 친화적 | 일부 서비스만 지원, Condition 미평가 | 개발자 로컬 검증 |
| CloudTrail Lake + SQL | 대량 거부 이벤트 분석 | SQL로 패턴 분석, 장기 보관 | 초기 설정 비용, SQL 지식 필요 | 운영 환경 패턴 분석 |
어떤 도구를 먼저 써야 하나
제 경험상 가장 효율적인 조합은 CloudTrail Event Lookup으로 출발 → Policy Simulator로 가설 검증 → Access Analyzer로 보안 점검 순서예요. CloudTrail이 실제 거부가 일어난 순간을 알려주고, Policy Simulator가 정책 자체를 평가해줘서, 두 도구가 만나는 지점에서 원인이 명확해지거든요. 다른 도구들은 각각 약점이 있어서 단독으로는 부족해요. IAM Access Analyzer는 내부 호출 디버깅엔 거의 쓸모가 없고, CLI dry-run은 Condition 블록을 제대로 평가하지 않거든요.
💡 도구 조합 꿀팁
- 운영 환경에서 거부 이벤트가 많다면 EventBridge → Lambda → Slack으로 자동 알림을 구성하면, CloudTrail Lake 없이도 비슷한 효과를 얻을 수 있어요.
- Policy Simulator 결과가 Implicit Deny로만 뜨면 Allow 정책 추가가 정답이지만, Explicit Deny가 보이면 그 Deny 정책을 찾아 제거하는 게 우선이에요.
5. 정책 충돌과 우선순위 함정
IAM 정책은 한 개가 아니라 여러 종류가 동시에 평가된다는 점이 가장 혼란스러워요. 같은 호출이라도 어떤 정책에서 Deny가 먼저 걸리느냐에 따라 결과가 완전히 달라지거든요.
SCP vs IAM vs Resource Policy
평가 순서는 호출 방향에 따라 다른데, 같은 계정 안에서는 SCP → IAM Identity Policy → Resource Policy 순서로 AND 연산이 돼요. 모두 Allow여야 최종 허용이 되거든요. SCP는 계정 전체에 영향을 주는 권한 천장이라서, IAM에서 아무리 풀어도 SCP에서 막혀 있으면 그대로 거부돼요. 리소스 정책은 버킷 정책처럼 리소스 자체에 붙는 권한인데, Principal이 없는 정책은 외부 호출만 허용한다는 점을 모르는 분들이 더러 있더라고요.
Condition 블록 놓치기 쉬운 5가지
- aws:RequestedRegion — 정책에 명시된 리전이 아니면 즉시 Deny
- aws:ResourceTag — 특정 태그가 있는 리소스에만 허용, 태그 누락 시 Deny
- aws:CurrentTime — 시간 기반 정책, 만료 후 Deny
- aws:SecureTransport — HTTPS가 아닌 호출은 Deny
- aws:PrincipalTag / Session Tag — 세션에 태그가 없으면 Deny
이런 Condition 키는 정책을 JSON으로 직접 봐야만 보이기 때문에 콘솔에서 Allow로 표시되는 권한과 실제 평가 결과가 어긋나는 주요 원인이 돼요. Policy Simulator에서도 Condition 평가는 지원하거든요. Action 옆에 “Provide Request Context” 옵션이 있는데, 거기서 태그나 시간 같은 값을 미리 넣어봐야 정확한 결과를 얻을 수 있어요.
6. 실전 시나리오 3가지와 해결법
실제로 자주 마주치는 시나리오 3가지를 정리했어요. 각각 어떤 진단 절차로 해결하는지 패턴만 익혀두면 새로운 케이스에도 응용할 수 있거든요.
시나리오 A: S3 버킷 다운로드 거부
위에서 다룬 케이스와 유사한데, 버킷 정책에서 aws:SourceIp 조건이 걸려 있는 경우 VPN IP만 허용하도록 되어 있어 사내망에서만 접근 가능한 상황이 더러 있어요. 이때는 CloudTrail errorMessage에서 “explicit deny” 키워드를 찾고, 버킷 정책의 Condition을 aws:SourceVpce로 바꿔주면 VPC Endpoint 기반 제어로 마이그레이션할 수 있어요.
시나리오 B: EC2 인스턴스 프로파일 문제
EC2 안에서 AWS CLI를 실행했는데 AccessDenied가 뜨는 경우는 대부분 인스턴스에 연결된 IAM 역할이 없거나, 역할에 정책이 비어 있는 경우예요. 이때는 EC2 메타데이터(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/)로 실제 어떤 자격증명이 발급됐는지부터 확인하는 게 핵심이에요. 자격증명이 아예 없으면 IAM 역할 자체를 인스턴스에 부착해야 하고, 있다면 그 역할의 ARN을 Policy Simulator에 넣어 디버깅해요.
시나리오 C: Lambda 실행 역할 오류
Lambda 함수가 다른 AWS 서비스를 호출할 때 AccessDenied가 발생하면, 대부분 함수의 execution role이 문제예요. AWS 콘솔에서 Lambda → 구성 → 권한에서 역할 ARN을 확인하고, 그 역할에 필요한 정책이 부착돼 있는지 살펴보면 돼요. 만약 정책은 있는데도 거부된다면, resource-based policy가 호출 거부하는 경우라서 DynamoDB 테이블 정책이나 SQS 큐 정책을 별도로 봐야 해요. CloudTrail errorMessage에서 “denied by resource-based policy” 문구가 보이면 그쪽이 범인이거든요.
이 세 가지 시나리오의 공통점은 결국 “CloudTrail errorMessage를 읽고 → Policy Simulator로 가설 검증 → 실제 정책 비교”의 루프를 도는 거예요. 처음에는 어려워 보여도 한두 번만 돌려보면 패턴이 보여서, 다음부터는 거의 자동으로 진단이 가능해져요.
자주 묻는 질문
Q. CloudTrail에서 거부 이벤트가 안 보일 때는 어떻게 하나요?
A. 대부분 CloudTrail 자체가 비활성화돼 있거나, 이벤트가 다른 리전의 트레일에만 기록된 경우예요. aws cloudtrail describe-trails로 현재 활성화된 트레일을 한 번 확인해보고, 모든 리전을 커버하려면 multi-region trail을 새로 만드는 게 빠르거든요.
Q. IAM Policy Simulator가 모든 서비스를 지원하나요?
A. 대부분 주요 서비스는 지원하지만, 일부 신기능이나 비공개 액션은 평가 대상에서 빠져요. 특히 최신 출시 액션은 시뮬레이터가 아직 모르는 경우가 더러 있거든요. 결과가 “Not Supported”로 뜨면 CloudTrail 로그에 의존하는 수밖에 없어요.
Q. SCP가 멀티 계정 환경의 모든 거부 원인인가요?
A. SCP가 가장 흔하지만, 리소스 정책의 Principal 제한, VPC Endpoint 정책, KMS 키 정책도 같은 효과를 내요. 특히 KMS는 키 정책에서 명시적으로 허용하지 않으면 어떤 IAM 권한이 있어도 복호화가 거부되거든요. KMS 거부 시에는 키 정책부터 확인하는 게 우선이에요.
Q. 정책 추가 없이 즉시 진단만 하고 싶다면?
A. Read-only IAM 접근만 있는 경우에도 CloudTrail 조회와 Policy Simulator 사용은 가능해요. 다만 정책 시뮬레이터는 실제 정책 평가 결과만 알려줄 뿐 자동으로 수정해주지는 않기 때문에, 최종 정책 변경은 관리자에게 요청해야 해요.
Q. Access Analyzer는 디버깅 말고 보안 점검에도 쓸 수 있나요?
A. 네, Access Analyzer의 가장 큰 강점은 외부 계정·퍼블릭 공유 권한을 자동 탐지하는 거예요. 디버깅보다는 정기 보안 감사에 더 잘 어울리는 도구라서, 내부 AccessDenied 분석보다는 S3 버킷이 외부에 노출됐는지 점검할 때 주로 활용돼요.
IAM 권한 디버깅은 결국 “보이지 않는 곳의 Deny를 찾는 게임”이에요. 콘솔에서 보이는 Allow에 현혹되지 말고, CloudTrail errorMessage와 Policy Simulator의 Explicit/Implicit Deny 표시를 함께 읽는 습관만 들이면 같은 오류에서도 10분 안에 답이 나와요. 한 번 패턴을 익혀두면 어떤 서비스 조합에서도 응용할 수 있거든요. 지금 바로 거부 이벤트 한 건만 골라서 위 워크플로우대로 따라가 보시면 감이 확 와요.
본 글에서 소개된 AWS IAM 정책 진단 절차와 도구 활용법은 일반적인 운영 가이드 목적이며, 실제 적용 시에는 사용자의 계정 구조와 보안 정책에 따라 결과가 달라질 수 있어요. AWS 서비스 사양과 IAM 평가 로직은 AWS의 공식 문서가 항상 최신 기준이므로, 정책 수정 전 반드시 AWS 공식 문서를 함께 확인하시길 권장드려요. 본 내용은 특정 환경에서의 발생 사례를 일반화한 참고용 정보이며, 이를 근거로 한 직접적인 손실에 대해서는 책임지지 않아요.