Chapter 04 - 강사용 답안

IAM 역할 & 접근 제어

"서버에 AWS 서비스 사용 권한을 안전하게 부여하자"

이 답안에 포함된 내용

  • 각 단계별 웹 콘솔 + AWS CLI 상세 풀이
  • IAM 정책 JSON 예시 및 신뢰 정책(Trust Policy) 설명
  • CLI 명령어: aws iam create-role, aws iam attach-role-policy, aws ec2 associate-iam-instance-profile
  • 자주 발생하는 문제 및 해결 방법

Step 1: IAM 정책 확인 - S3 접근 정책

답안

웹 콘솔 방법

  1. AWS 콘솔 상단 검색창에 "IAM" 입력 후 IAM 서비스 클릭
  2. 왼쪽 메뉴에서 "정책(Policies)" 클릭
  3. 검색창에 "AmazonS3FullAccess" 입력
  4. 검색 결과에서 AmazonS3FullAccess 클릭하여 내용 확인
  5. "권한(Permissions)" 탭에서 JSON 정책 내용을 확인할 수 있음

AmazonS3FullAccess 정책의 JSON 내용:

json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:*",
                "s3-object-lambda:*"
            ],
            "Resource": "*"
        }
    ]
}

AWS CLI 방법

로컬 PC에서 AWS CLI가 설정된 경우 다음 명령어로 정책을 확인할 수 있습니다:

bash
# AmazonS3FullAccess 정책의 ARN 확인
aws iam list-policies --query "Policies[?PolicyName=='AmazonS3FullAccess'].Arn" --output text

출력 결과:

bash
arn:aws:iam::aws:policy/AmazonS3FullAccess

정책의 상세 내용을 확인하려면:

bash
# 정책 버전 확인
aws iam get-policy --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess

# 정책 문서(JSON) 확인
aws iam get-policy-version \
  --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess \
  --version-id v1
해설: AWS 관리형 정책 (Managed Policy)

AmazonS3FullAccess는 AWS가 미리 만들어 제공하는 관리형 정책입니다. 관리형 정책은 ARN이 arn:aws:iam::aws:policy/로 시작합니다.

  • "Action": ["s3:*"] - S3의 모든 작업(업로드, 다운로드, 삭제, 버킷 관리 등)을 허용
  • "Resource": "*" - 계정 내 모든 S3 리소스에 대해 허용
  • 실무에서는 이렇게 광범위한 권한을 주면 안 됩니다. Chapter 7에서 축소 예정

Step 2: IAM 정책 확인 - DynamoDB 접근 정책

답안

웹 콘솔 방법

  1. IAM 콘솔 > 정책(Policies)
  2. 검색창에 "AmazonDynamoDBFullAccess" 입력
  3. 검색 결과에서 AmazonDynamoDBFullAccess 클릭하여 확인

AmazonDynamoDBFullAccess 정책의 JSON 내용:

