이 영역을 누르면 첫 페이지로 이동
Coding Groot 블로그의 첫 페이지로 이동

Coding Groot

페이지 맨 위로 올라가기

[AWS] S3를 통해 정적인 Asset 호스팅하기

Coding Groot

[AWS] S3를 통해 정적인 Asset 호스팅하기

  • 2022.08.22 17:47
  • DevOps, Infra/Cloud
글 작성자: Coding Groot

S3를 사용해서 정적인 Asset을 호스팅해보자

S3는 99.99%의 가용성을 제공해줍니다. 단순히 Asset을 업로드하는 용도로 쓸 수도 있고 웹사이트를 호스팅할 수도 있고 다양한 용도로 사용할 수 있습니다.

S3 서울 지역 요금표

Storage 요금(요청 요금은 별도)은 1TB 당 25달러 정도라 저렴합니다. 


이번 글에서는 S3를 통해 정적인 Asset을 배포해봅시다.

다음 글에서는 AWS의 CDN 서비스인 CloudFront랑 S3 bucket을 연동해서 CloudFront로 배포되도록 설정하는 것을 적어보겠습니다.

주의

이미지, 폰트처럼 변하지 않는 정적 Asset 배포용 방법입니다. 개발하면서 변하는 마크업 파일이나 정적 사이트 호스팅은 조금 다른 설정을 가져가셔야 합니다.

준비물

  • S3와 CloudFront의 권한을 가진 AWS 계정
  • 테스트용으로 호스팅할 Asset 하나 
    • 저는 coding-groot.jpeg파일 하나를 준비했습니다.

S3로 배포하는 방법

0. S3 서비스 페이지로 이동합니다.

S3를 검색합니다.

S3 검색

Bucket 페이지로 이동합니다.

Create bucket을 눌러서 Bucket 생성을 해봅시다.

1. S3에서 Bucket을 만듭니다

도메인을 붙여서 정적 호스팅할 것이라면 static.mydomainname.com 이런식으로 이름을 지어주는 것도 괜찮습니다.

버킷명과 Region을 잘 선택해줍시다

우리는 이 Bucket에 있는 것들을 외부에 공개할 것이기 때문에 Block Public Access settings for this bucket을 모두 해제합니다. 
밑에 경고로 뜨는 것도 체크하셔서 나는 이 위험성을 알고 있다는 사실을 한번 더 인증해주셔야 합니다.

버킷을 퍼블릭에 공개하도록 설정합니다.

다른 설정은 하지 않고 Create bucket을 눌러서 생성해주겠습니다.

2. Asset 업로드

그럼 만들어진 버킷에 테스트용으로 준비한 사진을 업로드합니다.

제가 방금 생성한 버킷을 눌르면 이런 창이 뜹니다.

Upload 버튼을 눌러봅시다.

업로드 창

파일로 업로드할 수도 있고 폴더로 업로드할 수 있습니다. 여기 창에 drag and drop을 해도 됩니다. 

Add files를 눌러서 이미지 하나를 올려보겠습니다.

coding-groot 이미지 하나를 선택했습니다.

Upload를 눌러서 이미지 업로드를 마무리합니다.

아래 창과 같이 Upload succeeded가 뜨면 성공입니다.

coding-groot.jpeg을 클릭해봅시다.

coding-groot.jpeg을 클릭해봅니다.

그럼 그 이미지에 대한 상세 정보가 나옵니다.

Etag, Last modified, (Content-)Type 등 HTTP 요청에서 쓰일법한 것들도 보이고 Object URL도 보고 이 자원에 관한 여러 정보들이 보입니다. 심지어 Object URL은 HTTPS로 제공해줍니다.

3. S3 Bucket 정책 설정하기

Object URL 복사해서 접속한다면 이 이미지를 바로 불러올 수 있을까요?

이미지의 Object URL에 접속시 접근할 수 없다고 뜹니다.

AccessDenied라고 뜹니다.


우리가 처음에 Block Public Access settings for this bucket을 모두 해제했지만 왜 이런 현상이 발생하는 걸까요?

