(AWS) S3 생성 및 권한 설정

최건·2025년 5월 6일

참고 블로그

S3 생성

  1. S3 검색 후 버킷 만들기 클릭

  1. 버킷 이름 짓기 및 객체 소유권 설정 -> 비활성화를 선택해서 내가 접속한 계정에서만 소유하도록 함

  1. 모든 퍼블릭 액세스 차단 풀기 -> 외부에서 파일을 읽게 하기 위해 (URL을 통해)

  1. 버킷 생성 완료 후 생성된 버킷으로 다시 들어가서 권한 클릭

  1. 버킷 정책 편집하기 : https://awspolicygen.s3.amazonaws.com/policygen.html

  1. Select Type of Policy: 정책 타입 선택 (버킷 정책으로)
    Effect: 정책 적용 허용
    Principal: 버킷 정책이 적용될 대상 -> 전체(*)
    Actions: 버킷에 수행할 액션 (GetObject, PutObejct) 선택
    ARN: 버킷에 어떤 리소스에 적용할지 -> 버킷 이름 선택, 리소스 전체
arn:aws:s3:::버킷이름/* 

{
  "Id": "Policy1649421058532", // 정책 ID
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1649420985040", 
      "Action": [ // 버킷에 수행할 액션(행동)
        "s3:GetObject", // 객체 가져오기
        "s3:PutObject" // 객체 업로드하기
      ],
      "Effect": "Allow", // 정책 적용
      "Resource": "arn:aws:s3:::버킷명/*", // 어떤 버킷에 어떤 리소스에 적용? tistory-test-bucket-01 버킷에 있는 모든 리소스(객체)
      "Principal": "*" // 정책 적용 대상 모두
    }
  ]
}
출처: https://inpa.tistory.com/entry/AWS-📚-S3-버킷-생성-사용법-실전-구축 [Inpa Dev 👨‍💻:티스토리]
  • 편집 완료버튼 클릭하기.

s3 권한만 갖은 사용자 생성하기

  • 버킷만 생성해도 파일을 올리거나 삭제할 수 있지만 코드에서 접근하기 위해서는 사용자 권한이 필요하다.
  • root 권한을 갖은 사용자를 사용하면 위험하기 때문에 s3 권한만 갖은 사용자를 생성해서 사용하는 것이 좋다.
  1. IAM 접속
  2. 사용자 > 사용자 생성 클릭

  1. 사용자 이름 작성

  1. 권한 옵션 -> 직접 정책 연결 선택 후 AmazonS3FullAccess 선택

  1. 사용자 생성

  1. 사용자 이름 클릭 -> 보안 자격 증명 클릭 후 엑세스 키 만들기 클릭

  1. 사용 사례 CLI 선택 후 태그 값 작성

  1. 액세스키 .csv 파일로 다운 받기 후 완료

Node Js 코드

import { S3Client } from '@aws-sdk/client-s3';
import multer from 'multer';
import multerS3 from 'multer-s3';
import dotenv from 'dotenv';

dotenv.config();

const s3 = new S3Client({
    credentials: {
        accessKeyId: process.env.AWS_ACCESS_KEY_ID,
        secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, 
    },
    region: process.env.AWS_REGION,
})

const upload = multer({
    storage: multerS3({
        s3,
        bucket: process.env.AWS_S3_BUCKET_NAME,
        metadata: (req, file, cb) => {
            cb(null, { fieldName: file.fieldname });
        },
        key: (req, file, cb) => {
            cb(null, `image/${Date.now().toString()}-${file.originalname}`);
        }
    }),
    limits: {fileSize: 5 * 1024 * 1024},
});

export default upload;
// myprofile.js
import express from 'express';
import { MyprofileSaveLogic } from '../domains/myprofile/myprofile.controller.js';
import upload from '../config/s3.config.js';

export const MyprofileRouter = express.Router();

MyprofileRouter.post('/',upload.single('imgage'),MyprofileSaveLogic);

NestJs 코드

import { Injectable, InternalServerErrorException } from '@nestjs/common';
import { DeleteObjectCommand, PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { ConfigService } from '@nestjs/config';
import { LoggerService } from '../logger/logger.service';

@Injectable()
export class AwsService {
  s3Client: S3Client;
  private readonly bucketName: string;
  private readonly region: string;

  constructor(
    private readonly loggerService: LoggerService,
    private readonly configService: ConfigService,
  ) {
    try {
      this.region = this.configService.get<string>('AWS_REGION');
      this.bucketName = this.configService.get<string>('AWS_BUCKET_NAME');

      this.s3Client = new S3Client({
        region: this.region,
        credentials: {
          accessKeyId: this.configService.get<string>('AWS_ACCESS_KEY'),
          secretAccessKey: this.configService.get<string>('AWS_SECRET_ACCESS_KEY'),
        },
      });
    } catch (err) {
      this.loggerService.warn(`S3/ 초기화 에러: ${err}`);
    }
  }

  async uploadImagesToS3(files: Express.Multer.File[] | Express.Multer.File | undefined, ext: string): Promise<string[]> {
    try {
      if (!files) return [];

      const fileArray = Array.isArray(files) ? files : [files];

      const uploadPromises = fileArray.map(async (file) => {
        const fileName = `review/${Date.now()}-${file.originalname}`;

        const command = new PutObjectCommand({
          Bucket: this.bucketName,
          Key: fileName,
          Body: file.buffer,
          ContentType: `image/${ext}`,
        });

        await this.s3Client.send(command);

        return `https://${this.bucketName}.s3.${this.region}.amazonaws.com/${fileName}`;
      });

      return Promise.all(uploadPromises);
    } catch (err) {
      this.loggerService.warn(`S3/ 업로드 에러: ${err}`);
      throw new InternalServerErrorException();
    }
  }

  async deleteImageFromS3(imageUrl: string) {
    const fileName = imageUrl.split('/').pop();
    const command = new DeleteObjectCommand({
      Bucket: this.bucketName,
      Key: fileName,
    });

    await this.s3Client.send(command);
  }
}
profile
개발이 즐거운 백엔드 개발자

0개의 댓글