Chapter 08

IAM 최소 권한 (Least Privilege)

"필요한 권한만, 필요한 리소스에만 부여하자"

학습 목표

  • IAM 최소 권한 원칙(Principle of Least Privilege)을 이해한다
  • FullAccess 정책의 위험성을 파악하고, 커스텀 정책으로 교체하는 방법을 익힌다
  • 특정 S3 버킷과 DynamoDB 테이블만 접근 가능한 커스텀 IAM 정책을 생성한다
  • FullAccess 정책을 분리(Detach)하고 커스텀 정책을 연결(Attach)한다

왜 최소 권한 원칙이 중요한가?

Chapter 04에서 EC2에 IAM 역할(ShopEasy-EC2-Role)을 연결하고, AWS 관리형 정책인 AmazonS3FullAccessAmazonDynamoDBFullAccess를 부여했습니다. 이 정책들은 빠르게 설정할 수 있어 개발 단계에서는 편리하지만, 프로덕션 환경에서는 심각한 보안 위험을 초래합니다.

FullAccess 정책의 위험성

AmazonS3FullAccess모든 S3 버킷에 대한 모든 작업을 허용합니다. 만약 EC2 인스턴스가 해킹되면, 공격자는 다음과 같은 행동이 가능합니다:

위험 시나리오FullAccess의 경우최소 권한의 경우
다른 S3 버킷 접근 계정 내 모든 버킷 읽기/쓰기/삭제 가능 shopeasy 버킷 2개만 접근 가능
다른 DynamoDB 테이블 접근 모든 테이블 읽기/쓰기/삭제 가능 Reviews 테이블만 접근 가능
데이터 유출 모든 데이터를 외부로 복사 가능 ShopEasy 리뷰 데이터만 유출 위험
데이터 삭제 모든 버킷/테이블 삭제 가능 ShopEasy 관련 데이터만 삭제 가능
피해 범위 AWS 계정 전체 ShopEasy 서비스만
비유로 이해하기: 마스터 키 vs 개별 키

FullAccess는 건물의 마스터 키와 같습니다. 이 키 하나로 모든 방(서버실, 금고, 사무실, 화장실)에 들어갈 수 있습니다. 만약 마스터 키를 도둑에게 빼앗기면? 건물 전체가 위험해집니다.

최소 권한개별 방 키를 나눠주는 것입니다. 청소부에게는 청소 도구함 키만, 경비원에게는 로비 키만, 재무팀에게는 재무실 키만 줍니다. 청소부의 키를 도둑이 가져가도, 금고나 서버실은 안전합니다.

ShopEasy EC2 서버는 리뷰 이미지 버킷프론트엔드 버킷, 그리고 Reviews 테이블에만 접근하면 됩니다. 다른 모든 리소스에 접근할 수 있는 마스터 키를 가지고 있을 이유가 없습니다.

핵심 개념: 최소 권한 원칙 (Principle of Least Privilege)

최소 권한 원칙이란, 사용자나 서비스에게 업무 수행에 필요한 최소한의 권한만 부여하는 보안 원칙입니다. AWS Well-Architected Framework의 보안 필라(Pillar)에서도 최소 권한을 핵심 원칙으로 강조합니다.

최소 권한 적용의 3가지 축:

  • Action(작업): 필요한 API 작업만 허용 (예: s3:GetObject, s3:PutObject만)
  • Resource(리소스): 특정 리소스(버킷, 테이블)만 허용 (예: shopeasy-images-* 버킷만)
  • Condition(조건): 특정 조건에서만 허용 (예: 특정 IP에서만, 특정 시간에만)

현재 상태 vs 목표 상태

현재 상태 (Chapter 04에서 설정한 것)

text
ShopEasy-EC2-Role
  +-- AmazonS3FullAccess        (AWS 관리형 정책)
  |     모든 S3 버킷, 모든 작업(s3:*) 허용
  |
  +-- AmazonDynamoDBFullAccess  (AWS 관리형 정책)
        모든 DynamoDB 테이블, 모든 작업(dynamodb:*) 허용

목표 상태 (이번 챕터에서 달성할 것)

text
ShopEasy-EC2-Role
  +-- ShopEasy-S3-Custom         (커스텀 정책)
  |     shopeasy-images-{ACCOUNT_ID} 버킷만
  |     shopeasy-frontend-{ACCOUNT_ID} 버킷만
  |     GetObject, PutObject, DeleteObject, ListBucket만 허용
  |
  +-- ShopEasy-DynamoDB-Custom   (커스텀 정책)
        Reviews 테이블만
        PutItem, GetItem, Query, Scan, DeleteItem, UpdateItem만 허용
IAM 정책 변경: FullAccess → 커스텀 정책
EC2 (ShopEasy API)
ShopEasy-EC2-Role
S3 커스텀 정책
shopeasy-images 버킷
shopeasy-frontend 버킷
Get/Put/Delete/List만
DynamoDB 커스텀 정책
Reviews 테이블만
Put/Get/Query/Scan/
Delete/UpdateItem만
커스텀 정책으로 교체하면 ShopEasy 서비스에 영향이 있을까?

