05 CHAPTER 05 · 핵심 서비스

Amazon S3

무제한 파일 창고 — 이미지부터 정적 사이트까지

핵심 서비스 상시 무료 5GB Spring Boot 기준

S3 · 버킷 · 객체 · 스토리지 클래스 · 버전 관리 · 수명 주기 · 암호화 · 프리사인드 URL · 정적 호스팅

CHAPTER INFO
🗄가장 많이 쓰는 AWS 서비스
💰GB당 월 $0.023 (Standard)
🔗이전: CH04 ELB · Auto Scaling
🔗다음: CH06 Amazon RDS

S3란 — 서버 디스크에 저장하면 안 되는 이유

사용자가 올린 이미지를 EC2 디스크에 저장하면 어떻게 될까요? Auto Scaling으로 서버가 여러 대 떠 있을 때 한 서버에만 파일이 있습니다. 서버를 교체하면 파일이 사라집니다.

S3(Simple Storage Service)는 파일을 EC2와 분리해서 저장하는 전용 오브젝트 스토리지입니다. 서버가 몇 대든, 교체하든 파일은 S3에 안전하게 있습니다.

🗄 S3 아키텍처 — 파일 업로드 흐름
📱
클라이언트
①파일 전송
⚖️
ALB
🖥
Spring Boot
EC2
③PutObject
🗄
S3
버킷

S3 기본 구조

용어의미비유
버킷(Bucket)파일을 담는 최상위 컨테이너. 이름은 전 세계에서 유일해야 함외장 하드
객체(Object)버킷에 저장된 파일. 파일 본체 + 메타데이터파일
키(Key)객체의 이름(경로). images/2024/photo.jpg파일 경로

스토리지 클래스 — 비용 최적화

파일마다 접근 빈도가 다릅니다. 자주 쓰는 파일은 빠른 스토리지에, 거의 안 쓰는 파일은 저렴한 아카이브에 두면 비용을 크게 줄일 수 있습니다.

클래스접근 빈도저장 비용조회 비용용도
Standard자주$0.023/GB없음이미지, 정적 파일
Standard-IA가끔$0.0125/GB있음백업, 로그
Glacier거의 없음$0.004/GB높음·느림장기 아카이브
Intelligent-Tiering패턴 불명자동자동접근 패턴 불규칙 시

S3 권한 — 퍼블릭 액세스 차단

S3 버킷은 기본적으로 모든 퍼블릭 액세스가 차단돼 있습니다. 이 설정을 절대 끄지 마세요.

🚨
퍼블릭 버킷으로 인한 데이터 유출 사고가 실제로 많습니다
"일단 열어두고 나중에 닫자"는 생각이 사고로 이어집니다. 파일을 공개해야 한다면 퍼블릭 버킷 대신 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;
    }
}

프리사인드 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로 서비스할 수 있습니다.

  1. 버킷 생성 — 퍼블릭 액세스 차단 유지
  2. 빌드 결과물 업로드 (npm run builddist/)
  3. 속성 탭 → 정적 웹사이트 호스팅 활성화 → 인덱스 문서: index.html
  4. CloudFront 배포 → 원본: S3 버킷 → OAC 설정 (다음 챕터에서 상세 다룸)
📌 CH05 핵심 개념 요약
S3 용도이미지·파일을 EC2와 분리 저장. 서버 교체·스케일링에 영향 없음
퍼블릭 액세스 차단기본값 유지. 절대 끄지 말 것. 필요하면 CloudFront+OAC 또는 프리사인드 URL
IAM 역할EC2에 역할 부여 → 코드에 키 없이 S3 접근. 액세스 키 코드 삽입 금지
프리사인드 URL비공개 파일을 시간 제한으로 공개. 서버가 URL 생성, 클라이언트가 직접 S3에서 다운로드
스토리지 클래스Standard→IA→Glacier 순으로 저렴. 수명 주기 정책으로 자동 이동 가능