본문 바로가기
AWS

AWS S3 인스턴스 생성 + Spring boot 연동

by codeyaki 2023. 1. 1.
반응형

버킷 생성

1. 버킷 인스턴스 대시보드에 들어가기

버킷 만들기 클릭

  • 버킷 이름 작성
  • AWS 리전: 아시아 태평양(서울) 선택
  • 그 외에 모든 설정은 그대로 버킷 생성

S3 권한이 있는 IAM 계정 만들기 & 액세스 키 발급받기

S3 권한이 있는 IAM계정을 발급받아서 진행하는 것이 보안에 좋아요!

지금은 S3 IAM 계정이 있기 때문에 엑세스 키 발급만 진행하도록 하겠습니다.

1. aws 프로필 - 보안 자격 증명

2. 보안 자격증명에 들어가면 아래 액세스 키 만들기 를 통해서 액세스 키를 만들어 주면 됩니다.

비밀번호는 이때밖에 볼 수 없으니 잘 기록해 두거나 csv파일로 잘 저장해 두세요!


Spring boot에서 연동하기

1. 의존성 추가

pom.xml에 아래 스타터를 추가해 주세요.

(maven을 기준입니다.)

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-aws</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

2. application.yml에 설정 정보 추가

절대 노출시키면 안 되니깐 config server를 사용해서 구현하시거나 or git ignore 신경 쓰세요!!

 cloud:
   aws:
     credentials:
       access-key: 발급받은 access key
       secret-key: 발급받은 secret key
     region:
       static: 접속할 리전 정보 (한국은 ap-northeast-2 )
     s3:
       bucket: 당신의 S3 버킷 인스턴스 명
     stack:
       auto: false

 

spring에서 AmazonS3 이름으로 직접 bean을 생성할 때 아래와 같은 과정으로 생성해 주세요
(지금은 이해를 돕기 위해서 작성을 해둔 것이므로 작성하지 않아도 됩니다!)
yml에 작성한 정보를 토대로 미리 만들어져 있는 객체를 사용하려면 AmazonS3 Bean을 사용하면 된다.

package ;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AwsConfig {
    @Value("${cloud.aws.credentials.access-key}")
    private String accessKey;

    @Value("${cloud.aws.credentials.secret-key}")
    private String secretKey;

    @Value("${cloud.aws.region.static}")
    private String region;

    @Bean
    public AmazonS3Client amazonS3Client() {
        BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);
        return (AmazonS3Client) AmazonS3ClientBuilder.standard()
                .withRegion(region)
                .withCredentials(new AWSStaticCredentialsProvider(awsCreds))
                .build();
    }

}

업로드

package com.sixman.roomus.product.command.infra.service;

import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.*;
import com.sixman.roomus.product.command.domain.exception.NullContentTypeException;
import com.sixman.roomus.product.command.domain.service.ProductAwsS3Service;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.UUID;

@Service
@RequiredArgsConstructor
public class ProductAwsS3ServiceImpl implements ProductAwsS3Service {

    @Value("${cloud.aws.s3.bucket}")
    private String bucket;

    private final AmazonS3 amazonS3;

    @Override
    public String fileUpload(String category, MultipartFile uploadFile) throws IOException {
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(uploadFile.getInputStream().available());

        objectMetadata.setContentType(contentType);
        String fileNameString = String.valueOf(getRandomUuid());
        amazonS3.putObject(new PutObjectRequest(bucket, fileNameString, uploadFile.getInputStream(), objectMetadata));

        return amazonS3.getUrl(bucket, fileNameString).toString();

    }

    private static UUID getRandomUuid() {
        return UUID.randomUUID();
    }
  • amazonS3 객체와 bucket명을 받아와서 저장을 해주어야 하기 때문에 두 객체를 DI 해주어야 합니다.
  • 현재 파일 이름은 UUID를 자동으로 생성하여 저장하는 방식입니다. 원하는 방식으로 바꿔서 이름을 저장해 주어도 됩니다!
    (다른 파일과 중복되지 않게 규칙을 정하기만 한다면 아무런 방법으로 해도 괜찮으나 그것이 아니라면 자바에서 지원하는 UUID를 사용해서 간편하게 만드는 것도 좋다고 생각합니다)
    UUID (Java SE 11 & JDK 11 )
 

UUID (Java SE 11 & JDK 11 )

The timestamp value associated with this UUID. The 60 bit timestamp value is constructed from the time_low, time_mid, and time_hi fields of this UUID. The resulting timestamp is measured in 100-nanosecond units since midnight, October 15, 1582 UTC. The tim

docs.oracle.com

