S3 버킷에 CORS 접근 허용하기

@bbearcookie · March 01, 2024 · 4 min read

서론

이미지 다운로드 버튼을 누르면 파일을 다운로드하는 기능을 구현해야 했었다.
이미지의 원본 데이터는 S3 버킷에 저장하고 있는 상태였는데 이미지 경로를 img 태그의 src 속성에 담아 보여주는 것 자체는 문제가 없었지만, 다운로드를 위해서는 파일 데이터를 ajax 요청으로 가져오고 Blob 데이터로 만들 필요성이 있었다.

따라서 S3 버킷에서 허용하는 Origin을 설정해 줄 필요성이 있었다.

a 태그의 download 속성을 이용하는 방법도 사용해보려고 했으나, 이미지가 다운로드 되는 것이 아니라 아예 이미지 경로로 redirect 되는 현상이 있어서 찾아보니 보안 이슈로 인해 동일한 출처가 아니라면 다운로드를 트리거 하지 못하도록 수정되었다고 한다.

이번 글에서는 간단하게 해결 방법을 기록해보고자 한다.

S3에 CORS 정책 추가하기

AWS 공식 문서를 살펴보면 크게 3가지의 방법이 있다고 하는데, 가장 간단한 S3 콘솔을 통한 설정을 적용해보자.

해결 방법은 아주 간단한데, S3 버킷 > 권한 > CORS(Cross-origin 리소스 공유) 에 아래 내용을 적어주면 끝이다.

[
  {
    "AllowedHeaders": ["*"],
    "AllowedMethods": ["GET", "HEAD"],
    "AllowedOrigins": ["*"],
    "ExposeHeaders": []
  }
]

S3 CORS
S3 CORS

추가 내용

alt text
alt text

그런데 며칠 후 다시 S3 버킷에 접근해보니 Access-Control-Allow-Origin 이 없다고 하는 현상이 나타났다.

로컬 환경과 배포 환경이 있었는데, 재미있는 건 로컬 환경에서 실행한 앱에서는 요청이 실패하는데 배포 환경에서 실행한 앱에서는 요청이 성공했다.
그리고 배포 환경에서 요청이 성공한 이후에는 로컬 환경에서도 요청이 성공하게 된다.

이 부분은 브라우저에 요청 결과가 캐싱이 되어서 그런건지, 혹은 Preflight 요청이 로컬 환경에서만 불가능했던건지 아리송하다.

우선 개인적인 의심으로는 Preflight 요청이 제대로 되고 있지 않다고 판단했는데 S3 CORS 설정에서 AllowedMethods 필드에는 OPTIONS 메소드를 넣을 수 없길래, 그냥 Cloudfront를 거쳐서 처리하는 방식을 알아보기로 했다.

Cloudfront에 헤더 설정하기

사실 S3 버킷에 직접 리소스를 요청하는 것 보다는 CDN을 통해서 캐싱하는 것이 비용 절감과 속도 차원에서도 유리하다보니 겸사겸사 Cloudfront를 사용했다.

우리는 Cloudfront로 들어오는 크로스 오리진 요청에 대한 처리를 해줘야 하니, Cloudfront > 배포 > 동작 에서 관련 설정을 해준다.

Cloudfront 헤더
Cloudfront 헤더

응답 헤더 정책에 CORS-With-Preflight 를 선택해준다.
참고로 이 설정은 아래와 같은 내용을 응답 헤더에 담아서 보내준다.

Managed-CORS-With-Preflight
Managed-CORS-With-Preflight

결과

이제 이미지에 대한 ajax 요청이 정상적으로 처리되고 있음을 확인할 수 있다.

요청 결과
요청 결과

References

[HTML] a 태그를 이용한 다운로드 기능
S3의 CORS 정책을 이용하도록 CloudFront 설정하기

@bbearcookie
Frontend Developer