Block Public Access settings for this bucket을 설정해놓는 것은 근본적으로 이 Bucket 자체를 외부에서 인터넷을 통해 접근할 수 없게 하는 것입니다.

누가 다른 작업을 하다가 실수로 "이 Asset을 공개해줘!"라고 어떤 작업을 하더라도 무조건 차단하게 됩니다.
(물론 ACL을 사용하도록 설정하면 이게 원천 차단됐더라도 다른 사람이 접근할 수 있게 할 수 있긴합니다.)

Block Public Access settings for this bucket를 모두 해제했다는 것은 "이제 너는 Pulic으로 공개될 수 있는 능력을 가졌어. 내가 막지않을게"라고 말하는 것과 비슷합니다. 

우리는 이 버킷이 외부로 공개해도 되게 설정했지만 실질적으로 외부로부터 자원에 대한 요청이 왔을 때 어떻게 하라는 것은 설정한 적이 없습니다.

정리하자면, AccessDenied가 뜬 이유는 Public에 대한 접근은 뚫어줬지만 "누가 외부에서 이 버킷의 자원인 coding-groot.jpeg에 접근했을 때 읽는 행위를 허용해줘"라는 것은 설정하지 않았기 때문입니다. 

우리는 아무런 Bucket Policy를 설정하지 않았습니다.

"누가 외부에서 버킷 자원에 접근했을 때 이런건 허용해줘" 이런 것은 S3 Bucket 정책에서 설정합니다. 이것까지 설정해줘야지 외부에서 접근해서 자원을 볼 수 있게 됩니다.

요약

  • Block Public Access settings for this bucket으로 차단
    • = 외부에서 인터넷으로 들어오는 모든 자원에 대한 요청을 원천 차단하겠다는 뜻
    • 아무리 내부적으로 공개 설정을 하든 말든 Public에서(인터넷으로) 접근 못함
      (물론 예외는 존재)
    • 정책으로 모든 사람에게 공개하도록 설정해도 Public에서(인터넷으로) 접근 불가
  • Block Public Access settings for this bucket을 해제해서 외부 접근 허용
    • = 외부에서 인터넷으로 접근하는 걸 원천 차단하진 않겠다는 뜻
    • 외부에서 요청을 받을 수 있는 상태
    • 정책을 통해 Public으로 자원을 제공해줄 수 있는 상태
      • 어떤 것을 허용할지 버킷 정책으로 설정하면 외부에서도 접근 가능
  • S3 버킷 정책 (Bucket policy)
    • 실질적으로 Bucket 자원에 대한 접근을 제어
    • "어떤 사람이 버킷 자원에 접근했을 때 이런건 허용해줘, 이런 사람에게는 이런건 허용하지마"
    • 이게 없으면 Block Public Access settings for this bucket을 해제했더라도 AccessDenied 뜸
      • 왜냐면 버킷 자원 접근에 대한 걸 정의한 게 없으니 일단 차단하는 것

그럼 버킷 정책을 설정해봅시다.

S3 Bucket으로 가서 우리가 생성한 Bucket을 클릭합니다. 그리고 Permissions 탭으로 이동합니다.

Permissions 탭

아래에 내리셔서 Bucket Policy에 Edit 버튼을 클릭합니다.

Bucket Policy의 Edit을 클릭합니다.

먼저 Bucket policy 편집창에 보시면 공백이 하나 있을텐데 그걸 지워줍니다.
(주의) space가 하나 추가로 들어가거나 오타 하나만 나도 오류가 납니다. 이것 때문에 처음에 고생 많이 합니다.

미리 공백 문자 하나 지워주세요

제가 미리 만들어둔 정책을 복붙합니다.
(Bucket Policy에 관련한 것은 https://awspolicygen.s3.amazonaws.com/policygen.html이걸 쓰시면 편합니다. 어떤게 들어가는지 금방 느낌 오실 겁니다)

복붙하실 때 "Resurce"의 자신의arn주소 부분은 BucketPolicy 상단에 떠있는 Bucket ARN을 입력하셔야 됩니다.

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "allowGetObjectCodingGroot",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "자신의arn주소/*"
}
]
}

위처럼 되셨다면 Save changes를 눌러주세요.