json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "dynamodb:*",
                "dax:*",
                "application-autoscaling:DeleteScalingPolicy",
                "application-autoscaling:DeregisterScalableTarget",
                "application-autoscaling:DescribeScalableTargets",
                "application-autoscaling:DescribeScalingActivities",
                "application-autoscaling:DescribeScalingPolicies",
                "application-autoscaling:PutScalingPolicy",
                "application-autoscaling:RegisterScalableTarget",
                "cloudwatch:DeleteAlarms",
                "cloudwatch:DescribeAlarmHistory",
                "cloudwatch:DescribeAlarms",
                "cloudwatch:DescribeAlarmsForMetric",
                "cloudwatch:GetMetricStatistics",
                "cloudwatch:ListMetrics",
                "cloudwatch:PutMetricAlarm",
                "cloudwatch:GetMetricData",
                "datapipeline:ActivatePipeline",
                "datapipeline:CreatePipeline",
                "datapipeline:DeletePipeline",
                "datapipeline:DescribeObjects",
                "datapipeline:DescribePipelines",
                "datapipeline:GetPipelineDefinition",
                "datapipeline:ListPipelines",
                "datapipeline:PutPipelineDefinition",
                "datapipeline:QueryObjects",
                "ec2:DescribeVpcs",
                "ec2:DescribeSubnets",
                "ec2:DescribeSecurityGroups",
                "iam:GetRole",
                "iam:ListRoles",
                "kms:DescribeKey",
                "kms:ListAliases",
                "sns:CreateTopic",
                "sns:DeleteTopic",
                "sns:ListSubscriptions",
                "sns:ListSubscriptionsByTopic",
                "sns:ListTopics",
                "sns:Subscribe",
                "sns:Unsubscribe",
                "sns:SetTopicAttributes",
                "lambda:CreateFunction",
                "lambda:ListFunctions",
                "lambda:ListEventSourceMappings",
                "lambda:CreateEventSourceMapping",
                "lambda:DeleteEventSourceMapping",
                "lambda:GetFunctionConfiguration",
                "lambda:DeleteFunction",
                "resource-groups:ListGroups",
                "resource-groups:ListGroupResources",
                "resource-groups:GetGroup",
                "resource-groups:GetGroupQuery",
                "resource-groups:DeleteGroup",
                "resource-groups:CreateGroup",
                "tag:GetResources",
                "kinesis:ListStreams",
                "kinesis:DescribeStream",
                "kinesis:DescribeStreamSummary"
            ],
            "Effect": "Allow",
            "Resource": "*"
        },
        {
            "Action": "cloudwatch:GetInsightRuleReport",
            "Effect": "Allow",
            "Resource": "arn:aws:cloudwatch:*:*:insight-rule/DynamoDBContributorInsights*"
        },
        {
            "Action": [
                "iam:PassRole"
            ],
            "Effect": "Allow",
            "Resource": "*",
            "Condition": {
                "StringLike": {
                    "iam:PassedToService": [
                        "application-autoscaling.amazonaws.com",
                        "application-autoscaling.amazonaws.com.cn",
                        "dax.amazonaws.com"
                    ]
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "iam:CreateServiceLinkedRole"
            ],
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "iam:AWSServiceName": [
                        "replication.dynamodb.amazonaws.com",
                        "dax.amazonaws.com",
                        "dynamodb.application-autoscaling.amazonaws.com",
                        "contributorinsights.dynamodb.amazonaws.com",
                        "kinesisreplication.dynamodb.amazonaws.com"
                    ]
                }
            }
        }
    ]
}

AWS CLI 방법

bash
# AmazonDynamoDBFullAccess 정책의 ARN 확인
aws iam list-policies --query "Policies[?PolicyName=='AmazonDynamoDBFullAccess'].Arn" --output text

출력 결과:

bash
arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess
해설: DynamoDBFullAccess에 왜 다른 서비스 권한이 포함되는가?

DynamoDBFullAccess 정책에는 DynamoDB 외에도 CloudWatch, SNS, Lambda 등의 권한이 포함되어 있습니다. 이는 DynamoDB 콘솔에서 Auto Scaling, 스트림, 알림 등 연관 기능을 사용하기 위해 필요한 권한입니다.

우리 ShopEasy 앱에 실제로 필요한 DynamoDB 권한dynamodb:PutItem, dynamodb:GetItem, dynamodb:Query, dynamodb:Scan, dynamodb:DeleteItem 정도입니다. 이것은 Chapter 7에서 최소 권한 정책을 만들 때 다루겠습니다.

Step 3: IAM 역할 생성

답안

웹 콘솔 방법

3-1. 역할 생성 시작

  1. IAM 콘솔 > 왼쪽 메뉴 "역할(Roles)" 클릭
  2. 오른쪽 상단 "역할 생성(Create role)" 클릭

