S3에서 EC2로 파일 복사하는 방법: aws s3 cp 명령어와 IAM 권한 완전 가이드
EC2 인스턴스를 새로 띄우고 나서 S3에 올려둔 설정 파일을 내려받으려는 순간, Unable to locate credentials 오류나 Access Denied가 뜨면서 막히는 경험은 누구나 한 번쯤 겪는다. S3에서 EC2로 파일 복사하는 작업은 명령어 자체는 단순하지만, IAM 인스턴스 프로파일이 제대로 붙어 있지 않으면 자격 증명 문제로 첫 단계부터 실패한다.
TL;DR — 핵심 요약
| 항목 | 내용 |
|---|---|
| 복사 명령어 | aws s3 cp s3://버킷명/경로/파일명 /로컬/경로/ |
| 필수 IAM 액션 | s3:GetObject (단일 파일), s3:ListBucket (경로 확인 시) |
| 자격 증명 방식 | EC2 인스턴스 프로파일 (IAM Role) — 권장 |
| 자격 증명 확인 | aws sts get-caller-identity |
| 가장 흔한 실패 원인 | 인스턴스 프로파일 미연결 또는 버킷 정책의 명시적 Deny |
동작 원리: S3 파일 복사 흐름
aws s3 cp는 내부적으로 S3 REST API의 GetObject를 호출한다. EC2에서 이 호출이 성공하려면 두 가지 레이어가 모두 허용 상태여야 한다. 첫째는 IAM — 인스턴스에 연결된 Role이 해당 S3 액션을 허용해야 한다. 둘째는 S3 리소스 정책(버킷 정책) — 버킷 정책에 명시적 Deny가 있으면 IAM Allow를 덮어쓴다.
- EC2 → IMDSv2 요청: AWS CLI가 인스턴스 메타데이터 서비스(IMDS)에서 임시 자격 증명을 가져온다.
- STS 임시 자격 증명 발급: 인스턴스 프로파일에 연결된 IAM Role 기반으로 단기 토큰이 발급된다.
- S3 GetObject 호출: CLI가 해당 토큰으로 S3 엔드포인트에 요청을 보낸다.
- IAM + 버킷 정책 평가: 두 정책이 모두 Allow(또는 버킷 정책 없음)여야 객체가 반환된다.
- 파일 수신: 응답 스트림이 EC2 로컬 파일시스템에 기록된다.
사전 준비: IAM 인스턴스 프로파일 설정
EC2가 S3에 접근하는 올바른 방법은 액세스 키를 직접 발급하는 것이 아니라 IAM Role을 인스턴스 프로파일로 연결하는 것이다. 액세스 키를 EC2에 직접 심어두면 키 로테이션 부담과 유출 위험이 생긴다. 인스턴스 프로파일 방식은 STS가 자동으로 단기 자격 증명을 갱신해준다.
1단계: IAM 정책 생성
최소 권한 원칙에 따라 특정 버킷의 특정 경로에만 s3:GetObject를 허용한다. 와일드카드 버킷 권한은 피해야 한다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowGetConfigFile",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-config-bucket/configs/*"
},
{
"Sid": "AllowListBucketForPath",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::my-config-bucket",
"Condition": {
"StringLike": {
"s3:prefix": "configs/*"
}
}
}
]
}
s3:ListBucket은 aws s3 cp 단독 실행 시 필수는 아니지만, 경로가 존재하는지 확인하거나 aws s3 ls로 디버깅할 때 없으면 AccessDenied 대신 빈 결과가 반환되어 혼란을 준다. 두 액션을 함께 부여하는 것이 운영상 현실적이다.
2단계: IAM Role 생성 및 정책 연결
# IAM Role 생성 (EC2 신뢰 정책 포함)
aws iam create-role \
--role-name EC2S3ReadRole \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "ec2.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}'
# 위에서 만든 정책을 Role에 연결 (정책 ARN은 실제 생성 후 확인)
aws iam attach-role-policy \
--role-name EC2S3ReadRole \
--policy-arn arn:aws:iam::123456789012:policy/EC2S3ConfigReadPolicy
# 인스턴스 프로파일 생성
aws iam create-instance-profile \
--instance-profile-name EC2S3ReadProfile
# 프로파일에 Role 추가
aws iam add-role-to-instance-profile \
--instance-profile-name EC2S3ReadProfile \
--role-name EC2S3ReadRole
3단계: EC2 인스턴스에 프로파일 연결
인스턴스가 이미 실행 중이라면 associate-iam-instance-profile로 런타임에 연결할 수 있다. 인스턴스 재시작 없이 적용된다.
# 실행 중인 인스턴스에 프로파일 연결
aws ec2 associate-iam-instance-profile \
--instance-id i-0abcdef1234567890 \
--iam-instance-profile Name=EC2S3ReadProfile \
--region us-east-1
aws s3 cp 명령어로 S3에서 EC2로 파일 복사
인스턴스 프로파일이 연결되었다면 EC2 내부에서 아래 명령어를 실행한다. AWS CLI가 IMDS에서 자동으로 자격 증명을 가져오므로 별도 설정이 필요 없다.
단일 파일 복사
aws s3 cp s3://my-config-bucket/configs/app.conf /etc/myapp/app.conf
디렉터리 전체 복사 (재귀)
aws s3 cp s3://my-config-bucket/configs/ /etc/myapp/ --recursive
특정 리전 버킷 명시
버킷이 EC2와 다른 리전에 있거나, VPC 엔드포인트 구성에 따라 리전을 명시해야 할 때 사용한다.
aws s3 cp s3://my-config-bucket/configs/app.conf /etc/myapp/app.conf \
--region ap-northeast-2
SSE-KMS 암호화 객체 복사
버킷에 KMS 키로 서버 사이드 암호화가 적용된 경우, IAM Role에 kms:Decrypt 권한도 추가로 필요하다. 명령어 자체는 동일하지만 권한이 없으면 KMS.KmsException이 발생한다.
aws s3 cp s3://my-config-bucket/configs/secret.conf /etc/myapp/secret.conf
S3 복사는 단순해 보이지만 실제로는 IAM 평가, 버킷 정책, KMS 복호화, VPC 라우팅이 직렬로 연결된 파이프라인이다. 어느 한 레이어라도 막히면 오류 메시지는 대부분 'Access Denied' 하나로 수렴한다.
진단: 자격 증명 및 권한 확인
명령어를 실행하기 전에 인스턴스가 올바른 자격 증명을 사용하고 있는지 먼저 확인한다. 이 단계를 건너뛰면 권한 문제인지 네트워크 문제인지 구분이 안 된다.
1단계: 자격 증명 확인
인스턴스 프로파일이 제대로 붙었는지, 어떤 Role로 동작 중인지 확인한다. 여기서 IAM Role ARN이 보이지 않으면 프로파일 연결 자체가 실패한 것이다.
aws sts get-caller-identity
예상 출력:
{
"UserId": "AROAEXAMPLEID:i-0abcdef1234567890",
"Account": "123456789012",
"Arn": "arn:aws:sts::123456789012:assumed-role/EC2S3ReadRole/i-0abcdef1234567890"
}
2단계: S3 객체 접근 가능 여부 확인
실제 복사 전에 객체 메타데이터만 조회해서 권한을 검증한다. 파일을 내려받지 않고 권한만 테스트할 수 있다.
aws s3api head-object \
--bucket my-config-bucket \
--key configs/app.conf
3단계: 버킷 경로 목록 확인
s3:ListBucket 권한이 있다면 경로가 실제로 존재하는지 확인할 수 있다. 오타로 인한 'not found'와 권한 문제를 구분하는 데 유용하다.
aws s3 ls s3://my-config-bucket/configs/
- 자격 증명 없음:
get-caller-identity가 실패하면 인스턴스 프로파일 미연결. 프로파일을 연결하거나 AWS CLI 설정을 확인한다. - Access Denied (head-object): IAM 정책에
s3:GetObject가 없거나 버킷 정책이 Deny하는 경우. 두 레이어를 모두 확인한다. - NoSuchKey: 객체 경로 오타.
s3 ls로 실제 경로를 확인한다. - KMS 오류: IAM Role에
kms:Decrypt권한 추가 필요.
실제 운영에서 겪은 패턴: Access Denied의 진짜 원인
IAM 정책을 분명히 붙였는데 Access Denied가 계속 나오는 상황. 처음엔 정책 오타를 의심해서 와일드카드로 바꿔봤지만 여전히 실패했다. aws sts get-caller-identity를 돌려보니 Role ARN 자체는 정상이었다.
실제 원인은 버킷 정책이었다. 해당 버킷에 이전 팀이 설정해둔 버킷 정책에 "Effect": "Deny", "Principal": "*" 구문이 있었고, 예외 조건에 해당 Role ARN이 빠져 있었다. IAM Allow는 버킷 정책의 명시적 Deny를 절대 이길 수 없다 — 이건 AWS IAM 평가 로직의 기본 원칙이지만, 실제로 두 정책을 동시에 들여다보지 않으면 놓치기 쉽다.
버킷 정책을 확인하는 명령어:
aws s3api get-bucket-policy \
--bucket my-config-bucket \
--query Policy \
--output text
명시적 Deny가 있다면 해당 Role ARN을 예외 조건에 추가하거나, Deny 범위를 좁혀야 한다. IAM 시뮬레이터로 최종 평가 결과를 검증하는 것도 좋은 방법이다.
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:role/EC2S3ReadRole \
--action-names s3:GetObject \
--resource-arns arn:aws:s3:::my-config-bucket/configs/app.conf
VPC 환경에서의 추가 고려사항
프라이빗 서브넷에 있는 EC2는 인터넷 게이트웨이 없이 S3에 접근할 수 없다. 이 경우 S3 게이트웨이 VPC 엔드포인트를 사용하면 트래픽이 AWS 내부 네트워크를 통해 라우팅된다. 엔드포인트 정책이 별도로 설정된 경우, 엔드포인트 정책도 IAM 및 버킷 정책과 함께 평가된다.
# VPC 엔드포인트 존재 여부 확인
aws ec2 describe-vpc-endpoints \
--filters Name=service-name,Values=com.amazonaws.us-east-1.s3 \
--region us-east-1 \
--query 'VpcEndpoints[*].{ID:VpcEndpointId,State:State,Type:VpcEndpointType}'
S3에서 EC2로 파일 복사: 마무리 및 다음 단계
S3에서 EC2로 파일 복사하는 작업의 핵심은 명령어가 아니라 IAM 인스턴스 프로파일과 버킷 정책의 정합성이다. aws s3 cp 자체는 단순하지만, 그 뒤에서 IAM 평가, 버킷 정책, KMS, VPC 라우팅이 직렬로 동작한다는 점을 이해하고 있어야 오류가 났을 때 빠르게 원인을 좁힐 수 있다.
다음 단계로 고려할 수 있는 것들:
- EC2 User Data 스크립트에
aws s3 cp를 포함시켜 인스턴스 시작 시 자동으로 설정 파일을 내려받도록 구성 - 설정 파일 배포를 AWS Systems Manager Parameter Store나 Secrets Manager로 전환하는 것도 장기적으로 고려할 만하다
- S3 VPC 게이트웨이 엔드포인트 설정으로 프라이빗 서브넷에서도 안전하게 접근
관련 AWS 공식 문서: AWS CLI s3 cp 레퍼런스, IAM 정책 평가 로직
핵심 용어 정리
| 용어 | 설명 |
|---|---|
| 인스턴스 프로파일 (Instance Profile) | IAM Role을 EC2 인스턴스에 연결하는 컨테이너. EC2가 AWS 서비스에 접근할 때 사용하는 자격 증명의 출처. |
| IMDS (Instance Metadata Service) | EC2 인스턴스 내부에서 169.254.169.254로 접근하는 메타데이터 서비스. AWS CLI가 자동으로 임시 자격 증명을 여기서 가져온다. |
| 명시적 Deny (Explicit Deny) | IAM 정책 평가에서 Allow보다 우선하는 거부 규칙. 버킷 정책이나 SCP에 있으면 IAM Allow를 무효화한다. |
| S3 게이트웨이 엔드포인트 | VPC 내부에서 인터넷 없이 S3에 접근하기 위한 VPC 엔드포인트 유형. 라우팅 테이블에 자동으로 경로가 추가된다. |
| SSE-KMS | AWS KMS 키를 사용한 S3 서버 사이드 암호화. 복호화 시 kms:Decrypt 권한이 별도로 필요하다. |
댓글
댓글 쓰기