Presigned URL (사전 서명 URL)
Presigned URL은 S3 개념 ↗︎으로, API 자격 증명을 노출하지 않고 객체에 임시 접근 권한을 부여하는 방법이에요. presigned URL은 서명 파라미터를 URL 자체에 포함해서, URL을 가진 누구든지 만료 전까지 특정 객체에 대해 특정 작업(예: GetObject나 PutObject)을 수행할 수 있게 해 줘요.
출처: 문서
본문
사용자가 파일을 R2에 직접 업로드하게 하거나, 시간 제한이 있는 다운로드 링크를 제공하는 것처럼 특정 객체에 임시 접근을 부여하기에 딱 맞는 방식이에요.
presigned URL을 생성하려면 다음을 지정해요:
- 리소스 식별자: 계정 ID, 버킷 이름, 객체 경로
- 작업: 허용되는 S3 API 작업(GET, PUT, HEAD, DELETE)
- 만료 시간: 1초에서 7일(604,800초) 사이의 타임아웃
presigned URL은 R2와 통신하지 않고 서버 측에서 생성돼요. 필요한 것은 R2 API 자격 증명과 AWS Signature Version 4 서명 알고리즘 구현뿐이에요.
접근 방식 고르기
R2는 시간 제한 접근을 위한 두 가지 패턴을 지원해요. 두 패턴은 겹치지만 장단점이 달라요:
| 패턴 | 부여 내용 | 적합한 경우 |
|---|---|---|
| Presigned URL(이 페이지) | 단일 객체에 대한 단일 S3 작업 | S3 클라이언트 없이 단일 객체에 직접 HTTP 접근을 부여할 때(예: 브라우저 업로드, 공유 가능한 다운로드 링크) |
| 임시 자격 증명 | 버킷과 허용 작업 집합에 범위가 제한되고, 선택적으로 특정 경로로 제한된 여러 S3 작업 | 표준 S3 클라이언트나 SDK로 범위가 제한된 세션에서 여러 작업을 수행하는 호출자 |
Presigned URL 생성
사전 요구사항
SDK 예시
import { S3Client, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
const S3 = new S3Client({
region: "auto", // Required by SDK but not used by R2
// Provide your Cloudflare account ID
endpoint: `https://<ACCOUNT_ID>.r2.cloudflarestorage.com`,
// Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)
credentials: {
accessKeyId: '<ACCESS_KEY_ID>',
secretAccessKey: '<SECRET_ACCESS_KEY>',
},
});
// Generate presigned URL for reading (GET)
const getUrl = await getSignedUrl(
S3,
new GetObjectCommand({ Bucket: "my-bucket", Key: "image.png" }),
{ expiresIn: 3600 }, // Valid for 1 hour
);
// https://my-bucket.<ACCOUNT_ID>.r2.cloudflarestorage.com/image.png?X-Amz-Algorithm=...
// Generate presigned URL for writing (PUT)
// Specify ContentType to restrict uploads to a specific file type
const putUrl = await getSignedUrl(
S3,
new PutObjectCommand({
Bucket: "my-bucket",
Key: "image.png",
ContentType: "image/png",
}),
{ expiresIn: 3600 },
);
import boto3
s3 = boto3.client(
service_name="s3",
# Provide your Cloudflare account ID
endpoint_url='https://<ACCOUNT_ID>.r2.cloudflarestorage.com',
# Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)
aws_access_key_id='<ACCESS_KEY_ID>',
aws_secret_access_key='<SECRET_ACCESS_KEY>',
region_name="auto", # Required by SDK but not used by R2
)
# Generate presigned URL for reading (GET)
get_url = s3.generate_presigned_url(
'get_object',
Params={'Bucket': 'my-bucket', 'Key': 'image.png'},
ExpiresIn=3600 # Valid for 1 hour
)
# https://my-bucket.<ACCOUNT_ID>.r2.cloudflarestorage.com/image.png?X-Amz-Algorithm=...
# Generate presigned URL for writing (PUT)
# Specify ContentType to restrict uploads to a specific file type
put_url = s3.generate_presigned_url(
'put_object',
Params={
'Bucket': 'my-bucket',
'Key': 'image.png',
'ContentType': 'image/png'
},
ExpiresIn=3600
)
# Generate presigned URL for reading (GET)
# The AWS CLI presign command defaults to GET operations
aws s3 presign --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com \
s3://my-bucket/image.png \
--expires-in 3600
# Output:
# https://<ACCOUNT_ID>.r2.cloudflarestorage.com/my-bucket/image.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...
# Note: The AWS CLI presign command only supports GET operations.
# For PUT operations, use one of the SDK examples above.
완전한 예시와 추가 작업은 SDK별 문서를 참고해 주세요:
모범 사례
presigned URL을 생성할 때 다음으로 남용과 오용을 제한할 수 있어요:
- Content-Type 제한: SDK 파라미터에서 허용할
Content-Type을 지정해요. 서명에 이 헤더가 포함되므로, 클라이언트가 업로드 요청에서 다른Content-Type을 보내면403/SignatureDoesNotMatch오류로 업로드가 실패해요. - CORS 구성: presigned URL을 브라우저에서 사용한다면, 어떤 오리진이 요청할 수 있는지 제어하도록 버킷에 CORS 규칙을 설정해요.
Presigned URL 사용
생성한 presigned URL은 다른 HTTP 엔드포인트처럼 사용하면 돼요. 서명이 URL에 포함되어 있으므로 추가 인증 헤더는 필요 없어요.
# Download using a GET presigned URL
curl "https://my-bucket.<ACCOUNT_ID>.r2.cloudflarestorage.com/image.png?X-Amz-Algorithm=..."
# Upload using a PUT presigned URL
curl -X PUT "https://my-bucket.<ACCOUNT_ID>.r2.cloudflarestorage.com/image.png?X-Amz-Algorithm=..." \
--data-binary @image.png
웹 브라우저, 모바일 앱, 또는 어떤 HTTP 클라이언트에서도 presigned URL을 직접 사용할 수 있어요. 같은 presigned URL은 만료되기 전까지 여러 번 재사용할 수 있어요.
Presigned URL 예시
다음은 R2 API 자격 증명으로 AWS Signature Version 4 서명 과정을 따라 만든 presigned URL 예시예요:
https://my-bucket.123456789abcdef0123456789abcdef.r2.cloudflarestorage.com/photos/cat.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=CFEXAMPLEKEY12345%2F20251201%2Fauto%2Fs3%2Faws4_request&X-Amz-Date=20251201T180512Z&X-Amz-Expires=3600&X-Amz-Signature=8c3ac40fa6c83d64b4516e0c9e5fa94c998bb79131be9ddadf90cefc5ec31033&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject
이 예시에서 이 presigned URL은 ID가 123456789abcdef0123456789abcdef인 계정의 my-bucket 버킷 안의 photos/cat.png 객체에 대해 GetObject를 수행해요. 이 presigned URL을 구성하는 핵심 서명 파라미터는 다음과 같아요:
X-Amz-Algorithm: URL 서명에 사용된 알고리즘을 식별해요.X-Amz-Credential: 서명 계산에 사용된 자격 증명 정보를 담고 있어요.X-Amz-Date: 서명이 생성된 날짜와 시간(ISO 8601 형식)이에요.X-Amz-Expires:X-Amz-Date부터 계산한 presigned URL의 유효 기간(초)이에요.X-Amz-Signature: 비밀 키로 URL이 서명되었음을 증명하는 서명이에요.X-Amz-SignedHeaders: 서명 계산에 포함된 HTTP 헤더 목록이에요.
참고
서명 파라미터(예: X-Amz-Algorithm, X-Amz-Credential, X-Amz-Date, X-Amz-Expires, X-Amz-Signature)는 변조할 수 없어요. 리소스, 작업, 또는 만료 시간을 수정하려 하면 403/SignatureDoesNotMatch 오류가 발생해요.
지원되는 작업
R2는 다음 HTTP 메서드에 대해 presigned URL을 지원해요:
GET: 버킷에서 객체 가져오기HEAD: 버킷에서 객체 메타데이터 가져오기PUT: 버킷에 객체 업로드DELETE: 버킷에서 객체 삭제
POST(HTML 폼을 통한 multipart 폼 업로드)는 현재 지원되지 않아요.
보안 고려사항
presigned URL은 bearer 토큰처럼 취급해요. URL을 가진 사람이라면 누구든 만료 전까지 지정된 작업을 수행할 수 있어요. presigned URL은 의도한 수신자에게만 공유하고, 민감한 작업에는 짧은 만료 시간을 고려해 주세요.
커스텀 도메인
presigned URL은 S3 API 도메인(<ACCOUNT_ID>.r2.cloudflarestorage.com)에서만 동작하며, 커스텀 도메인에서는 사용할 수 없어요.
커스텀 도메인(퍼블릭 버킷)으로 접근하는 R2 버킷에 인증이 필요하다면 WAF HMAC 검증 기능을 사용해 주세요(Pro 플랜 이상 필요).
관련 리소스
R2 API 토큰
presigned URL 생성을 위한 자격 증명을 만들어요.
퍼블릭 버킷
인증 없이 공개 읽기 접근을 제공하는 대안 방식이에요.
Workers의 R2 바인딩
내장 인증으로 서버 측 R2 접근을 위한 대안이에요.
사용자 생성 콘텐츠 저장
R2로 사용자 업로드를 처리하는 아키텍처 가이드예요.
더 알아보기 (Learn more)
- 임시 자격 증명 — 여러 S3 작업을 위한 시간 제한 접근
- R2 API 토큰 — presigned URL 생성을 위한 자격 증명
- R2 예시: AWS SDK — SDK별 presigned URL 예시