3-2. 1단계 - 신뢰할 수 있는 엔터티 선택

  1. 신뢰할 수 있는 엔터티 유형: "AWS 서비스(AWS service)" 선택
  2. 서비스 또는 사용 사례(Use case): "EC2" 선택
  3. "다음(Next)" 클릭
신뢰 정책(Trust Policy)이란?

EC2를 선택하면 다음과 같은 신뢰 정책이 자동으로 생성됩니다. 이 정책은 "EC2 서비스가 이 역할을 맡을(AssumeRole) 수 있다"는 의미입니다.

json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "ec2.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

Principal이 "ec2.amazonaws.com"이므로, 오직 EC2 인스턴스만 이 역할을 사용할 수 있습니다. 다른 사용자나 서비스가 이 역할을 악용할 수 없습니다.

3-3. 2단계 - 권한 추가(Add permissions)

  1. 검색창에 "AmazonS3FullAccess" 입력 > 체크박스 선택
  2. 검색창 지우고 "AmazonDynamoDBFullAccess" 입력 > 체크박스 선택
  3. 2개 정책이 모두 선택된 것을 확인 > "다음(Next)" 클릭
정책 2개 동시 선택하기

첫 번째 정책을 체크한 후 검색어를 지우고 두 번째를 검색하면, 첫 번째 체크가 유지된 채로 두 번째를 추가 선택할 수 있습니다. 상단에 "선택된 권한 정책" 숫자가 2인지 확인하세요.

3-4. 3단계 - 이름 지정 및 검토

  1. 역할 이름: ShopEasy-EC2-Role 입력
  2. 설명(선택): ShopEasy EC2 인스턴스용 - S3, DynamoDB 접근 역할
  3. 연결된 정책 2개 확인:
    • AmazonS3FullAccess
    • AmazonDynamoDBFullAccess
  4. "역할 생성(Create role)" 클릭

"역할 ShopEasy-EC2-Role이(가) 생성되었습니다." 메시지가 나타나면 성공입니다.

AWS CLI 방법

3-1. 신뢰 정책 JSON 파일 작성

먼저 EC2가 역할을 맡을 수 있도록 하는 신뢰 정책 파일을 만듭니다:

bash
# 신뢰 정책 JSON 파일 생성
cat << 'EOF' > trust-policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "ec2.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
EOF

3-2. IAM 역할 생성

bash
# IAM 역할 생성
aws iam create-role \
  --role-name ShopEasy-EC2-Role \
  --assume-role-policy-document file://trust-policy.json \
  --description "ShopEasy EC2 인스턴스용 - S3, DynamoDB 접근 역할"

출력 예시:

json
{
    "Role": {
        "Path": "/",
        "RoleName": "ShopEasy-EC2-Role",
        "RoleId": "AROA...",
        "Arn": "arn:aws:iam::123456789012:role/ShopEasy-EC2-Role",
        "CreateDate": "2026-03-03T00:00:00+00:00",
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "Service": "ec2.amazonaws.com"
                    },
                    "Action": "sts:AssumeRole"
                }
            ]
        }
    }
}

3-3. 정책 연결 (2개)

bash
# S3 FullAccess 정책 연결
aws iam attach-role-policy \
  --role-name ShopEasy-EC2-Role \
  --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess

# DynamoDB FullAccess 정책 연결
aws iam attach-role-policy \
  --role-name ShopEasy-EC2-Role \
  --policy-arn arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess

3-4. 인스턴스 프로파일 생성 및 역할 추가

CLI에서는 인스턴스 프로파일을 별도로 만들어야 합니다

웹 콘솔에서는 역할을 만들면 같은 이름의 인스턴스 프로파일이 자동 생성됩니다. 하지만 CLI에서는 인스턴스 프로파일을 직접 만들고 역할을 추가해야 합니다.

bash
# 인스턴스 프로파일 생성
aws iam create-instance-profile \
  --instance-profile-name ShopEasy-EC2-Role

