Post

[AWS] 웹에서 S3 파일 제어(CRUD) - 1. API Gateway 사용하기

목표

AWS 서비스인 API Gateway를 사용해 S3 파일 제어(CRUD)

 

AWS Management Console 설정하기

AWS 회원가입을 완료하면, 가장 먼저 AWS 관리 콘솔창이 나옵니다. 관리 콘솔창은 위젯을 통해 내가 자주 찾는 서비스나, 최신 AWS 뉴스 등 나에게 필요한 정보를 한눈에 볼 수 있는 창인데, 여러 가지 위젯을 추가/제거해서 내 용도에 맞게 커스터마이징 할 수 있습니다. 저 같은 경우 Favorites라는 위젯에 S3, API Gateway, IAM을 추가해 바로가기 경로를 만들었고, 그 외에 따로 건드린 부분은 없었습니다.

AWS 관리 콘솔창

 

S3 버킷 추가하기

S3에는 버킷(Bucket)이라는 개념이 있습니다. 버킷은 S3 파일을 그룹으로 묶는 일종의 컨테이너(폴더)인데, API Gateway를 통해 외부에서 접근하기 위해서는 버킷별로 개별적인 접근 권한을 부여해야 합니다. 버킷을 추가하기 위해 S3로 이동해 Create bucket 버튼을 클릭합니다.

S3

 

버킷 생성을 위해서는 Bucket name과 Region을 선택해야 합니다. Bucket name은 원하시는 폴더명을, Region은 서비스가 주로 사용될 지역을 선택하면 됩니다. 한글 서비스의 경우 아무래도 한국에서 접근하는 경우가 많기 때문에 Asia Pacific (Seoul) ap-northeast-2를 선택하는게 속도 면에서 더 유리할 것으로 예상됩니다. 선택을 완료하고 스크롤을 내리면 Block public access 섹션이 나오는데, 외부에서 S3 파일에 접근할 것이기 때문에 Block public access를 비활성화해 외부에서의 접근을 허용합니다. 설정이 모두 완료되면 Create bucket 버튼을 클릭해 버킷 생성을 완료합니다.

S3 - Create bucket

 

버킷 생성을 완료하면 CORS 허용을 위해 해당 버킷의 Permissions 페이지로 이동합니다. 스크롤을 맨 아래로 내리면 CORS를 설정하는 섹션이 나오는데, AllowedOrigins에 내 로컬 IP와 프로덕션 IP를 추가해 줍니다.

CORS란?

Cross Origin Resource Sharing의 약자로 웹페이지의 도메인과 API의 도메인이 다를 경우 API 요청을 차단하는 일종의 보안 정책입니다. 예를 들어, https://taedonn.com에서 http://aws.com/api/s3-upload에 리소스 요청을 했다면, 두 URL의 도메인이 다르기 때문에 리소스 요청은 차단됩니다. 그렇기 때문에 외부에서 API에 접근하기 위해서는 CORS를 반드시 허용해야 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "PUT",
            "POST",
            "DELETE",
            "GET"
        ],
        "AllowedOrigins": [
            "http://localhost:3000", // 로컬 IP
            "https://taedonn.com"    // 프로덕션 IP
        ],
        "ExposeHeaders": []
    }
]

 

IAM

AWS를 설정할 때 가장 헷갈렸던 부분입니다. IAM은 Identity and Access Management의 약자로 말 그대로 사용자의 접근 권한을 관리하는 서비스입니다. AWS는 처음 회원 가입을 완료하면 그 즉시 모든 서비스에 대한 접근 권한이 생기는 개념이 아니라, 가입 후 IAM을 통해 사용자를 추가해 사용자별로 개별 서비스에 대한 접근 권한을 부여해 주는 개념입니다. 아마 개인보다 회사에서 많이 사용하는 서비스라 권한을 나누어서 보안을 강화하겠다는 취지가 아닐까 생각이 됩니다.

먼저 왼쪽 사이드 메뉴의 Roles로 들어간 후 오른쪽의 Create role 버튼을 클릭합니다.

IAM - Create role

 

Trusted entity type은 AWS Service를 선택하고, Use case는 API Gateway 선택합니다(검색창에 검색하면 나옴). 선택을 모두 완료하면 Next 버튼을 눌러 다음 페이지로 이동합니다.

IAM - Trusted entity

 

다음 페이지는 Permission을 추가하는 페이지입니다. 이미 이전 페이지에서 API Gateway를 선택했기 때문에 따로 설정할 필요 없이 Next 버튼을 눌러 다음 페이지로 이동합니다(스크린샷 X). 다음 페이지로 이동하면 Role의 이름을 정하는 페이지가 나오는데, api-gateway-upload-to-s3처럼 직관적으로 기억할 수 있는 이름을 정한 후, 맨 밑의 Create 버튼을 눌러 Role을 생성합니다.

IAM - Name, review and create

 

Role에 S3 권한 추가하기

이제 Role에 S3 권한을 추가해야 합니다. IAM > Roles로 들어가면 방금 생성한 Role이 목록에 추가되어 있는데, 클릭해서 상세 페이지로 이동합니다.

