Amazon S3 파일 서버 - upswp/THXSTORE GitHub Wiki
Amazon Simple Storage Service(Amazon S3)는 인터넷 스토리지 서비스입니다.
언제 어디서든지 데이터를 저장하고 검색하여 사용 가능합니다.
- 버킷 만들기 - 데이터를 저장하는 버킷을 만들고 해당 버킷의 이름을 지정합니다. 버킷은 데이터 스토리지를 위한 Amazon S3의 기본 컨테이너입니다.
- 데이터 저장 - 버킷에 데이터를 무한정으로 저장합니다. Amazon S3 버킷에 객체를 원하는 만큼 업로드할 수 있으며, 각 객체에 최대 5TB의 데이터를 포함할 수 있습니다. 각 객체는 고유한 개발자 할당 키를 사용하여 저장 및 검색합니다.
- 데이터 다운로드 - 데이터를 직접 다운로드하거나 다른 사람이 다운로드할 수 있도록 합니다. 언제든지 데이터를 직접 다운로드하거나 다른 사람이 다운로드하도록 허용할 수 있습니다.
- 권한 - 데이터를 Amazon S3 버킷으로 업로드 또는 다운로드하려는 사용자에게 액세스 권한을 부여하거나 해당 권한을 거부합니다. 3가지 유형의 사용자에게 업로드 및 다운로드 권한을 부여할 수 있습니다. 인증 메커니즘을 사용하면 데이터가 무단으로 액세스되지 않도록 보호하는 데 도움이 될 수 있습니다.
- 표준 인터페이스 - 모든 인터넷 개발 도구 키트에서 사용할 수 있도록 설계된 표준 기반 REST 및 SOAP 인터페이스를 사용합니다.
Spring과 S3를 연동해서 파일 저장과 주소 반환 기능만 적용했습니다.
aws 계정이 필요합니다. 여기서는 프리티어로 s3를 만들며 설명하겠습니다.
- 계정 아이디를 누르고 [내 보안 자격 증명]을 클릭합니다. 그 후, 좌측 목차에서 [사용자] 클릭 후 [사용자 추가]를 합니다.
-
사용자 세부 정보 설정을 합니다.
[사용자 이름]을 입력 후, 우리는 프로그래밍으로 접근할 것이기 때문에 [프로그래밍 박식 엑세스]를 선택합니다.
-
기존 정책 직접 연결에서 [AmazonS3FullAccess]를 선택하고 넘어갑니다.
-
계속 다음다음다음... 눌러서 생성합니다.
그럼 엑세스키와 비밀키가 생성된 것을 확인할 수 있습니다.
- s3에 접속 후, 버킷만들기를 클릭합니다.
- 버킷이름과 리전을 선택합니다.
- 엑세스 차단 설정을 해제합니다. 그리고 생성합니다.
- 생성된 버킷에 들어간 후, 권한에서 버킷 정책 편집을 클릭합니다.
- 버킷 정책 편집에서 [버킷 ARN]부분을 복사 후, [정책 생성기]를 클릭합니다.
-
버킷 정책 생성을 아래와 같이 새줍니다. [ARN]은 이전 복사한 것을 넣어주고, 마지막에 /*를 붙입니다.
[Actions]에서 GetObject를 선택합니다.
- 정상적으로 만들어졌고, Generate Policy를 눌러서 정책 코드를 복사합니다.
- 다시 [버킷 정책 편집]으로 돌아와서 붙여넣고 저장합니다.
- 그러면 [퍼블릭 엑세스 가능]이라는 창이 나오고, 테스트로 업로드한 사진을 링크따라 들어가서 확인이 가능해집니다.
- gradle.build
dependencies{
implementation platform('com.amazonaws:aws-java-sdk-bom:1.11.934')
implementation 'com.amazonaws:aws-java-sdk-s3'
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
}
- application.xml
cloud:
aws:
credentials:
accessKey: 입력
secretKey: 입력
s3:
bucket: thxstore
region:
static: ap-northeast-2
stack:
auto: false
aws에서 확인 후, accessKey, secretKey 입력
** 위 [accessKey, SecurityKey 생성] 파트에서 4번 참조
-
ImageService.java
서비스에서 호출하여 사용하는 부분입니다.
@Service
@Transactional
@RequiredArgsConstructor
public class ImageService {
private final AwsS3Service awsS3Service;
// 자신의 버킷 주소로 입력하셔야합니다
public static final String DOMAIN_NAME = "thxstore.s3.ap-northeast-2.amazonaws.com";
public String createImage(MultipartFile image) throws IOException {
String imgName = awsS3Service.uploadImage(image);
// 반환할 주소값
String imgPath = "https://" + DOMAIN_NAME + "/" + imgName;
return imgPath;
}
}
-
AwsS3Service.java
Amazon S3 서버에 실제로 저장되는 부분입니다. ImageService.java는 사용자 편의를 위해 만들어진 클래스 파일이며, AwsS3Service.java는 실제 서버 버킷에 형식에 맞춰 저장이 됩니다.
@Service
@RequiredArgsConstructor
public class AwsS3Service {
private final AwsConfiguration awsConfiguration;
private final AwsS3Property awsS3Property;
private AmazonS3 amazonS3;
@Transactional
public String uploadImage(MultipartFile image) throws IOException {
amazonS3 = awsConfiguration.setS3Client();
UUID uuid = UUID.randomUUID();
long time = System.currentTimeMillis();
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss", Locale.KOREA);
// 시간 + 파일이름으로 중복 X
String imageName = uuid + "-" + formatter.format(time) + image.getOriginalFilename();
File uploadFile = convert(image)
.orElseThrow(() -> new IllegalArgumentException("MultipartFile -> File로 전환이 실패했습니다."));
amazonS3.putObject(new PutObjectRequest(awsS3Property.getBucket(), imageName, uploadFile)
.withCannedAcl(CannedAccessControlList.PublicRead));
removeNewFile(uploadFile);
return imageName;
}
private Optional<File> convert(MultipartFile file) throws IOException {
File convertFile = new File(file.getOriginalFilename());
if(convertFile.createNewFile()) {
try (FileOutputStream fos = new FileOutputStream(convertFile)) {
fos.write(file.getBytes());
}
return Optional.of(convertFile);
}
return Optional.empty();
}
private void removeNewFile(File targetFile) {
targetFile.delete();
}
}
-
awss3property.java
aws 권한 클래스(application.xml)
@ConstructorBinding
@ConfigurationProperties(prefix = "aws.s3")
@NoArgsConstructor
@Getter
public class AwsS3Property {
@Value("${cloud.aws.credentials.accessKey}")
private String accessKey;
@Value("${cloud.aws.credentials.secretKey}")
private String secretKey;
@Value("${cloud.aws.s3.bucket}")
private String bucket;
@Value("${cloud.aws.region.static}")
private String region;
}
- AwsConfiguration.java
@Configuration
@EnableConfigurationProperties(value = {AwsS3Property.class})
@RequiredArgsConstructor
public class AwsConfiguration {
private final AwsS3Property awsS3Property;
@PostConstruct
public AmazonS3 setS3Client() {
AWSCredentials credentials = new BasicAWSCredentials(awsS3Property.getAccessKey(), awsS3Property.getSecretKey());
return AmazonS3ClientBuilder
.standard()
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.withRegion(awsS3Property.getRegion())
.build();
}
}
위와 같은 S3 방법은 권한을 열었기 때문에 보안에 취약할 수 있습니다. 엑세스 차단 설정이라던가 엑세스키 비밀키 설정, 버킷 정책 편집을 더 강화하는 것도 좋은 방법입니다.