# 인스턴스 프로파일에 역할 추가
aws iam add-role-to-instance-profile \
  --instance-profile-name ShopEasy-EC2-Role \
  --role-name ShopEasy-EC2-Role

3-5. 역할 생성 확인

bash
# 역할 정보 확인
aws iam get-role --role-name ShopEasy-EC2-Role

# 연결된 정책 목록 확인
aws iam list-attached-role-policies --role-name ShopEasy-EC2-Role

연결된 정책 확인 출력 예시:

json
{
    "AttachedPolicies": [
        {
            "PolicyName": "AmazonS3FullAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonS3FullAccess"
        },
        {
            "PolicyName": "AmazonDynamoDBFullAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess"
        }
    ]
}

임시 파일 정리:

bash
# 신뢰 정책 파일 삭제
rm trust-policy.json

Step 4: EC2에 IAM 역할 연결

답안

웹 콘솔 방법

  1. EC2 콘솔로 이동 (리전: ap-northeast-2)
  2. 왼쪽 메뉴 "인스턴스(Instances)" 클릭
  3. ShopEasy EC2 인스턴스의 체크박스 선택
  4. 상단 "작업(Actions)" > "보안(Security)" > "IAM 역할 수정(Modify IAM role)" 클릭
  5. 드롭다운에서 "ShopEasy-EC2-Role" 선택
  6. "IAM 역할 업데이트(Update IAM role)" 클릭

"IAM 역할이 성공적으로 연결되었습니다" 메시지가 표시되면 완료입니다.

연결 확인

  1. 해당 인스턴스 클릭하여 상세 페이지 이동
  2. "보안(Security)" 탭 클릭
  3. "IAM 역할" 항목에 ShopEasy-EC2-Role이 표시되면 성공

AWS CLI 방법

4-1. EC2 인스턴스 ID 확인

bash
# ShopEasy EC2 인스턴스 ID 확인
# (태그 이름으로 필터링 - 인스턴스 이름에 맞게 수정하세요)
aws ec2 describe-instances \
  --region ap-northeast-2 \
  --filters "Name=tag:Name,Values=*ShopEasy*" \
  --query "Reservations[].Instances[].{ID:InstanceId,Name:Tags[?Key=='Name']|[0].Value,State:State.Name}" \
  --output table

4-2. IAM 인스턴스 프로파일 연결

bash
# EC2에 인스턴스 프로파일(IAM 역할) 연결
# <INSTANCE-ID>를 실제 인스턴스 ID로 교체하세요
aws ec2 associate-iam-instance-profile \
  --region ap-northeast-2 \
  --instance-id <INSTANCE-ID> \
  --iam-instance-profile Name=ShopEasy-EC2-Role

출력 예시:

json
{
    "IamInstanceProfileAssociation": {
        "AssociationId": "iip-assoc-0abcdef1234567890",
        "InstanceId": "i-0abcdef1234567890",
        "IamInstanceProfile": {
            "Arn": "arn:aws:iam::123456789012:instance-profile/ShopEasy-EC2-Role",
            "Id": "AIPA..."
        },
        "State": "associating"
    }
}

4-3. 연결 상태 확인

bash
# 인스턴스에 연결된 IAM 프로파일 확인
aws ec2 describe-iam-instance-profile-associations \
  --region ap-northeast-2 \
  --filters "Name=instance-id,Values=<INSTANCE-ID>"
이미 다른 역할이 연결되어 있는 경우

EC2에 이미 다른 IAM 역할이 연결되어 있으면 associate 대신 replace-iam-instance-profile-association을 사용해야 합니다:

bash
# 기존 연결의 Association ID 확인
aws ec2 describe-iam-instance-profile-associations \
  --region ap-northeast-2 \
  --filters "Name=instance-id,Values=<INSTANCE-ID>" \
  --query "IamInstanceProfileAssociations[0].AssociationId" \
  --output text

