웹 서비스의 업로드 파일을 EC2 디스크에 저장하면 구현은 간단하다. 하지만 인스턴스를 교체하거나 여러 대로 늘리는 순간 각 서버가 서로 다른 파일을 갖게 된다. 이 글은 S3의 기능을 나열하기보다 언제 로컬 디스크에서 S3로 분리해야 하는지와 분리 후 무엇을 검증해야 하는지 정리한다.
IAM 정책과 PHP 업로드 구현은 별도 글인 「AWS S3와 IAM을 함께 사용하는 방법」에서 다룬다. 이 글의 역할은 저장소 선택과 AWS CLI 기반의 최소 검증이다.
1. 로컬 저장이 문제가 되는 시점
다음 조건 중 하나가 생기면 애플리케이션 서버와 파일 저장소의 분리를 검토한다.
- 로드 밸런서 뒤에서 EC2를 두 대 이상 운영한다.
- 인스턴스를 교체해도 업로드 파일이 남아야 한다.
- 배포 파일과 사용자 데이터를 서로 다른 수명 주기로 관리해야 한다.
- 파일의 보존 기간, 버전, 접근 기록을 별도로 관리해야 한다.
반대로 단일 서버의 임시 변환 파일처럼 짧게 사용하고 없어져도 되는 데이터라면 로컬 임시 디스크가 더 단순할 수 있다. 모든 파일을 무조건 S3로 옮기는 것이 목표는 아니다.
2. S3에서 폴더처럼 보이는 것은 Key prefix다
uploads/2026/08/a.png는 실제 디렉터리가 아니라 객체의 Key 문자열이다. 따라서 파일 경로를 설계할 때 사용자 입력을 그대로 Key에 넣지 않고 서버가 충돌하지 않는 이름을 생성해야 한다.
uploads/{yyyy}/{mm}/{generated-id}.{extension}
원본 파일명은 필요한 경우 별도 메타데이터나 DB에 저장한다. Key에는 개인정보, 이메일 주소와 예측 가능한 인증 토큰을 넣지 않는다.
3. 테스트 버킷 생성과 공개 차단 확인
다음 명령은 서울 리전 예시다. 버킷 이름은 전역에서 고유해야 하므로 실제로 사용할 이름으로 바꾼다.
aws s3api create-bucket \
--bucket example-private-assets \
--region ap-northeast-2 \
--create-bucket-configuration LocationConstraint=ap-northeast-2
aws s3api put-public-access-block \
--bucket example-private-assets \
--public-access-block-configuration \
BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
aws s3api get-public-access-block \
--bucket example-private-assets
설정 명령의 성공만 보지 않고 조회 결과에서 네 항목이 모두 true인지 확인한다. 다른 리전을 사용하면 버킷 생성 옵션이 달라질 수 있으므로 현재 AWS CLI 문서를 함께 확인한다.
4. 업로드·조회·삭제를 한 흐름으로 검증
printf 's3 verification\n' > s3-check.txt
aws s3api put-object \
--bucket example-private-assets \
--key checks/s3-check.txt \
--body s3-check.txt
aws s3api head-object \
--bucket example-private-assets \
--key checks/s3-check.txt
aws s3api get-object \
--bucket example-private-assets \
--key checks/s3-check.txt \
downloaded-s3-check.txt
aws s3api delete-object \
--bucket example-private-assets \
--key checks/s3-check.txt
put-object 성공만으로 검증을 끝내지 않는다. head-object로 메타데이터를 확인하고, 다시 내려받은 파일의 해시를 원본과 비교한다.
Get-FileHash .\s3-check.txt -Algorithm SHA256
Get-FileHash .\downloaded-s3-check.txt -Algorithm SHA256
두 해시가 같아야 한다. 테스트 객체는 검증 후 삭제한다.
5. 403 AccessDenied를 분류하는 순서
aws sts get-caller-identity로 현재 호출 주체를 확인한다.- 요청한 버킷 이름, 리전과 Key prefix가 맞는지 확인한다.
- IAM 정책에 필요한 Action과 정확한 Resource가 있는지 확인한다.
- Bucket Policy, 조직 SCP와 권한 경계의 명시적 Deny를 확인한다.
- KMS 암호화를 사용하면 KMS Key 권한도 확인한다.
권한 오류를 해결하려고 s3:*와 Resource: *를 추가하면 원인을 가릴 뿐 아니라 피해 범위를 키운다. 실제 업로드 정책은 필요한 버킷과 prefix로 제한한다.
6. S3가 파일 시스템을 그대로 대체하지 않는 경우
- 파일 일부를 계속 덮어쓰거나 임의 위치를 수정해야 하는 작업
- POSIX 파일 잠금과 디렉터리 연산을 전제로 한 애플리케이션
- 매우 낮은 지연 시간의 로컬 임시 작업
이 경우 EBS, EFS 또는 로컬 임시 공간과 S3를 역할별로 조합한다. S3는 객체 저장소이며 서버의 파일 시스템과 동작 방식이 같지 않다.
정리: S3 도입 여부는 “클라우드라서”가 아니라 서버 교체·수평 확장·데이터 수명 분리가 필요한지로 판단한다. 도입 후에는 공개 차단, 호출 주체, 업로드·다운로드 해시와 삭제까지 한 흐름으로 검증한다.
댓글 0