Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

58장. 사전 서명 URL과 권한 모델

이 장에서 말하고자 하는 것

사용자가 큰 파일(이미지 · 동영상) 을 업로드한다.

① 사용자 → 우리 서버 → S3
② 사용자 → S3 직접

①은 서버 트래픽과 컴퓨팅을 잡아먹는다.
②는 가장 효율적이지만 “어떻게 임시로 권한을 줄 것인가” 가 문제다.

이걸 푸는 방식이

사전 서명 URL (Presigned URL)

이다.


1. 사전 서명 URL이란

서버가 S3에 대한 임시 권한이 담긴 URL을 만들어준다.

https://msa-uploads.s3.amazonaws.com/users/123/profile.png?
  X-Amz-Algorithm=...
  &X-Amz-Credential=...
  &X-Amz-Expires=300
  &X-Amz-Signature=...
  • 5분간만 유효
  • 이 객체에 대해 PUT (또는 GET) 만 허용
  • URL을 가진 사람은 그 동안만 직접 S3 접근 가능

2. 흐름

1. 사용자: "프로필 사진 올릴 거야"
2. 서버: 사전 서명 URL 생성 → 사용자에게 전달
3. 사용자 → 그 URL로 S3에 직접 PUT
4. 서버: (선택) S3 이벤트로 후처리

서버는 데이터 자체를 들고 다니지 않는다.

  • 트래픽 절감
  • 서버 부하 절감
  • 보안: 임시 권한이라 노출 위험 적음

3. PUT 용 / GET 용

GET 용: 비공개 객체를 잠시 다운로드 가능하게
PUT 용: 임시 업로드 슬롯

GET용은 “private 영상 일시 재생” 같은 용도에 쓴다.


4. POST Policy — 더 정교한 업로드 제어

PUT 사전 서명 URL은 한 객체에 대한 단순 권한이다.

업로드 시 제약 (크기 · Content-Type · 접두사) 이 필요하면 POST Policy 를 쓴다.

허용 조건:
  - 키가 uploads/user-{id}/ 로 시작
  - Content-Type은 image/*
  - 크기 5MB 이하

위반하는 업로드는 S3가 자체적으로 거부한다.


5. S3 권한 모델 — 세 층

S3 접근은 세 층의 검사를 모두 통과해야 한다.

1. IAM 정책 (호출자가 무엇을 할 수 있는가)
2. 버킷 정책 (이 버킷이 누구에게 무엇을 허용)
3. 객체 ACL (개별 객체 권한 — 거의 안 쓴다)

그리고 Public Access Block 으로 전체 노출이 한 번 더 막힌다.

기본은 모든 게 막혀 있고, 세 층 중 하나라도 거절하면 통과 안 된다.


6. CloudFront OAC와 사전 서명 URL의 차이

항목OAC (CloudFront)사전 서명 URL
대상모든 사용자특정 사용자
캐시가능거의 불가
만료없음짧음 (분 단위)
용도정적 공개 자원비공개 / 일시 접근

정적 공개 → CloudFront + OAC
사용자별 비공개 → 사전 서명 URL


7. 우리 서비스에서

[사용자] (프로필 사진 업로드)
   ↓ POST /api/uploads/presign
[API Gateway → ECS "uploads"]
   ↓ Task Role로 S3 PutObject 권한
   ↓ presigned URL 생성
[사용자] (URL 받음)
   ↓ PUT 그 URL (S3 직접)
[S3 버킷 uploads]
   ↓ S3 이벤트
[Lambda 또는 SQS] (썸네일 생성 등)

uploads 서비스는 데이터를 만지지 않는다. “URL 발급기” 역할만.


8. 직접 확인해보기 — CLI

aws s3 presign s3://msa-uploads/users/123/profile.png --expires-in 300

--expires-in 단위는 초.

curl --upload-file ./file.png "<presigned-url>"

로 PUT 하면 파일이 올라간다.


9. 코드로는 이렇게 생겼다 — Node.js

import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

const s3 = new S3Client({ region: "ap-northeast-2" });

async function presign(key) {
  const command = new PutObjectCommand({
    Bucket: "msa-uploads",
    Key: key,
    ContentType: "image/png",
  });
  return getSignedUrl(s3, command, { expiresIn: 300 });  // 5분
}

ECS Task Role이 s3:PutObject 권한을 가지면 끝.


10. 이렇게 쓰면 망한다 — 안티패턴

안티패턴 1. 만료 시간을 길게 둔다

URL이 새어 나가면 그 시간 동안 누구나 업로드 가능.

분 단위로 짧게 — 5~15분 정도

안티패턴 2. 큰 파일을 서버를 통해 받는다

API Gateway는 페이로드 크기 제한이 있다. ECS도 큰 파일은 메모리 부담.

큰 파일은 사전 서명 URL로 사용자 → S3 직접

안티패턴 3. POST Policy 제약을 안 건다

악성 사용자가 거대한 파일을 올려 비용 폭탄을 만들 수 있다.

안티패턴 4. 사전 서명 URL을 CloudFront에 노출한다

캐시되면 만료된 URL이 계속 응답된다.


11. 한 줄로 정리

사전 서명 URL은 사용자 ↔ S3 직접 통신에 짧은 임시 권한을 주는 방식이며,
큰 파일 업로드 · 비공개 자원 접근의 표준 도구다


12. 이 장의 핵심 정리

  1. 사전 서명 URL은 임시 S3 접근 권한이 담긴 URL이다.
  2. 사용자 → S3 직접 통신으로 서버 부담을 없앤다.
  3. PUT · GET 둘 다 가능하다.
  4. 제약이 필요하면 POST Policy.
  5. 만료는 짧게 — 보통 5~15분.
  6. CloudFront OAC와는 용도가 다르다 — 공개 vs 일시 비공개.