# 역할 교체
aws ec2 replace-iam-instance-profile-association \
  --region ap-northeast-2 \
  --association-id <ASSOCIATION-ID> \
  --iam-instance-profile Name=ShopEasy-EC2-Role

Step 5: EC2에서 S3 접근 권한 확인

답안

EC2에 SSH 접속 후 확인

bash
# EC2에 SSH 접속
ssh -i your-key.pem ec2-user@<EC2-PUBLIC-IP>
bash
# AWS CLI 버전 확인
aws --version

출력 예시:

bash
aws-cli/2.x.x Python/3.x.x Linux/x.x.x-xxx source/x86_64
bash
# S3 버킷 목록 조회
aws s3 ls

성공 시: S3 버킷 목록이 출력되거나, 버킷이 없으면 아무것도 출력되지 않고 프롬프트로 돌아옵니다. (에러 메시지 없음)

실패 시:

bash
Unable to locate credentials. You can configure credentials by running "aws configure".

이 에러가 나오면 IAM 역할이 아직 연결되지 않았거나, 적용되기까지 시간이 필요합니다.

추가 확인: 리전 설정

EC2에서 AWS CLI를 사용할 때 리전을 명시하지 않으면 기본 리전이 설정되지 않을 수 있습니다:

bash
# 리전을 명시적으로 지정하여 S3 조회
aws s3 ls --region ap-northeast-2

# 기본 리전 설정 (선택사항)
aws configure set region ap-northeast-2
aws configure set은 Access Key와 다릅니다

aws configure set region은 기본 리전만 설정하는 것으로, Access Key를 설정하는 것이 아닙니다. IAM Role 인증은 그대로 유지됩니다. ~/.aws/config 파일에 리전 정보만 저장됩니다.

Step 6: EC2에서 IAM 역할 확인

답안

EC2에서 STS 호출로 현재 자격증명 확인

bash
# EC2에 SSH 접속 후 실행
aws sts get-caller-identity

정상 출력 예시:

json
{
    "UserId": "AROA3EXAMPLE:i-0abcdef1234567890",
    "Account": "123456789012",
    "Arn": "arn:aws:sts::123456789012:assumed-role/ShopEasy-EC2-Role/i-0abcdef1234567890"
}

출력 결과 해석

필드 설명 확인 포인트
UserId 역할 ID + 세션 이름 AROA로 시작 (역할 기반)
Account AWS 계정 번호 본인 계정 번호와 일치
Arn 호출자의 ARN assumed-role/ShopEasy-EC2-Role 포함
해설: assumed-role의 의미

Arn에 assumed-role이 포함되어 있다는 것은, 이 EC2가 IAM 역할을 "맡아서(assume)" 사용하고 있다는 뜻입니다. Access Key를 직접 사용하는 것이 아니라, AWS STS(Security Token Service)가 발급한 임시 자격증명을 사용하고 있습니다.

임시 자격증명의 특징:

  • 유효 기간이 있음 (기본 6시간, 자동 갱신됨)
  • 탈취되더라도 시간이 지나면 자동 만료
  • CloudTrail에서 어떤 역할이 어떤 작업을 했는지 추적 가능

인스턴스 메타데이터로 역할 정보 직접 확인

EC2 내부에서 인스턴스 메타데이터 서비스(IMDS)를 통해 IAM 역할 정보를 직접 확인할 수도 있습니다:

bash
# IMDSv2 토큰 발급
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \
  -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")

# 연결된 IAM 역할 이름 확인
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/iam/security-credentials/

출력 예시:

bash
ShopEasy-EC2-Role
bash
# 해당 역할의 임시 자격증명 상세 확인
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/iam/security-credentials/ShopEasy-EC2-Role

출력 예시:

json
{
    "Code": "Success",
    "LastUpdated": "2026-03-03T00:00:00Z",
    "Type": "AWS-HMAC",
    "AccessKeyId": "ASIA...",
    "SecretAccessKey": "...",
    "Token": "...",
    "Expiration": "2026-03-03T06:00:00Z"
}
해설: 인스턴스 메타데이터 서비스(IMDS)