space가 들어가거나 comma가 마지막 필드에 남아있거나 오타가 하나라도 나면 오류가 뜰 겁니다.


이 정책을 간략하게 설명해보겠습니다.

먼저 Effect는 Allow이므로 다음에 나오는 것들을 허용하는 정책으로 사용하겠다는 의미입니다.

Action의 s3:부분은 s3와 관련된 액션이라는 것을 의미합니다. s3 액션의 GetObject는 버킷의 오브젝트를 가져오는(Read) 것을 의미합니다.

그리고 Resources에서는 어떤 오브젝트를 의미하는지 적습니다. 저는 여기에 자신의 버킷 arn주소 뒤에 "/*"을 붙이도록 했습니다.
arn은 AWS 리소스를 고유하게 식별하게 해주는 값입니다. 자신의 버킷 arn을 적었으면 자신의 bucket을 의미하게 됩니다. *은 모든 이라는 와일드 문자입니다. "버킷arn/*"은 버킷에 있는 모든 자원을 뜻하게 됩니다.

합치면 S3:GetObject를 내 버킷에 있는 모든 자원에 대하여 허용하라는 의미가 됩니다.  


이제 다 되셨으면 Save changes를 눌러줍니다.

그리고 이전에 업로드했던 이미지의 Oject URL에 다시 접속해볼까요?

이제는 잘 불러옵니다.

4. CORS 설정

우리가 이렇게 S3를 통해 정적 Asset을 호스팅하는 이유는 다른 사이트에서 이 Asset을 불러와서 사용하고 싶기 때문일겁니다. 

그렇다면 자연스럽게 CORS에 대한 걱정이 들겁니다. 

(만약 단순히 이미지 src로만 쓰거나 URL을 공유해서 다른 사람과 자원을 공유하는 용도이면 CORS 설정은 필요 없습니다.)

한번 테스트로 삼아 다른 사이트에서 크롬 console창을 열어서 AJAX요청을 보내봅시다.

CORS에 의해 막힙니다.

내가 웹사이트에서 보낸 Request

GET /static.내S3오브젝트주소.com/coding-groot.jpeg HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: ko-KR,ko;q=0.9,en;q=0.8
Cache-Control: no-cache
Connection: keep-alive
Host: s3.ap-northeast-2.amazonaws.com
Origin: https://www.내웹사이트.com
Pragma: no-cache
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36
sec-ch-ua: "Chromium";v="104", " Not A;Brand";v="99", "Google Chrome";v="104"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"

S3 호스팅 서버로부터의 Response

HTTP/1.1 200 OK
x-amz-id-2: kSlyda4xxYlqQ9gCCNakbj5Fragr2QEOkxCxIts3FCWMLXk+kE3C8tii6AbRY/BXdkm+QA=
x-amz-request-id: RYB8Q8JKSDZF
Date: Mon, 22 Aug 2022 08:24:45 GMT
Last-Modified: Mon, 22 Aug 2022 07:03:38 GMT
ETag: "dad7e1df9f3b106dfb46d352957cae88"
Accept-Ranges: bytes
Content-Type: image/jpeg
Server: AmazonS3
Content-Length: 8665

S3도 CORS 설정을 지원해줍니다. 한번 고쳐봅시다.

다시 Bucket의 Permission으로 가줍니다.

다시 버킷의 Permission 탭으로 이동

제일 아래에 Cross-origin resource sharing (CORS)에서 Edit을 눌러줍니다.

CORS 창에서 Edit을 눌러줍니다.

다음의 정책을 붙여넣습니다.

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

위의 정책으로 CORS 설정

일단 임시로 모든 Origin에 대하여 GET과 HEAD 메서드만 허용하겠습니다.

다 되셨으면 Save changes를 눌러서 저장해줍니다.

다시 한번 AJAX 요청을 보내볼까요?

다시 보낸 fetch 요청

S3 호스팅 서버로부터 받은 Response

HTTP/1.1 200 OK
Date: Mon, 22 Aug 2022 08:33:53 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: HEAD, GET
Access-Control-Expose-Headers: ETag
Last-Modified: Mon, 22 Aug 2022 07:03:38 GMT
ETag: "dad7e1df9f3b106dfb46d352957cae88"
Accept-Ranges: bytes
Content-Type: image/jpeg
Server: AmazonS3
Content-Length: 8665