IAM - Roles

 

상세 페이지 오른쪽의 Add permission 드롭 다운 메뉴에서 Create inline policy를 선택합니다.

IAM - Edit role

 

사용할 서비스의 접근 권한을 Role에 추가하는 페이지가 나옵니다. GetObject(읽기), DeleteObject(삭제), PutObject(업로드), 총 3가지의 정책을 Role에 추가해야 합니다. 정책 추가를 위해 Policy editor에서 S3를 선택합니다.

IAM - Create policy

 

S3를 선택하면 나오는 검색창에 GetObject를 검색합니다. 검색해서 나온 GetObject를 체크한 후, PutObject, DeleteObject도 똑같은 방식으로 체크하고 Add Arn 버튼을 클릭합니다.

ARN이란?

Amazon Resource Names의 약자로 리소스를 고유하게 식별하는 ID입니다. API 호출과 같이 리소스를 명확하게 지정해야 하는 경우 사용합니다.

IAM - Add GetObject

 

Add Arn 버튼을 클릭하면 모달창이 나옵니다. Bucket name을 입력하는 칸에는 이전에 S3에 추가한 버킷명을, Object name을 입력하는 칸에는 아무것도 입력하지 않고 바로 위의 Any object name을 체크합니다. 설정이 모두 완료되면 Add ARNs 버튼을 클릭해 ARN을 생성합니다.

IAM - Add ARNs

 

ARN을 추가하고 나면 다음 페이지로 이동합니다. Policy 이름을 정하는 페이지가 나오는데, 이름을 정하고 나면 Create policy 버튼을 눌러 정책을 생성합니다. 여기까지 완료했다면, IAM 설정은 모두 마쳤습니다.

IAM - Create policy

 

API Gateway

먼저 API Gateway 콘솔로 들어갑니다. 콘솔로 들어가면 사이드 메뉴의 APIs로 들어가 Create API 버튼을 누릅니다.

API Gateway

 

API 타입을 정하는 페이지가 나옵니다. REST API를 선택해 줍니다.

API Gateway - API Type

 

API 이름을 정하는 페이지가 나오는데, 이름을 정하고 나면 다른 설정값은 그대로 두고 Create API 버튼을 눌러 API를 생성합니다.

API Gateway - Create API

 

리소스 경로 설정하기

이제 생성한 API에 Action을 추가해 줄 겁니다. Action은 Method 별로 요청이 왔을 때 어떤 행동을 할지를 정해주는 일종의 행동 규칙입니다. 먼저 사이드 메뉴의 APIs로 들어가 방금 추가한 API를 클릭합니다. Resources의 Actions 드롭다운 메뉴에서 Create Resource를 클릭하면 리소스 생성 페이지가 나오는데, Resource name에는 folder를, Resource path에는 {folder}를 입력합니다. 입력을 완료하면 Create resource 버튼을 눌러 리소스를 생성합니다.

API Gateway - Create Resource

 

그 후 다시 Create Resources를 눌러 이번에는 Resource name에는 object를, Resource path에는 {object}를 입력해 리소스를 하나 더 생성합니다. 이렇게 설정하고 나면 API에서 접근할 S3의 경로는 {folder(버킷명)}/{object(파일명)}이 됩니다. 만약 버킷 안에 하위 버킷을 하나 더 만들고 하위 버킷에 파일을 저장하겠다고 하면, 리소스를 하나 더 생성해 {folder}/{folder}/{object}로 리소스 경로를 지정하면 됩니다.

API Gateway - Create Resource

 

Method 설정하기

리소스 경로를 모두 설정한 후, 다시 Actions 드롭다운 메뉴에서 이번에는 Create Method를 선택합니다. /{object} 이래에 칸이 하나 생기는데, 여기서 PUT을 선택합니다.

API Gateway - Create Method

 

이제 PUT Method의 초기 설정을 해야 합니다. 초기 설정값은 다음과 같습니다.

  • Integration type: AWS Service
  • AWS Region: 버킷 설정 시 설정한 Region과 동일하게 설정
  • AWS Service: Simple Storage Service (S3)
  • HTTP method: PUT
  • Action Type: Use path override
  • Path override (optional): {bucket}/{key}
  • Execution role: 내 IAM Role의 ARN값
  • Content handling: Passthrough

API Gateway - PUT Method

 

Execution role의 ARN값은 IAM > Roles > 내 Role의 상세 페이지에서 확인할 수 있습니다. ARN은 내 Role의 고유 식별자이기 때문에 아무와도 공유하면 안 됩니다.

IAM - ARN

 

다시 API Gateway로 돌아와서 PUT Method를 클릭하면 Method Execution 페이지로 이동하는데, 여기서 Integration Request를 클릭합니다.

API Gateway - Method Execution

 

아래쪽에 URL Path Parameters라는 드롭 다운 메뉴가 있습니다. 펼치면 아직 아무것도 없는데, Add Path 버튼을 클릭해 목록을 2개 추가한 후, 아래 데이터를 입력합니다.

  • Name에 bucket, Mapped from에 method.request.path.folder
  • Name에 key, Mapped from에 method.request.path.object