  • putObjectRequest: putObject를 요청하기 위한 객체로 bucket, key(파일 이름), input(업로드할 파일), metadata (파일 정보)를 삽입해야 합니다.
    • bucket: S3 스토리지 이름으로 스토리지 이름 뒤에 / 붙여서 추가로 작성해 주면 디렉터리가 됩니다.
      ex) bucket = testS3/img: testS3 이름의 스토리지의 img 디렉터리에 저장

생성한 후에 putObject를 통해서 s3서버에 업로드하면 됩니다.


권한 설정

[AWS] 📚 S3 개념 정리 & 버킷 생성 · 권한(Policy / ACL) 설정하기

 

[AWS] 📚 S3 개념 정리 & 버킷 생성 · 권한(Policy / ACL) 설정하기

S3 (Simple Storage Service) 개념 AWS S3는 업계 최고의 확장성과 데이터 가용성 및 보안과 성능을 제공하는 온라인 오브젝트(객체) 스토리지 서비스이다. (참고로 S 앞글자가 3개라서 S3 이라고 한다.) 쉽

inpa.tistory.com

좀 더 자세한 방법은 위 블로그를 통해서 확인할 수 있습니다.


위에서 파일 업로드 후 생성된 URL을 통해서 자원에 접근할 수 있습니다.

하지만 권한 설정을 따로 해주지 않으면 백엔드를 통해서 파일을 전송해주어야 하는데 이는 네트워크를 이중으로 사용하는 과부하가 생길 것으로 생각되어서 클라이언트에는 url을 보내주고 그 url을 통해서 직접 접근할 수 있도록 만들어주려고 하는 것이 좋은 것 같습니다.

처음 생성할 때 public 비활성화를 시켜두었기 때문에 해당 설정을 모두 해제해 준다.

1. 퍼블릭 액세스 차단 - 편집

‘모든 퍼블릭 액세스 차단’ 해제 - 변경 사항 저장

2. 버킷 정책

이곳에서 정책을 추가해 주면 됩니다.

 

우측 상단에 보이는 편집 버튼을 누르면

해당 화면이 나오는데 version은 정책의 버전을 입력해 주면 됩니다. 위 사진은 최소한의 설정입니다.

아래쪽에 보면 + 새문 추가 버튼을 눌러서 위와 같이 정책을 추가해 주면 됩니다.

세부 설정 목록

해당 설정들을 해주면 url을 통해서 리소스에 접근하는 것이 허용이 됩니다.

  {
      "Version": "2012-10-17", // Bucket Policy의 문법이 언제 날짜 기준으로 확정된 문법을 사용하는지 → 2008-10-17 버전 후 2012-10-17 버전이 있는데, 그 뒤로는 업데이트가 안됐음
      "Id": "S3PolicyId1", // Bucket Policy의 고유 아이디, 자동으로 부여되는 경우가 많음
      "Statement": [
          {
              "Sid": "IPAllow", // 각 Statement의 고유 아이디. 무슨 역할을 하는 policy인가
              "Effect": "Allow", // 버킷에 대한 명령을 허락(allow)하거나 거부(deny). 특정 사용자에 대해 명령을 제한하거나, 허용하는 식으로 사용
              "Principal": {"AWS": "arn:aws:iam::spark323:user/spark"}, // Bucket Policy의 적용대상 (spark323 아이디의 유저에 대해서)
              "Action": [ // Bucket Policy에서 허용한 Action
                  "s3:GetObject", // 객체 가져오는 행동
                  "s3:GetBucketLocation", // 버켓 위치를 확인하는 행동
                  "s3:ListBucket", // 버켓 리스트를 확인하는 행동
              ],
              "Resource": "arn:aws:s3:::bucketname/*", // 대상이 대는 Bucket에 대한 명세
              "Condition": { // 어떤 조건 하에
                  "NotIpAddress": { // 이 IP비허용
                      "aws:SourceIp": "1.1.1.1/32"
                  },
                  "IpAddress": { // 이 IP허용
                      "aws:SourceIp": [
                          "192.168.1.1",
                          "192.168.1.2/32",
                      ]
                  }
              }
          }
      ]
  }
반응형