S3 CORS — 와일드카드 한 단계와 presigned POST
사용자가 올리는 파일을 서버가 받아서 다시 S3 로 넘기지 않고 브라우저가 S3 에 바로 올리게 해둔 기능이 있었습니다. 서버는 업로드를 허가하는 presigned 요청만 만들어 주고, 실제 바이트는 브라우저 → S3 로 직접 가는 구조라, 서버 대역폭을 안 쓰고 큰 파일도 그대로 올라갑니다.
다만 브라우저가 S3 라는 다른 출처로 직접 요청을 보내는 구조라, S3 버킷 쪽 CORS 규칙에 그 출처가 허용돼 있어야 합니다. 한 번 걸어 두면 그 뒤로는 볼 일이 없는 설정이라 올려 두고 잊고 있었고, 그러다 그 업로드가 막혔습니다.
Access to fetch at '...s3...' from origin 'https://a.studio.example.com'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header
버킷에 CORS 규칙은 이미 걸려 있었으니, 그 규칙이 지금 요청과 실제로 매칭되는지를 한 줄씩 맞춰 봤습니다.
와일드카드는 한 단계 라벨만 매칭
기존 CORS 규칙의 AllowedOrigins 는 이랬습니다.
"AllowedOrigins": ["https://*.example.com"]
https://*.example.com 은 https://foo.example.com 은 매칭하지만
https://a.studio.example.com 은 매칭 안 합니다. S3 CORS 의 * 는 점 하나 사이의 한 단계
라벨만 대체해서, 두 단계(a.studio)를 한 번에 한 규칙으로 같이 처리하지 못합니다.
요청 origin 이 a.studio.example.com 이라 두 단계였고, 어떤 규칙에도 안 걸리니
Access-Control-Allow-Origin 헤더가 안 붙었습니다.
PUT만 허용한 규칙에 안 걸리는 presigned POST
origin 을 고쳐도 여전히 막혔고, 기존 규칙의 AllowedMethods 는 GET, HEAD, PUT 인데 이 기능은
presigned POST 로 올리고 있었습니다.
presigned URL 업로드에는 PUT 방식과 폼 필드로 올리는 POST 방식이 있는데, 브라우저 멀티파트
업로드에서는 후자가 흔합니다. 둘은 서로 다른 HTTP 메서드라, PUT 만 허용한 CORS 규칙에는 POST
업로드가 안 걸립니다.
해결 — 별도 규칙으로 origin과 POST를 명시
두 단계 서브도메인용 규칙을 따로 만들고 POST 를 넣었습니다.
{
"AllowedOrigins": ["https://*.studio.example.com"],
"AllowedMethods": ["POST", "PUT", "GET", "HEAD"],
"AllowedHeaders": ["*"]
}
*.studio.example.com 처럼 매칭시키고 싶은 단계에 정확히 와일드카드를 두고, 실제로 쓰는
메서드(여기선 POST)를 명시합니다.
CORS가 막혔을 때 볼 두 곳 — 라벨 매칭과 메서드
브라우저 에러 메시지는 Access-Control-Allow-Origin 헤더가 없다는 것까지만 말하고 왜 안
붙였는지는 안 알려주니, 규칙 매칭을 손으로 따져 보는 수밖에 없습니다.
볼 곳은 두 군데입니다. 먼저 요청 origin 이 와일드카드 규칙에 진짜 매칭되는지 봅니다. S3 의
* 는 한 라벨만 대체하니, 다단계 서브도메인이면 그 단계에 맞춰 규칙을 따로 둬야 합니다. 그다음은 요청
메서드가 AllowedMethods 에 있는지고, presigned POST 업로드는 PUT 규칙과 별개라 POST 를 안
넣으면 서명이 아무리 맞아도 CORS 에서 걸립니다.
댓글 0