01
S3란 — 서버 디스크에 저장하면 안 되는 이유
사용자가 올린 이미지를 EC2 디스크에 저장하면 어떻게 될까요? Auto Scaling으로 서버가 여러 대 떠 있을 때 한 서버에만 파일이 있습니다. 서버를 교체하면 파일이 사라집니다.
S3(Simple Storage Service)는 파일을 EC2와 분리해서 저장하는 전용 오브젝트 스토리지입니다. 서버가 몇 대든, 교체하든 파일은 S3에 안전하게 있습니다.
🗄 S3 아키텍처 — 파일 업로드 흐름
클라이언트
①파일 전송
ALB
②
Spring Boot
EC2
EC2
③PutObject
S3
버킷
버킷
S3 기본 구조
| 용어 | 의미 | 비유 |
|---|---|---|
| 버킷(Bucket) | 파일을 담는 최상위 컨테이너. 이름은 전 세계에서 유일해야 함 | 외장 하드 |
| 객체(Object) | 버킷에 저장된 파일. 파일 본체 + 메타데이터 | 파일 |
| 키(Key) | 객체의 이름(경로). images/2024/photo.jpg | 파일 경로 |
02
스토리지 클래스 — 비용 최적화
파일마다 접근 빈도가 다릅니다. 자주 쓰는 파일은 빠른 스토리지에, 거의 안 쓰는 파일은 저렴한 아카이브에 두면 비용을 크게 줄일 수 있습니다.
| 클래스 | 접근 빈도 | 저장 비용 | 조회 비용 | 용도 |
|---|---|---|---|---|
| Standard | 자주 | $0.023/GB | 없음 | 이미지, 정적 파일 |
| Standard-IA | 가끔 | $0.0125/GB | 있음 | 백업, 로그 |
| Glacier | 거의 없음 | $0.004/GB | 높음·느림 | 장기 아카이브 |
| Intelligent-Tiering | 패턴 불명 | 자동 | 자동 | 접근 패턴 불규칙 시 |
03
S3 권한 — 퍼블릭 액세스 차단
S3 버킷은 기본적으로 모든 퍼블릭 액세스가 차단돼 있습니다. 이 설정을 절대 끄지 마세요.
퍼블릭 버킷으로 인한 데이터 유출 사고가 실제로 많습니다
"일단 열어두고 나중에 닫자"는 생각이 사고로 이어집니다. 파일을 공개해야 한다면 퍼블릭 버킷 대신 CloudFront + OAC 조합이나 프리사인드 URL을 쓰세요.
"일단 열어두고 나중에 닫자"는 생각이 사고로 이어집니다. 파일을 공개해야 한다면 퍼블릭 버킷 대신 CloudFront + OAC 조합이나 프리사인드 URL을 쓰세요.
IAM 역할 vs 액세스 키
EC2에서 S3에 파일을 올리려면 권한이 필요합니다. 액세스 키를 코드에 넣는 방식은 절대 안 됩니다. EC2에 IAM 역할을 붙이면 코드에 키 없이도 동작합니다.
✅ 올바른 방식 — IAM 역할 사용
// application.yml — 키 설정 없음
cloud:
aws:
region:
static: ap-northeast-2
# EC2에 IAM 역할이 붙어 있으면 자격증명 자동 주입
// S3Service.java
@Service
public class S3Service {
private final AmazonS3 s3; // IAM 역할로 자동 인증
public String upload(MultipartFile file) {
String key = "uploads/" + UUID.randomUUID() + "_" + file.getOriginalFilename();
s3.putObject(bucketName, key, file.getInputStream(), metadata);
return key;
}
}
04
프리사인드 URL — 비공개 파일을 안전하게 제공
버킷은 비공개로 두면서 특정 파일을 일정 시간만 공개하고 싶을 때 씁니다. 서버가 서명된 URL을 생성하고, 클라이언트는 그 URL로 직접 S3에서 파일을 받습니다.
🔑 프리사인드 URL 흐름
// 프리사인드 URL 생성 (15분 유효)
public String getPresignedUrl(String key) {
Date expiration = new Date(System.currentTimeMillis() + 15 * 60 * 1000);
GeneratePresignedUrlRequest request =
new GeneratePresignedUrlRequest(bucketName, key)
.withExpiration(expiration);
return s3.generatePresignedUrl(request).toString();
}
// 생성된 URL 예시
https://my-bucket.s3.ap-northeast-2.amazonaws.com/uploads/photo.jpg
?X-Amz-Algorithm=AWS4-HMAC-SHA256
&X-Amz-Expires=900
&X-Amz-Signature=abc123...
실습
S3 정적 웹 호스팅
React, Vue로 만든 프론트엔드는 빌드하면 HTML·CSS·JS 파일이 됩니다. 서버 없이 S3 + CloudFront로 서비스할 수 있습니다.
- 버킷 생성 — 퍼블릭 액세스 차단 유지
- 빌드 결과물 업로드 (
npm run build의dist/) - 속성 탭 → 정적 웹사이트 호스팅 활성화 → 인덱스 문서:
index.html - CloudFront 배포 → 원본: S3 버킷 → OAC 설정 (다음 챕터에서 상세 다룸)
📌 CH05 핵심 개념 요약
S3 용도이미지·파일을 EC2와 분리 저장. 서버 교체·스케일링에 영향 없음
퍼블릭 액세스 차단기본값 유지. 절대 끄지 말 것. 필요하면 CloudFront+OAC 또는 프리사인드 URL
IAM 역할EC2에 역할 부여 → 코드에 키 없이 S3 접근. 액세스 키 코드 삽입 금지
프리사인드 URL비공개 파일을 시간 제한으로 공개. 서버가 URL 생성, 클라이언트가 직접 S3에서 다운로드
스토리지 클래스Standard→IA→Glacier 순으로 저렴. 수명 주기 정책으로 자동 이동 가능