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 규칙은 이미 걸려 있었습니다. 규칙을 한 줄씩 요청과 맞춰보니 걸리는 데가 origin 쪽과 메서드 쪽, 두 군데였습니다.
원인 1 — 와일드카드의 한 단계 라벨 매칭
기존 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 헤더가 안 붙었습니다.
원인 2 — 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가 막혔을 때 볼 두 곳 — 라벨 매칭과 메서드
CORS 가 막히면 먼저 볼 곳이 둘입니다. 하나는 origin 이 와일드카드 규칙에
진짜 매칭되는가인데, S3 의 * 는 한 라벨만 먹으니 다단계 서브도메인이면 그
단계에 맞춰 규칙을 따로 둬야 합니다. 다른 하나는 요청 메서드가
AllowedMethods 에 있는가로, presigned POST 업로드는 PUT 규칙과 별개라 POST
를 안 넣으면 서명이 맞아도 CORS 에서 걸립니다. 브라우저 에러 메시지는 “헤더가 없다” 만 말하지, 왜
안 붙였는지는 안 알려주니 규칙 매칭을 손으로 따져봐야 합니다.
댓글 0