본문 바로가기
개발/SpringBoot

SpringBoot AWS S3 파일 업로드

by 궁즉변 변즉통 통즉구 2023. 6. 4.
반응형

SpringBoot 백엔드에서 AWS S3로 파일 업로드 하는 방법을 알아본다. 

 

1. AWS 설정(S3버킷 생성 및 IAM 설정)

테스트용 S3 버킷을 간단히 생성한다.

 

IAM에서 S3 접근을 위한 계정 및 AccessKey 설정을 한다. 먼저 계정의 권한은 AmazonS3FullAccess를 부여한다.

다음으로 S3업로드 시 사용할 AccessKey를 생성한다.

 

2. SpringBoot 어플리케이션 설정

'spring-cloud-starter-aws' gradle 의존성을 추가한다.

implementation org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE

 

application.yml에서 S3관련 설정 정보를 추가한다. 

cloud:
  aws:
    s3:
      bucket: myapp-bucket
      uploadPath: test/  # upload prefix
    stack:
      auto: false # CloudFormation 비활성화
    region:
      static: ap-northeast-2
    credentials:
      accessKey: ENC(xxxxxxxxxx)
      secretKey: ENC(xxxxxxxxxx)
    cloudfront: https://xxxxxxx.cloudfront.net/  # CloudFront연계용

필자는 S3에 이미지를 업로드하고 AWS CloudFront URL을 통해서 이미지 호출할 것이라서 coudfront URL정보까지 application.yml에 추가했다. 참고로 CloudFront와 S3연계는 본 내용과 별개임으로 여기서는 생략한다.

 

AmazonS3Config 클래스를 작성한다.

@Configuration
public class AmazonS3Config {

    @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 awsCredentials= new BasicAWSCredentials(accessKey, secretKey);
        return (AmazonS3Client) AmazonS3ClientBuilder.standard()
                .withRegion(region)
                .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
                .build();
    }
}

 

3. S3 업로드 샘플코드 작성 및 테스트

이제 업로드 샘플코드를 작성해본다. 먼저 아래와 같이 Upload Controller메소드를 작성한다.

@PostMapping(value = "/uploadImage")
public ResponseEntity uploadImage(@RequestParam("file") MultipartFile file) throws Exception{
	String url = uploadService.uploadImage(file);
	return new ResponseEntity<>(url, HttpStatus.OK);
}

 

다음으로 UploadService 클래스를 작성해준다.

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

@Value("${cloud.aws.cloudfront}")
private String cfUrl;

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

@Autowired
private AmazonS3Client amazonS3Client;


....

public String uploadImage(MultipartFile file) throws Exception{
	String originfileName = file.getOriginalFilename();
	String filePath = uploadPath + UUID.randomUUID() + originfileName.substring(originfileName.lastIndexOf("."));;
	ObjectMetadata metadata = new ObjectMetadata();
	metadata.setContentType(file.getContentType());
	metadata.setContentLength(file.getSize());
	metadata.addUserMetadata("originfilename", URLEncoder.encode(originfileName, StandardCharsets.UTF_8));
	PutObjectResult result = amazonS3Client.putObject(bucket, filePath, file.getInputStream(), metadata);
	return cfUrl + filePath;
}

 

Postman 등을 통해 테스해보면 S3에 잘 업로드 된다.

 

4. AmazonS3Client Credentials 추가 내용

위에서 AmazonS3Client 빈 설정에서 credentials 설정 시 accessKey와 secretKey를 직접 제공해주는 AWSStaticCredentialsProvider()를 사용했다. 어플리케이션 소스에서 키 값들을 관리하는 것이 보안적으로 괜찮은 방법인가 싶어서 다른 방법들을 찾아보다 DefaultAWSCredentialsProviderChain 클래스를 찾았는데 상황에 따라서 좀 더 유연하게 사용이 가능할 것 같아서 추가적으로 정리해본다.

DefaultAWSCredentialsProviderChain 클래스 내부를 보면 아래와 같이 여러개의 CredentialsProvider가 설정되어 있는 것을 확인할 수 있다.

public class DefaultAWSCredentialsProviderChain extends AWSCredentialsProviderChain {

    private static final DefaultAWSCredentialsProviderChain INSTANCE
        = new DefaultAWSCredentialsProviderChain();

    public DefaultAWSCredentialsProviderChain() {
        super(new EnvironmentVariableCredentialsProvider(),
              new SystemPropertiesCredentialsProvider(),
              WebIdentityTokenCredentialsProvider.create(),
              new ProfileCredentialsProvider(),
              new EC2ContainerCredentialsProviderWrapper());
    }

    public static DefaultAWSCredentialsProviderChain getInstance() {
        return INSTANCE;
    }
}

 

그리고 주석을 보면 적용되는 우선순위는 아래와 같다.

1. 환경변수: 환경변수에 설정된 다음 키 값들을 가져운다. AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY (RECOMMENDED since they are recognized by all the AWS SDKs and CLI except for .NET),

or AWS_ACCESS_KEY and AWS_SECRET_KEY (only recognized by Java SDK)

2. Java System Properties : aws.accessKeyId and aws.secretKey

3. Credential profiles file : at the default location (~/.aws/credentials) shared by all AWS SDKs and the AWS CLI 4.

4. Amazon EC2 Container Credentials: 환경변수 AWS_CONTAINER_CREDENTIALS_RELATIVE_URI가 설정 시 Amazone ECS에서 로드

5. 인스턴스 Profile Credentials: the Amazon EC2 metadata service Web Identity Token credentials from the environment or container.

 

빈설정은 아래와 같이 변경 해주면 될것이다.

@Bean
public AmazonS3Client amazonS3Client() {
    return (AmazonS3Client) AmazonS3ClientBuilder.standard()
        .withRegion(region)
        .withCredentials(DefaultAWSCredentialsProviderChain.getInstance())
        .build();
}

 

반응형

댓글