지금 하고 있는 프로젝트에서 React-Native 기반의 앱에서 사진을 찍어서 upload 요청을 하면, 받아서 S3에 올리고, 다시 꺼내주는 API를 만들어야했다. 처음에는 REST API 대신, 원래쓰던 GraphQL로 트라이 하다가, 몇번에 실패 후 사진 업로드 모듈만 따로 REST로 때어냈다.(아 아무튼 사진만 업로드 되면 되니까...)
하는김에 AWS 보안 설정도 좀 더 손봐서 추가해본다.
1. AWS IAM 사용자 추가 및 Access Key 발급
AWS 콘솔에 root 유저로 로그인 되어있다는 가정하에, 좌측 상단에서 IAM 검색 -> 사용자 -> 사용자 추가
위와 같이 액세스 키, 암호를 할당, 이후 쭉쭉 다음 눌려서 검토 후 생성 -> 이때 key를 csv로 받을 수 있고, 유저 이름과 유저에 할당된 id 번호를 메일로도 발송할 수 있다.
나중에 액세스 키와 시크릿 키는 S3에 저장할 때 쓰이니 꼭 잘 저장해두자
이후 사용자 그룹에서 방금 만든 IAM 사용자에게 권한 할당을 해준다. IAM -> 사용자 그룹 -> 사용자 그룹 생성
밑에 권한 정책 연결해서 필요한 접근 권한을 설정해준다. 본인은 일단은 초기 설정할 때는 Root 처럼 쓰기 위해
PowerUserAccess와 IAMFullAccess 권한을 부여했다. (찾아보고 필요한것만 골라서 권한 할당하는게 제일 안전함)
이후 그룹에 직전에 만든 사용자를 할당해준다.
이제 root 계정에서 로그아웃 후 IAM 계정으로 로그인해준다. (로그인 하자마자 우측 상단 계정명 클릭 후, MFA 설정 추천)
2. AWS S3 버킷 생성
좌측 상단 검색에서 S3 검색 후 버킷을 만들어준다.
버킷 이름 설정 후, 리젼도 원하는 곳으로 설정(국내 서비스면 서울)
위와 같이 액세스 설정 후 다른 설정 그대로 버킷을 만들어준다.
방금 만든 버킷을 클릭해서 권한으로 간다. 밑에 내려보면
버킷 정책을 설정할 수 있다. 편집을 누르고
여기서 좌측에 버킷 ARN을 복사해둔다. 이후 정책 생성기로 들어가서
Actions는 GetObject를 선택하고, ARN에는 방금 앞에서 복사한 ARN을 넣고 뒤에 /* 을 붙여준다.
Ex) ~~~버킷명/*
3. Node.js 코드
// uploadImgS3.js
var express = require("express");
var router = express.Router();
const multer = require("multer");
const AWS_SDK = require("aws-sdk");
const multerS3 = require("multer-s3");
require("dotenv").config();
// dotenv 모듈로 안보이게 처리하고 .env 파일에 명세해준다. -> .env 파일은 .gitignore 처리 꼭 해둘것
const s3 = new AWS_SDK.S3({
accessKeyId: process.env.AWS_ACCESSKEY_ID, // IAM 유저 설정하고 받은 액세스 키
secretAccessKey: process.env.AWS_SECRET_ACCESSKEY, // IAM 유저 설정하고 받은 시크릿 키
region: process.env.AWS_REGION, // 지역에 따라서 서울이면 ap-northeast-2
});
const upload = multer({
storage: multerS3({
s3: s3,
bucket: "버킷명",
key: function (req, file, cb) {
cb(null, Date.now() + "." + file.originalname.split(".").pop()); // 파일명 설정
},
}),
acl: "public-read-write",
limits: { fileSize: 20 * 1024 * 1024 }, // 몇 MB까지 허용할지
});
router.post("/img", upload.single("file"), async (req, res) => {
console.log(req.file.location);
res.status(200).json({ location: req.file.location });
});
module.exports = router;
본인은 GraphQL을 위해 Apollo Server를 쓰고 있어서, 그냥 REST API로 할 때랑 모양이 조금 다를 수는 있다.
// app.js
import express from "express";
...
var cors = require("cors");
...
require("dotenv").config();
const port = process.env.PORT;
const app = express();
app.use(cors());
...
app.use("/", require("./utils/uploadImgS3"));
const server = new ApolloServer({
...
});
server.start().then((res) => {
...
app.listen(port, async () => {
console.log(`GraphQL API server open on ${port}`);
});
});
1. CORS 설정을 꼭 해주자 var cors = require("cors");
2. 이건 진짜 억까 of 억까였는데, 사진을 업로드하면 'TypeError: this.client.send is not a function' 이런 에러가 서버쪽에서 떴다.
뒤적뒤적해보니 multer-s3 와 aws-sdk 사이에 버전 차이로 생기는 오류라고 했다. 에이 설마 하면서 package.json 해보니
multer-s3 는 3.대, aws-sdk 는 2.대 버전이였다.
npm i multer-s3@^2 --save
강제로 버전을 낮추니 아주 잘 API가 동작했다.
도움이 많이된 블로그
-> https://velog.io/@wngud4950/AWS-multer-s3-upload-%EC%98%A4%EB%A5%98
'인프라 > AWS' 카테고리의 다른 글
[AWS] AWS S3 + CloudFront + Route53으로 https로 React 웹 호스팅하기 (0) | 2022.11.19 |
---|---|
[AWS] Amazon SES에 자체 도메인 연결하고, Node.js 환경에서 메일 발송하기 (0) | 2022.11.10 |
[ElasticSearch] AWS OpenSearch Service로 NodeJS 서버 logging하고, kibana로 분석하기 (0) | 2022.09.30 |
[AWS] Elastic Beanstalk에서 고용량 파일(이미지)을 받을 때 nginx 설정 (0) | 2022.07.18 |
[AWS] Github Action을 사용해서 Elastic Beanstalk에 nodejs 서버 CI/CD (0) | 2022.07.18 |