S3의 CORS 정책을 이용하도록 CloudFront 설정하기

프론트엔드 서버와 분리되어, S3와 CloudFront를 통해 운영되는 리소스 서버가 있습니다. S3에 이미지를 업로드하고 CloudFront를 통해 다운로드하는 방식으로 구성되어 있으며 Signed Cookie를 활용하고 있습니다.
리소스 서버의 이미지가 포함된 웹페이지를 브라우저에서 열면 정상적으로 잘 보이지만, html2canvas를 이용하여 캡처하려고 하니 CORS 오류가 발생하였습니다. 이 CORS 오류를 해결하는 과정에서 얻은 경험을 공유하고자 합니다.

이 글에서 다루지 않는 내용

아래와 같은 이론적인 지식이나 기초적인 사용방법은 이 글에서 다루지 않습니다.

  • CORS의 정의와 동작 방식
  • AWS 가입 방법 및 절차
  • S3에서 CORS 설정 방법
  • CloudFront에서 OAI 설정 방법

원본 요청 정책 설정하기

CloudFront는 기본적으로 “클라이언트”로부터 받은 요청 헤더, 쿠키, 쿼리 문자열을 “원본”으로 전달하지 않습니다. 이 글에서 “클라이언트”는 웹 브라우저이고 “원본”은 S3입니다. S3의 CORS 정책을 이용하려면 최소한 origin 헤더는 S3로 전달되어야 하고, 필요에 따라 access-control-request-headers와 access-control-request-method도 전달될 수 있습니다.

CloudFront에서 설정하고자 하는 배포를 선택하고 동작 탭에서 편집 페이지로 이동합니다. 동작 편집 페이지 중간쯤에 “캐시 키 및 원본 요청”이 있고 별다른 설정을 하지 않았다면 “Cache policy and origin request policy (recommended)”가 선택되어 있을 것입니다. 그 아래에 “원본 요청 정책 – 선택 사항”이라는 항목이 있는데 아무것도 선택되어 있지 않습니다. 이 항목을 “CORS-S3Origin”으로 선택하고 저장합니다.

curl 또는 Postman을 이용하여, origin 헤더에 “http://localhost”를 포함한 HTTP GET 요청을 보냅니다. 그러면 헤더에 “Access-Control-Allow-Origin: *”이 포함된 HTTP 응답을 받을 수 있습니다. (S3에 CORS 정책이 미리 설정되어 있어야 합니다.)

여기서 끝인 줄 알았습니다. 그런데 HTTP 요청에 origin 헤더를 포함하지 않아도 HTTP 응답에 “Access-Control-Allow-Origin: *”이 포함되고 있었습니다. 아, 뭐가 문제지? 여러 번의 재시도와 구글링 끝에 알게 된 결론은, CloudFront는 기본적으로 요청 헤더에 뭐가 들어있든 상관없이 캐싱을 한다는 것입니다.

캐시 정책 설정하기

아까 설정한 동작 편집 페이지 중간쯤에 있는 “캐시 키 및 원본 요청”을 살펴봅니다. “캐시 정책”에 “CachingOptimized”가 선택되어 있습니다. 직역하면 “최적화된 캐싱”이니 이 녀석이 문제라고는 생각하지 못했습니다.

관리형 정책 중에는 쓸만한 것이 보이지 않습니다. 새로운 정책을 만들기 위해 바로 아래의 “정책 생성”을 클릭하면 새 창이 열립니다. 이름은 대충 “CachingForCORS” 정도로 써줍니다. “캐시 키 설정” 중 “헤더”에 “Origin”을 추가합니다. 다른 건 건드리지 않고 “생성” 버튼을 클릭합니다.

동작 편집 페이지로 돌아와서 “캐시 정책”을 새로고침하면 조금 전에 만든 “CachingForCORS”를 선택할 수 있습니다. 이렇게 캐시 정책을 선택하고 저장합니다.

CloudFront 배포가 완료될 때까지 몇 분 정도 기다렸다가 curl 또는 Postman을 이용하여 다시 테스트해봅니다. 이제는 HTTP 요청의 “origin” 헤더에 따라 올바른 응답을 받을 수 있습니다.

마무리

“원본 요청 정책”을 “CORS-S3Origin”으로 선택하면 “캐시 정책”도 적절히 바꿔주든 경고 메시지로 알려주든 하면 좋을텐데 오늘 이러한 삽질(?)을 경험하면서 AWS의 불친절함을 새삼 느끼게 되었습니다. 이 글을 통해 여러분들의 퇴근 시간이 조금이라도 빨라지면 좋겠습니다.

Leave a Reply

Your email address will not be published. Required fields are marked *