Do Something
[AWS-S3] S3에서 내 계정으로만 쓰기 가능하고 모두가 읽기만 가능하도록 본문
s3도 쓸려고 하니까 복잡하다
내 Spring boot어플리케이션에서만 s3에 업로드 가능하게 하고 그 외는 전부 막아버리고 싶었다.
목표 : Iam 계정을 사용해서 업로드 가능. 그 외 전부 막기
첫번째로 내 Iam계정을 수정해야 한다.
저 오른쪽 위에 들어가서 [내 보안 자격 증명] 을 누르도록 하자
엑세스 관리 -> 사용자
사용자 추가
사용자를 만들 때 권한 정책에서 "AmazonS3FullAccess"를 줘버리자
PutBucketPolicy인가 이거만 있으면 되는거 같긴 하다.
보안자격 증명 -> 엑세스 키
엑세스 키 만들기 -> 만들기!
accessKey, secretKey가 만들어진다.
결론적으로 AmazonS3FullAccess를 가진 Iam계정과 키를 만들었다
이제 s3로 넘어가보자
버킷 -> 권한
ACL을 딱히 설정하지 않아서 상관없지만 일단 하나만 체크해두자.
모두가 읽을 수 있어야 하므로 다른건 건들지 않는다
버킷 정책을 수정해야 한다.
1. 모든 사람이 객체를 읽을 수 있어야 한다.
2. 내 계정으로는 쓰기가 가능해야 한다.
이걸 버킷 정책에 그대로 옮기면 된다.
{
"Version": "2012-10-17",
"Id": "Policy1689919765186",
"Statement": [
// 모든 사람에 대한 접근 허용
{
"Sid": "Stmt1689919302606",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::[님 버킷 이름]/*"
},
// 내 계정만 put가능
{
"Sid": "allowGet",
"Effect": "Allow",
"Principal": {
"AWS": [님 계정]
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::[님 버킷 이름]/*"
}
]
}
다음과 같다.
"Principal" -> "AWS"에는
요기 있는 ARN을 적으면 된다.
이렇게 하지 않고
1. 모든 사람에 대한 접근 허용
2. 모든 사람에 대한 접근 거부 -> 내 계정은 제외
하는 방법인
"NotPrincipal"을 사용할 수도 있다.
이렇게 하면 S3설정은 끝난다.
스프링에서 사용해보자
yml파일에는 다음과 같이 아까 Iam에서 발급받은 키를 써준다.
지금부터는 코드만 보여주고 주의할점만 적어두겠다
package com.s3.s3test.config;
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 S3config {
@Value("${cloud.aws.credentials.accessKey}")
private String accessKey;
@Value("${cloud.aws.credentials.secretKey}")
private String secretKey;
@Value("${cloud.aws.region.static}")
private String region;
@Bean
public AmazonS3Client amazonS3Client() {
BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
System.out.println(accessKey + " " + secretKey + " " + region);
return (AmazonS3Client) AmazonS3ClientBuilder
.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.build();
}
}
s3설정
@RestController
@Slf4j
public class controller {
@Autowired
S3service service;
@PutMapping("/custom")
public String custom(@RequestParam(value = "upfile", required = false) MultipartFile[] files) throws IOException {
return service.uploadOnS3( files[0]);
}
}
컨트롤러
package com.s3.s3test.service;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.PutObjectResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.UUID;
@Service
@Slf4j
public class S3service {
@Value("${cloud.aws.s3.bucket}")
private String bucket;
private final AmazonS3 amazonS3;
public S3service(AmazonS3 amazonS3) {
this.amazonS3 = amazonS3;
}
private static String getUuid() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
public String uploadOnS3(final MultipartFile file) throws IOException {
String[] type = file.getOriginalFilename().split("[.]");
String fileName = getUuid() +"." + type[type.length-1];
log.info(fileName);
try {
ObjectMetadata om = new ObjectMetadata();
om.setContentType(file.getContentType());
PutObjectResult result = amazonS3.putObject(
new PutObjectRequest(bucket, fileName, file.getInputStream(), om)
);
} catch (Exception e){
log.error(e.toString());
}
return fileName;
}
}
사진을 올릴 때 s3에 올리고 접근을 하려니까 자꾸 다운로드페이지가 뜨는걸 확인했다.
알아보니까 "applicatioin/octet-stream"으로 설정이 되는 문제라는걸 확인했고, 마침 ObjectMetadata에 contenttype을 설정해주는 부분이 있어서 이걸 활용했다 .
ObjectMetadata.setContentType을 사용해서 file.getContentType()을 이용해 파일의 컨텐츠 타입을 그대로 사용하는것으로 해결했다.
이렇게 하면 accessKey나 secretKey를 틀리면 접속이 거부되고, 정확안 키들을 적어야 s3에 올라가는것을 확인하고,
퍼블릭으로 객체 접근은 누구나 되는것을 확인했다.
끝!