AWS Cognito로 비공개 S3 객체에 액세스하는 방법

시나리오
고객을 위해 일부 애플리케이션을 개발했다고 가정해 봅시다. 그러나 애플리케이션의 레코드와 관련된 PDF, Word, Excel 등의 파일이 있습니다. 시나리오의 단순화를 위해 이러한 파일이 AWS의 단일 비공개(private) S3 버킷에 저장되어 있다고 가정합니다.
사용자는 애플리케이션의 URL 링크를 통해 비공개 S3 버킷에서 이러한 관련 파일에 액세스할 수 있어야 합니다. 우리 솔루션은 사내 소프트웨어를 위한 이식 가능한(portable) 솔루션으로 작동해야 합니다.
소개
이 문서의 목적은 Cognito 사용자 풀을 사용하여 비공개 S3 버킷의 파일을 다운로드하는 방법을 보여주는 것입니다. Cognito 외에도 Cognito에서 Authorizer가 있는 API Gateway로의 흐름과 API Gateway와 Lambda의 협력도 보여줍니다.
AWS 콘솔의 각 단계에 대해 가능한 많은 스크린샷이 공유되었습니다. 특히 초보자를 위해 단계를 더 명확하게 하기 위해 많은 시각 자료가 추가되었습니다.
배경
이 문서에서 개발된 내용을 더 잘 이해하기 위해 일부 사전 읽기가 유용할 수 있습니다. 특히 AWS 초보자를 위한 다음 링크가 유용합니다:
무엇을 해야 하나요?
이러한 작업에 대해 많은 흐름이나 방법을 코딩할 수 있습니다. 여기서는 아래에서 보여주는 방법을 구현합니다. 시나리오 구현 방법에 대한 간략한 설명이 아래 이미지에 제시되어 있습니다.
아래 이미지는 Cognito 사용자 풀, S3 버킷, API Gateway 메서드, Lambda 함수 등과 같은 일부 요소를 생성해야 함을 보여줍니다. AWS 환경에서 모든 엔터티를 생성한 후 모두 함께 협력하여 작동할 수 있도록 적절하게 구성해야 합니다.

AWS 환경의 모든 요소를 역순으로 생성하는 것이 좋습니다. 예를 들어 API 메서드와 함께 Lambda를 사용하려면 먼저 Lambda 함수를 개발하면 API Gateway 메서드 생성 시 이 함수를 쉽게 연결할 수 있습니다.
개요
다음 질문에 대한 답변을 찾아보겠습니다. 이 문서의 모든 단계를 구현하려면 AWS 계정이 있어야 한다는 점을 기억하세요.
- 비공개 S3 버킷은 어떻게 생성하나요?
- 비공개 S3 버킷의 객체에 액세스하기 위한 사용자 정의 정책은 어떻게 생성하나요?
- 비공개 S3 버킷의 객체에 액세스하기 위한 Lambda 함수는 어떻게 생성하나요?
- Lambda 함수를 사용하기 위한 Gateway API는 어떻게 생성하나요?
- 웹 폴더로 사용할 공개 S3 버킷은 어떻게 생성하나요?
- Cognito 사용자 풀은 어떻게 생성하고 설정을 구성하나요?
- 시나리오는 어떻게 테스트하나요?
1. 비공개 S3 버킷은 어떻게 생성하나요?
S3는 AWS에서 지역 기반(region-based) 서비스 중 하나입니다. S3 버킷의 항목을 객체(object)라고 합니다. 따라서 AWS에서 S3 버킷에 대해 객체와 파일 용어는 서로 바꿔 사용할 수 있습니다.
"모든 공개 액세스 차단"(Block All Public Access) 체크박스를 선택한 상태로 유지하세요. 여기서 비공개 S3 버킷이 생성되었습니다.

비공개 액세스를 테스트하기 위해 S3 버킷에 일부 객체를 업로드하세요. 이후 권한이 없는 사용자나 가능한 액세스 링크로 이러한 객체에 액세스를 시도하세요.

2. 비공개 S3 버킷의 객체에 액세스하기 위한 정책 생성
AWS에서 IAM(Identity and Access Management)은 모든 서비스의 기본입니다! 사용자, 그룹, 역할 및 정책은 우리가 익숙해져야 할 기본 개념입니다.
많은 기본 제공(built-in) 역할이 있으며 각 역할에는 권한을 의미하는 많은 기본 제공 정책이 있습니다. 이를 "AWS Managed"라고 합니다. 그러나 "Customer Managed"(고객 관리) 역할 및 정책을 생성하는 것도 가능합니다.
- 비공개 S3 버킷에서 객체를 가져오기 위해 사용자 지정 IAM 정책을 생성하세요.
- AWS의 기존 정책 목록을 찾고 아래와 같이 비공개 S3 버킷에서만
GetObject작업을 수행할 새 정책을 생성하세요:

아래와 같이 사용자 지정 정책을 생성하세요. 서비스로 S3를, 작업(action)으로
GetObject만 선택하세요:
리소스(resource)로 "specific"을 선택하고 정책이 원하는 기능을 갖도록 비공개 S3 버킷을 지정하세요:

정책에 이름을 지정하고 생성하세요.
정책 JSON 정의:
JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::private-s3-for-interfacing/*"
}
]
}
3. 비공개 S3 버킷의 객체에 액세스하기 위한 Lambda 함수 생성
여기서는 Lambda 함수에 NodeJS의 최신 버전을 사용했습니다. Lambda 함수를 생성하고 NodeJS를 선택하세요.

기존 코드를 제공된 샘플 코드로 교체하세요. 코드를 변경한 후 Lambda 함수를 사용하려면 "Deploy" 버튼을 누르세요.
NodeJS Lambda 코드 (Blob으로 반환):
JavaScript
const AWS = require('aws-sdk');
const S3= new AWS.S3();
exports.handler = async (event, context) => {
let fileName;
let bucketName;
let contentType;
let fileExt;
try {
bucketName = 'private-s3-for-interfacing';
fileName = event["queryStringParameters"]['fn']
contentType = 'application/pdf';
fileExt = 'pdf';
fileExt = fileName.split('.').pop();
switch (fileExt) {
case 'pdf': contentType = 'application/pdf'; break;
case 'png': contentType = 'image/png'; break;
case 'gif': contentType = 'image/gif'; break;
case 'jpeg': case 'jpg': contentType = 'image/jpeg'; break;
case 'docx': contentType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'; break;
case 'xlsx': contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; break;
default: ;
}
const data = await S3.getObject({Bucket: bucketName, Key: fileName}).promise();
return {
headers: {
'Content-Type': contentType,
'Content-Disposition': 'attachment; filename=' + fileName,
'Content-Encoding': 'base64',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token',
'Access-Control-Allow-Methods': 'GET,OPTIONS'
},
body: data.Body.toString('base64'),
isBase64Encoded: true,
statusCode: 200
}
} catch (err) {
return {
statusCode: err.statusCode || 400,
body: err.message || JSON.stringify(err.message)
}
}
}
Lambda 함수를 생성할 때 함께 역할이 생성됩니다. 그러나 이 역할에는 비공개 S3 버킷의 객체에 액세스할 권한이 없습니다. 이제 이전 단계에서 생성한 "Customer Managed" 정책을 Lambda 함수와 함께 생성된 이 역할에 연결해야 합니다.

이전 단계에서 생성한 사용자 지정 정책을 이 역할에 연결하세요.

4. Lambda 함수를 사용하기 위한 Gateway API 생성
아래와 같이 AWS Gateway REST API를 생성하세요. "REST" API를 "New API"로 생성합니다.

AWS GW API를 생성하고 실행하려면 몇 가지 단계가 있습니다:
- API 생성
- Resource 생성
- Method 생성
- API 배포(Deploy)
REST API에 대해 아래와 같이
Resource를 생성하세요:
생성한 리소스에 대해
GET 메서드를 생성하세요. 이전 단계에서 생성한 Lambda 함수를 이 메서드와 연결하는 것을 잊지 마세요.
Lambda Proxy Integration이 여기에서 체크되었습니다. 이 접근 방식을 통해 Lambda 함수에서 모든 응답 관련 콘텐츠를 처리할 수 있습니다.

아래와 같이 Gateway API에 대해 CORS를 활성화하세요.

AWS Gateway 메서드와 관련된 모든 것을 생성하고 구성한 후 이제 API를 배포(deploy)할 시간입니다.

API 게이트 액세스를 제한하려면 Authorizer(인증자)를 정의해야 합니다. 아래와 같이 Cognito Authorizer를 정의할 수 있습니다.

5. 웹 폴더로 사용할 공개 S3 버킷
솔루션에는 두 개의 S3 버킷이 필요합니다. 첫 번째는 이전 섹션에서 생성되었습니다. 두 번째는 지금 생성되며 웹 폴더로 사용됩니다.

웹 폴더로 공개 S3 버킷을 생성하세요. 이 버킷에는
callback.html 파일이 포함되어 있어 Cognito 콜백 주소로 사용할 수 있습니다.6. Cognito 사용자 풀 생성 및 구성
- Callback 주소:
https://web-s3-for-interfacing.s3.eu-west-2.amazonaws.com/Callback.html - OAuth 2.0 Flows: "implicit grant" 옵션을 선택하세요.
- OAuth 2.0 Scopes: email, openid, profile.
Cognito Hosted UI 링크에는 여러 URL 매개변수가 포함되어 있습니다.


7. 시나리오는 어떻게 테스트하나요?
Cognito 사용자 풀을 사용하여 제한된 액세스를 허용하는 API를 테스트하는 방법을 살펴보겠습니다.
모든 최종 사용자는 이 프로세스를 시작하기 위해 링크를 클릭할 수 있습니다.
LinkToS3Files.html 파일을 사용하여 시나리오를 테스트할 수 있습니다.결론
이 문서가 AWS 클라우드 환경을 처음 접하는 분들에게 유용하기를 바랍니다.