우리가 설정한대로 Access Control Allow Origin 헤더값이 모든 오리진("*")으로 오네용.

따라서 CORS에 의해 차단되지도 않았습니다.

특정 사이트만 설정해볼까요?

내 웹사이트만 허용

잘 옵니다. 

S3 Response

HTTP/1.1 200 OK
Date: Mon, 22 Aug 2022 08:42:54 GMT
Access-Control-Allow-Origin: https://www.웹사이트.com
Access-Control-Allow-Methods: HEAD, GET
Access-Control-Expose-Headers: ETag
Access-Control-Allow-Credentials: true
Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method
Last-Modified: Mon, 22 Aug 2022 07:03:38 GMT
ETag: "dad7e1df9f3b106dfb46d352957cae88"
Accept-Ranges: bytes
Content-Type: image/jpeg
Server: AmazonS3
Content-Length: 8665

5. 제대로 정책 설정

S3의 장점은 정책을 세분화해서 걸 수 있다는 겁니다.

모두 허용하지 말고 내가 의도한 사이트에서만 접근 가능하도록 제대로 정책을 설정해 봅시다.

 

반응형

댓글

댓글을 사용할 수 없습니다.

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • [AWS] AWS SES API를 사용해서 메일 보내기 (feat. NodeJS)

    [AWS] AWS SES API를 사용해서 메일 보내기 (feat. NodeJS)

    2022.10.09
  • [AWS] VPC의 NAT 비용을 줄여보자 :: Ubuntu로 NAT 인스턴스 만들기

    [AWS] VPC의 NAT 비용을 줄여보자 :: Ubuntu로 NAT 인스턴스 만들기

    2022.09.25
  • [AWS] VPC에 Subnet, NAT Gateway, Internet Gateway를 구성해보자

    [AWS] VPC에 Subnet, NAT Gateway, Internet Gateway를 구성해보자

    2022.08.07
  • [AWS] NestJS 프로젝트를 Code Pipeline을 사용해서 Elastic Beanstalk으로 배포하는 법

    [AWS] NestJS 프로젝트를 Code Pipeline을 사용해서 Elastic Beanstalk으로 배포하는 법

    2022.07.22
다른 글 더 둘러보기

정보

Coding Groot 블로그의 첫 페이지로 이동

Coding Groot

  • Coding Groot의 첫 페이지로 이동

검색

메뉴

  • 홈
  • 태그
  • 방명록
  • 소개
  • 블로그 저작권

카테고리

  • 분류 전체보기 (184)
    • Git (23)
      • Git Tutorial (9)
      • Git Note (7)
      • Git Lecture (7)
    • Programming Language (1)
      • C (2)
      • C Sharp (5)
      • Java (4)
      • JavaScript (7)
      • Julia (5)
      • Python (4)
    • Programming (8)
      • Algorithm (2)
      • Compiler (5)
      • Data Structure (0)
      • Web (12)
      • NestJS (2)
    • DevOps, Infra (36)
      • Apple (6)
      • Cloud (15)
      • Database (1)
      • Network (4)
      • Linux (8)
    • Game Programming (11)
      • Unity Tutorial (5)
      • Unity Note (6)
    • Hardware Design (1)
      • Digital Circuit (1)
    • Note (49)
      • Coffee (2)
      • Retrospect (15)
      • Reading List (14)
    • Mathematics (1)

인기 글

공지사항

태그

  • aws
  • Github
  • git
  • tutorial
  • 서평
  • javascript
  • 한빛미디어
  • 회고
  • 전체 보기…

정보

Coding Groot의 Coding Groot

Coding Groot

Coding Groot

블로그 구독하기

  • 구독하기
  • RSS 피드

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기

나의 외부 링크

  • GitHub
  • SlideShare
  • 유니티 2020 수업
  • TIL Blog
  • 모도코

방문자

  • 전체 방문자
  • 오늘
  • 어제
Powered by Tistory / Kakao. Copyright © Coding Groot.

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.