API Gateway - Integration Request

 

그 다음 GET Method와 DELETE Method도 동일한 방식으로 추가해 줍니다. 먼저 리소스 경로에서 /{object}를 클릭해 경로를 활성화한 후, GET Method, DELETE Method를 생성하고 초기 설정을 한 후 URL Path Parameters도 동일하게 추가해 줍니다.

초기 설정을 할 때 HTTP method에 Get Method는 GET, DELETE Method는 DELETE를 선택합니다.

API Gateway - GET Method

 

Request/Resonse 설정하기

Method를 전부 추가한 후, GET Method를 통해 가져온 이미지를 브라우저에서 볼 수 있게 API의 response mapping을 설정해 줘야 됩니다(response mapping은 GET에만 설정합니다). 먼저 리소스 경로에서 GET을 선택한 후, Method Execution 페이지에서 Method Response로 들어갑니다. 여기서 200이라고 되어 있는 드롭 다운 메뉴를 펼친 후, Response Body for 200에 들어있는 application/json을 지우고, Response Headers for 200의 Add Header 버튼을 클릭해 content-type을 입력합니다. content-type은 API가 어떤 타입의 파일을 주고받는 걸 허용할지를 결정합니다.

만약 content-type을 이미지로 제한한다면, API는 이미지를 제외한 다른 파일 타입의 GET 요청을 차단합니다.

API Gateway - Method Response

 

다시 Method Execution 페이지로 돌아와 이번에는 Integration Response 페이지로 들어가서 200이라고 되어있는 드롭 다운 메뉴를 펼친 후 Header Mappings의 content-type의 Mapping value에 ‘image/jpeg’를 입력해 줍니다.

API Gateway - Integration Response

 

그 다음 CORS 허용을 위해 리소스 경로에서 /{object}를 클릭해 활성화하고, Actions 드롭 다운 메뉴의 Enable CORS 버튼을 클릭합니다. CORS 설정 페이지로 이동하면 별도의 수정 없이 Enable CORS and replace existing CORS headers 버튼을 클릭해 CORS를 허용합니다.

API Gateway - Enable CORS

 

이제 API를 통해 전달하거나, 전달받을 Binary data의 Media type을 지정해 줘야 됩니다. 먼저 왼쪽 사이드 메뉴의 Settings를 클릭해 API 설정 페이지로 들어갑니다. 맨 아래로 스크롤을 내리면 Binary Media Types라는 섹션이 있는데, 여기에 내가 주고받을 파일이 이미지라면 content-type과 동일하게 ‘image/jpeg’를 입력합니다. 만약 svg나 gif, 또는 동영상 파일도 업로드하고 싶다면 /을 입력합니다. /는 Media type과 관계없이 모든 파일을 업로드하겠다는 뜻입니다.

Binary data란?

Binary data란 데이터의 저장과 처리를 목적으로 이진법으로 인코딩 된 파일을 말합니다. 우리가 자주 쓰는 .jpg나 .png 형태의 이미지 파일, .mp4 형태의 동영상 파일, .exe 형태의 실행 파일 등이 모두 binary data입니다.

API Gateway - Settings

 

API 배포하기

설정을 모두 마치면, 이제 API를 배포해야 합니다. 먼저 Resources로 들어와 actions 드롭 다운 메뉴의 Deploy API를 클릭합니다.

API Gateway - Deploy API

 

모달창의 Deployment stage에는 [new stage]를, Stage name에는 v1을 입력합니다. 입력을 모두 마치고 나면 Deploy 버튼을 클릭해 배포를 완료합니다.

API Gateway - Deploy

 

배포까지 마쳤으니 POSTMAN으로 테스트를 진행해 보겠습니다. API 주소는 기본적으로 아래의 구조로 되어있습니다.

API 주소는 APIs > 내 API > Stages > 내 Stage name으로 들어가면 확인할 수 있습니다.

1
https://[ID].execute-api.[Region].amazonaws.com/[Stage name]/[Bucket name]/[File name]

 

각각의 값을 찾는 곳

  • ID : APIs로 들어간 후 목록의 ID 섹션에서 확인
  • Region : Method 생성 시 설정한 Region과 동일
  • Stage name : API 배포 시 입력한 이름과 동일
  • Bucket name : S3에서 확인 가능
  • File name : 내가 정한 규칙대로 임의로 지정

 

테스트

POSTMAN에서 PUT을 선택한 후 파일명은 test.jpg로 적어놓고, 위의 API 주소로 이미지 파일을 전송했습니다.

POSTMAN

 

S3에 들어가 확인해 보니, test.jpg 파일이 문제없이 업로드된 걸 확인할 수 있었습니다.

S3

 

마치며

테스트까지 마치고 나면 AWS 설정은 모두 끝났습니다. 다음 포스트는 Next.js 프로젝트에서 aws-sdk for javascript를 통해 S3 파일을 제어하는 법에 대해 포스트 하려 합니다. 긴 글 읽어 주셔서 감사합니다. 🙂

 

레퍼런스

This post is licensed under CC BY 4.0 by the author.