개발새발 로그

[NestJS] AWS S3로 이미지 업로드 하기 본문

카테고리 없음

[NestJS] AWS S3로 이미지 업로드 하기

이즈흐 2025. 12. 19. 00:51

📖들어가며...

이번에 NestJS를 배우면서 이미지 관련한 기능을 구현했는데
처음에는 기능 개발 우선으로 이미지 같은 경우 그냥 NestJs의 폴더에 저장해서 관리했다.

이렇게 하면 나중에 이미지가 많아졌을 때 서버 크기도 같이 커지기 때문에 좋지 않다.

그래서 AWS를 이용해 해결하는 방법을 찾았고, 그 방법을 적용하는 과정을 기록해보았다.

 

 


AWS S3

1. 먼저 AWS의 스토리에 탭에서 S3에 들어간다.

나는 AWS 프리티어를 이용해서 S3를 사용할 것이다.

 

2. 버킷만들기를 클릭한다.

 

 

3. 버킷 이름을 입력하고, 버킷의 퍼블릭 액세스 차단 설정을 모두 해제한다. 그리고 아래 경고에 체크한다.

버킷의 퍼블릭 액세스 차단 설정이 무엇이고, 해제하면 어떻게 되나요?

S3 퍼블릭 액세스 차단(Block Public Access) 은 실수로라도 버킷이나 객체가 전 세계에 공개되는 사고를 막기 위한 안전장치

이걸 해제하면 완전 공개 가능 상태가 된다. 즉 전 세계 누구나 접근 가능

이걸 해제해도 되는 경우는 공개적인 SNS, 공개 이미지, 프로필 사진 등일 때이다.

 

나는 지금 SNS와 같은 앱을 만들고 있어서 차단이 불필요하다.

그럼 만약에 퍼블릭 액세스 차단 설정을 한다면 어떻게 해야하나요?

아마 Presigned URL 방식을 사용하면 될 것이다.

간단하게 설명하면

이미지를 업로드하고 나서 이미지에 대한 Key값을 DB에 저장하고, 유효기간이 있는 이미지 URL 주소를 FE에게 반환해준다.

그리고 만약 해당 이미지를 갖고오고 싶다면 Key값을 이용해 유효기간이 있는 이미지를 반환해주는 것이다.

 

 

4. 만들어진 버킷을 클릭하고 버킷 정책을 추가한다.

{

    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AddPerm",
            "Effect": "Allow",
            "Principal": "*", // 퍼블릭 버킷 선언
            "Action": [
                "s3:GetObject", // 객체 다운로드
                "s3:PutObjectAcl", // 객체 업로드
                "s3:PutObject" // 객체 접근 권한(ACL) 변경
            ],
            "Resource": "arn:aws:s3:::버킷이름/*" // 버킷 안 모든 객체
        }
    ]
}


// 누구나 이미지 다운로드
// 누구나 파일 업로드
// 누구나 ACL 변경, 객체를 public-read로 바꿀 수도 있음

S3 버킷 정책이란?

이 버킷과 그 안의 객체에 대해

누가 / 무엇을 / 어떤 조건에서 할 수 있는지 를 정의하는 리소스 기반 권한 정책(JSON)

해당 설정은 실 서비스에서는 위험한 설정이다.

올바른 대안은 Principal을 서버만 가능하도록 하는 것이다.

그리고 다운로드는 Presigned URL을 사용하게 하는 것이다.

 

이번 포스팅에서는 어떻게 AWS에 이미지를 업로드할 수 있게 하는지에 대해서 정리하는 것이 목적이다.

또한 앱에서 이미지 업로드의목적이 홍보를 위해서 업로드를 하는 것이라서 누구나 열어봐도 된다고 판단했다.

위처럼 보완이 필요한 부분은 추후 포스팅에서 다룰 예정이다.

 

5.폴더 만들기

폴더 만들기 클릭

폴더 이름 작성 후 만들기 클릭

6. 우측 상단에서 보안자격 증명 클릭 후 액세스 키 만들기 클릭해서 액세스 키 저장하기

이후 나온 액세스 키와 비밀 액세스 키를 복사해서 메모장에 저장

그리고 env에 액세스 키와 지역을 작성

AWS_BUCKET_REGION=ap-northeast-2
S3_ACCESS_KEY_ID=액세스키

 

 

 

7. NestJS에서 코드 작성

설치
npm i @aws-sdk/client-s3

 

이미지 업로드 코드 아래와 같이 작성(바로 컨트롤러에 작성했습니다)

@Controller('images')
@UseGuards(AuthGuard())
export class ImageController {
  @UseInterceptors(
    FilesInterceptor('images', numbers.MAX_IMAGE_COUNT, {
      limits: { fileSize: numbers.MAX_IAMGE_SIZE },
    }),
  )
  @Post('/')
  async uploadImages(@UploadedFiles() files: Express.Multer.File[]) {
    const s3Client = new S3Client({
      region: process.env.AWS_REGION,
      credentials: {
        accessKeyId: process.env.AWS_ACCESS_KEY_ID,
        secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
      },
    });
    const uuid = Date.now();

    const uploadPromises = files.map((file) => {
      const fileName = getUniqueFileName(file, uuid);

      const uploadParams = {
        Bucket: process.env.AWS_S3_BUCKET_NAME,
        Key: fileName,
        Body: file.buffer,
        ContentType: file.mimetype,
      };

      const command = new PutObjectCommand(uploadParams);
      return s3Client.send(command);
    });

    await Promise.all(uploadPromises);
  }
}

그리고 실제 파일을 업로드하면 AWS 스토리지에 저장이된다.

해당 파일을 미리보기하고 싶다면 FE에서 아래 주소와 같은 형식으로 이미지를 보이도록 해야한다.

 

 

📘마치며..

일단 다시 블로그 글을 봤을 때 빠르게 기억해낼 수 있도록 간단 명료하게 적어보았다.

글을 적으면서 중간중간에 했던 과정이 보안적인 문제로 실무에서는 사용되지 않는다는 것을 알게되었다.

추후 포스팅에서는 이 문제를 해결하는 과정을 기록해보려 한다.

728x90
반응형
LIST