169.254.169.254는 EC2 인스턴스 내부에서만 접근 가능한 특수 주소입니다. AWS SDK는 이 주소에서 임시 Access Key, Secret Key, Session Token을 자동으로 가져와 사용합니다.

  • IMDSv2를 사용하여 토큰 기반 인증(PUT 요청으로 토큰 발급)을 합니다
  • 임시 자격증명은 자동으로 갱신되므로 만료를 걱정할 필요가 없습니다
  • 이것이 바로 SDK가 "코드 변경 없이" IAM Role을 사용할 수 있는 원리입니다

강의 포인트

강의 시 강조할 핵심 메시지
  1. "Access Key를 코드에 넣는 것은 집 열쇠를 현관 매트 밑에 두는 것과 같다"

    실제 사례: GitHub에 AWS Access Key가 노출되면 수분 내에 악용되어 수천만 원의 비용이 청구된 사례가 다수 있습니다. AWS는 이를 방지하기 위해 GitHub을 스캔하고 노출된 키를 자동 비활성화합니다.

  2. "IAM Role은 AWS 보안의 기본 중의 기본"

    AWS 공인 자격증(SAA, SOA 등) 시험에서도 "EC2에서 S3에 접근하는 가장 안전한 방법은?"이라는 문제가 나오면 정답은 항상 IAM Role입니다.

  3. "지금은 FullAccess지만, 실무에서는 반드시 최소 권한 원칙을 적용해야 한다"

    Chapter 7에서 커스텀 정책으로 교체할 예정이므로, 지금은 전체 흐름을 이해하는 데 집중하도록 안내합니다.

학생들이 자주 하는 질문
  • Q: IAM 역할을 연결하면 EC2를 재시작해야 하나요?
    A: 아닙니다. IAM 역할은 실행 중인 인스턴스에 바로 적용됩니다. 다만 적용까지 1-2분 정도 걸릴 수 있습니다.
  • Q: 하나의 EC2에 여러 IAM 역할을 연결할 수 있나요?
    A: 아닙니다. EC2 인스턴스에는 하나의 인스턴스 프로파일(= 하나의 역할)만 연결할 수 있습니다. 대신 하나의 역할에 여러 정책을 연결하면 됩니다.
  • Q: aws configure로 Access Key를 설정한 적이 있으면 어떻게 되나요?
    A: AWS SDK의 Credential Provider Chain에서 환경변수와 설정파일이 IAM Role보다 우선순위가 높습니다. EC2에서 ~/.aws/credentials 파일이 있으면 IAM Role이 아닌 해당 파일의 키를 사용합니다. IAM Role을 사용하려면 해당 파일을 삭제하세요.
  • Q: 로컬 개발 환경에서는 IAM Role을 어떻게 사용하나요?
    A: 로컬에서는 IAM Role을 직접 사용할 수 없습니다. 대신 aws configure로 개인 Access Key를 설정하거나, AWS SSO를 사용합니다. IAM Role은 AWS 리소스(EC2, Lambda 등)에서만 사용 가능합니다.

트러블슈팅

자주 발생하는 문제 & 해결 방법

문제 1: IAM 역할 연결 후 바로 권한이 안 됨

증상: IAM 역할을 EC2에 연결했는데 aws s3 ls에서 "Unable to locate credentials" 에러 발생

원인: IAM 역할 연결 후 EC2 인스턴스의 메타데이터 서비스에 반영되기까지 시간이 필요합니다.

해결:

  • 1~2분 기다린 후 다시 시도하세요
  • 그래도 안 되면 5분 정도 기다려보세요
  • EC2 콘솔에서 인스턴스의 "보안" 탭에 역할이 정상적으로 표시되는지 확인하세요
문제 2: AWS CLI가 설치되어 있지 않음