아닙니다! ShopEasy가 실제로 사용하는 S3 버킷과 DynamoDB 테이블, 그리고 필요한 작업(Action)만 정확히 허용하므로, 기존 기능은 그대로 동작합니다. 불필요하게 넓은 권한만 제거하는 것입니다.

실습: IAM 최소 권한 적용

실습: ShopEasy-EC2-Role에 최소 권한 적용하기
실습 전 확인사항

이 실습을 진행하기 전에, Chapter 04에서 생성한 ShopEasy-EC2-Role이 EC2에 연결되어 있고, Chapter 05~06에서 생성한 S3 버킷과 DynamoDB 테이블이 정상 동작하는지 확인하세요.

  1. 현재 IAM 정책 확인

    먼저 ShopEasy-EC2-Role에 현재 어떤 정책이 연결되어 있는지 확인합니다.

    확인할 내용

    • 어떤 관리형 정책(Managed Policy)이 연결되어 있는가?
    • 각 정책이 어떤 권한을 부여하는가?
    • 현재 ShopEasy 서비스가 실제로 사용하는 권한은 무엇인가?
    AWS 관리형 정책 vs 커스텀 정책

    AWS 관리형 정책: AWS가 미리 만들어 제공하는 정책입니다. AmazonS3FullAccess, AmazonDynamoDBFullAccess 등이 있으며, 편리하지만 너무 많은 권한을 부여하는 경우가 많습니다.

    커스텀 정책(고객 관리형 정책): 사용자가 직접 JSON으로 작성하는 정책입니다. 필요한 Action과 Resource만 정확히 지정할 수 있어 최소 권한 원칙을 적용하기에 적합합니다.

    AWS 콘솔: IAM → Roles → ShopEasy-EC2-Role 클릭 → Permissions 탭에서 연결된 정책을 확인합니다.

    AWS CLI: aws iam list-attached-role-policies 명령어를 사용합니다.

  2. S3 커스텀 정책 생성

    ShopEasy가 실제로 사용하는 S3 버킷과 작업만 허용하는 커스텀 정책을 생성합니다.

    정책 요구사항

    • 정책 이름: ShopEasy-S3-Custom
    • 허용 버킷:
      • shopeasy-images-{ACCOUNT_ID} (리뷰 이미지 저장)
      • shopeasy-frontend-{ACCOUNT_ID} (프론트엔드 정적 파일)
    • 허용 작업(Actions):
      • s3:GetObject - 파일 읽기(다운로드)
      • s3:PutObject - 파일 쓰기(업로드)
      • s3:DeleteObject - 파일 삭제
      • s3:ListBucket - 버킷 내 파일 목록 조회
    S3 ARN 형식에 주의하세요!

    S3 리소스의 ARN은 두 가지 형식이 있습니다:

    • 버킷 자체: arn:aws:s3:::bucket-name - ListBucket에 사용
    • 버킷 내 객체: arn:aws:s3:::bucket-name/* - GetObject, PutObject, DeleteObject에 사용

    두 형식을 혼동하면 권한이 제대로 적용되지 않습니다!

    IAM 정책 JSON 구조

    IAM 정책은 JSON 형식으로 작성합니다. 기본 구조:

    json
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "설명용 이름",
          "Effect": "Allow",
          "Action": ["허용할 API 작업들"],
          "Resource": ["대상 리소스 ARN"]
        }
      ]
    }

    AWS 콘솔: IAM → Policies → Create policy → JSON 탭에서 직접 작성합니다.

    s3:GetObject, s3:PutObject, s3:DeleteObject는 버킷 내 객체에 대한 작업이므로 Resource에 /*를 붙여야 합니다. s3:ListBucket버킷 자체에 대한 작업이므로 /*를 붙이면 안 됩니다. 따라서 Statement를 2개로 나누어야 합니다.

  3. DynamoDB 커스텀 정책 생성

    ShopEasy가 실제로 사용하는 DynamoDB 테이블과 작업만 허용하는 커스텀 정책을 생성합니다.

    정책 요구사항

    • 정책 이름: ShopEasy-DynamoDB-Custom
    • 허용 테이블: Reviews (리뷰 데이터 저장)
    • 허용 작업(Actions):
      • dynamodb:PutItem - 항목 생성
      • dynamodb:GetItem - 단일 항목 조회
      • dynamodb:Query - 조건부 조회
      • dynamodb:Scan - 전체 스캔
      • dynamodb:DeleteItem - 항목 삭제
      • dynamodb:UpdateItem - 항목 수정
    • 리전: ap-northeast-2 (서울)
    DynamoDB ARN 형식

    DynamoDB 테이블의 ARN 형식은 다음과 같습니다:

    arn:aws:dynamodb:{리전}:{계정ID}:table/{테이블이름}

    예: arn:aws:dynamodb:ap-northeast-2:123456789012:table/Reviews

    계정 ID를 특정하고 싶지 않으면 *를 사용할 수 있습니다. 단, 테이블 이름은 정확히 지정합니다.

    AWS 콘솔: IAM → Policies → Create policy → JSON 탭에서 직접 작성합니다.

    DynamoDB 정책은 S3보다 간단합니다. Statement 1개로 모든 Action과 Resource를 지정할 수 있습니다. Resource에 arn:aws:dynamodb:ap-northeast-2:*:table/Reviews를 사용하세요.

  4. FullAccess 정책 교체

    이제 기존의 FullAccess 정책을 분리(Detach)하고, 새로 만든 커스텀 정책을 연결(Attach)합니다.

    작업 순서

    1. 커스텀 정책 연결: ShopEasy-S3-CustomShopEasy-DynamoDB-CustomShopEasy-EC2-Role에 연결
    2. FullAccess 정책 분리: AmazonS3FullAccessAmazonDynamoDBFullAccess를 분리
    3. 연결된 정책 확인: 커스텀 정책만 연결되어 있는지 확인
    4. 서비스 테스트: ShopEasy 서비스가 정상 동작하는지 확인
    정책 교체 순서가 중요합니다!

    반드시 커스텀 정책을 먼저 연결한 후에 FullAccess 정책을 분리하세요. 순서를 반대로 하면, 커스텀 정책을 연결하기 전에 모든 권한이 사라져서 서비스가 중단될 수 있습니다.

    서비스 동작 테스트

    정책 교체 후, ShopEasy 서비스가 정상 동작하는지 확인합니다:

    bash
    # EC2 퍼블릭 IP로 API 서버 테스트
    
    # 1. 상품 목록 조회 (RDS - IAM 정책과 무관)
    curl http://EC2_PUBLIC_IP:5000/api/products
    
    # 2. 리뷰 조회 (DynamoDB - 커스텀 정책 필요)
    curl http://EC2_PUBLIC_IP:5000/api/reviews/1
    
    # 3. S3 프론트엔드 접속 테스트
    # 브라우저에서 S3 웹사이트 URL로 접속하여 전체 서비스 테스트
    IAM 정책 변경 반영 시간

    IAM 정책 변경은 보통 즉시 또는 몇 초 이내에 반영됩니다. 하지만 EC2 인스턴스의 IAM 역할 자격증명(credentials)은 캐시되어 있어, 최대 몇 분까지 이전 권한이 유지될 수 있습니다. 테스트 시 바로 반영되지 않으면 1~2분 기다린 후 다시 시도하세요.

    AWS 콘솔: IAM → Roles → ShopEasy-EC2-Role → Permissions 탭에서 Add permissions → Attach policies로 커스텀 정책을 먼저 연결합니다. 그 후 FullAccess 정책 옆의 X 버튼으로 분리합니다.

    AWS CLI: aws iam attach-role-policy로 연결하고, aws iam detach-role-policy로 분리합니다.

확인 사항

  • ShopEasy-EC2-Role에서 AmazonS3FullAccess 정책이 분리(Detach)되었는가?
  • ShopEasy-EC2-Role에서 AmazonDynamoDBFullAccess 정책이 분리(Detach)되었는가?
  • 커스텀 정책 ShopEasy-S3-Custom이 생성되었는가?
  • S3 정책이 shopeasy-images-{ACCOUNT_ID}shopeasy-frontend-{ACCOUNT_ID} 버킷만 허용하는가?
  • S3 정책의 Action이 GetObject, PutObject, DeleteObject, ListBucket만 포함하는가?
  • 커스텀 정책 ShopEasy-DynamoDB-Custom이 생성되었는가?
  • DynamoDB 정책이 Reviews 테이블만 허용하는가?
  • DynamoDB 정책의 Action이 PutItem, GetItem, Query, Scan, DeleteItem, UpdateItem만 포함하는가?
  • 커스텀 정책이 ShopEasy-EC2-Role에 연결(Attach)되었는가?
  • 정책 교체 후 ShopEasy 서비스(상품 조회, 리뷰 작성, 이미지 업로드)가 정상 동작하는가?
이번 챕터에서 달성한 것
  • IAM 최소 권한 원칙의 중요성을 이해
  • FullAccess 관리형 정책의 위험성을 파악
  • S3와 DynamoDB용 커스텀 IAM 정책을 직접 JSON으로 작성
  • FullAccess 정책을 커스텀 정책으로 교체
  • 정책 교체 후 서비스 정상 동작을 확인

보안 개선 효과: EC2가 침해되더라도, 공격자는 ShopEasy 관련 리소스에만 접근 가능하며, 다른 S3 버킷이나 DynamoDB 테이블에는 접근할 수 없습니다. 피해 범위를 최소화하는 것이 최소 권한의 핵심입니다.