증상: aws: command not found

원인: EC2 인스턴스의 AMI에 따라 AWS CLI가 설치되어 있지 않을 수 있습니다.

해결:

bash
# Amazon Linux 2023 또는 Amazon Linux 2 (보통 기본 설치됨)
aws --version

# 설치되지 않은 경우 - Amazon Linux
sudo yum install -y aws-cli

# Ubuntu의 경우
sudo apt update && sudo apt install -y awscli

# 또는 최신 AWS CLI v2 수동 설치
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
문제 3: Access Denied 에러

증상: An error occurred (AccessDenied) when calling the ListBuckets operation

원인: IAM 역할에 S3 정책이 연결되지 않았거나, 다른 역할이 연결되어 있을 수 있습니다.

해결:

bash
# 먼저 어떤 역할이 사용되고 있는지 확인
aws sts get-caller-identity

# Arn에 ShopEasy-EC2-Role이 아닌 다른 역할이 나오면,
# EC2 콘솔에서 올바른 역할로 변경하세요

또한 IAM 콘솔에서 ShopEasy-EC2-Role에 AmazonS3FullAccess가 정상적으로 연결되어 있는지 확인하세요.

문제 4: 기존 ~/.aws/credentials 파일이 IAM Role을 덮어씀

증상: aws sts get-caller-identity에서 IAM Role이 아닌 IAM 사용자 ARN이 표시됨

원인: EC2에서 이전에 aws configure를 실행하여 Access Key가 저장되어 있으면, IAM Role보다 이 설정이 우선합니다.

해결:

bash
# credentials 파일 존재 여부 확인
ls -la ~/.aws/credentials

# credentials 파일이 있으면 삭제 (IAM Role을 사용하기 위해)
rm ~/.aws/credentials

# 환경변수에 Access Key가 설정되어 있는지도 확인
env | grep AWS_ACCESS
env | grep AWS_SECRET

# 환경변수가 설정되어 있으면 해제
unset AWS_ACCESS_KEY_ID
unset AWS_SECRET_ACCESS_KEY
unset AWS_SESSION_TOKEN

# 다시 확인
aws sts get-caller-identity
문제 5: "IAM 역할 수정" 메뉴가 보이지 않음

증상: EC2 콘솔에서 "작업 > 보안 > IAM 역할 수정"이 비활성화 또는 표시되지 않음

원인:

  • 인스턴스를 선택하지 않은 상태
  • 여러 인스턴스가 동시에 선택된 상태
  • IAM 콘솔 사용자에게 ec2:AssociateIamInstanceProfile 권한이 없는 경우

해결:

  • 인스턴스를 정확히 1개만 체크박스로 선택하세요
  • 인스턴스가 "실행 중(running)" 상태인지 확인하세요
  • AWS 계정의 루트 사용자 또는 관리자 권한이 있는 IAM 사용자로 로그인하세요
문제 6: CLI에서 인스턴스 프로파일 연결 시 에러

증상: An error occurred (IncorrectState) 또는 There is an existing association

원인: 이미 다른 인스턴스 프로파일이 연결되어 있습니다.

해결:

bash
# 현재 연결된 프로파일의 Association ID 확인
ASSOC_ID=$(aws ec2 describe-iam-instance-profile-associations \
  --region ap-northeast-2 \
  --filters "Name=instance-id,Values=<INSTANCE-ID>" \
  --query "IamInstanceProfileAssociations[0].AssociationId" \
  --output text)

echo "Association ID: $ASSOC_ID"

# 기존 연결 해제
aws ec2 disassociate-iam-instance-profile \
  --region ap-northeast-2 \
  --association-id $ASSOC_ID

# 잠시 대기
sleep 5

# 새 역할 연결
aws ec2 associate-iam-instance-profile \
  --region ap-northeast-2 \
  --instance-id <INSTANCE-ID> \
  --iam-instance-profile Name=ShopEasy-EC2-Role