구글링 했을 때 생각보다 정확한 정보가 없길래 글을 작성하게 되었다. PresignedURL을 발급받기 위해서 다음과 같은 과정이 필요하다.
- AWS S3 버킷 생성
- 버킷 정책 설정
- PresignedURL을 발급받을 IAM 생성
- 코드 작성
1. AWS S3 버킷 생성
AWS S3 서비스 탭으로 이동해서 버킷 생성하기를 수행하자. 버킷 이름만 잘 짓고 다른 모든 설정은 건들 필요가 없다. 그러나 이 부분은 선택 사항인데, 나의 경우 개발하는 프로젝트에서 프로필 사진을 업로드하면 해당 사진의 공개 URL을 통해서 누구나 접근할 수 있어야 하기 때문에 버킷에 대한 퍼블릭 액세스를 모두 허용해주었다.
생성하면 다음과 같이 보일 것이다.
2. 버킷 정책 설정
생성한 버킷의 세부 정책을 설정하자. (버킷 클릭 -> 권한 -> 버킷 정책 편집)
UI가 잘 되어있기 때문에 쉽게 설정할 수 있다. 아래 설정은 버킷에 대한 접근 중에 객체에 대한 접근과 객체 버전 정보를 가져오는 접근을 허용하는 설정이다. 아래 설정을 그대로 사용하려면 Resource에 자신이 생성한 버킷 이름을 넣어주도록 하자.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicRead",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion"
],
"Resource": "arn:aws:s3:::생성한 버킷 이름/*"
}
]
}
다양한 정책 설정 방법은 다음 글을 참고하는 것이 좋을 것 같다.
Bucket policy examples - Amazon Simple Storage Service
Before using this policy, replace the 54.240.143.0/24 IP address range in this example with an appropriate value for your use case. Otherwise, you will lose the ability to access your bucket.
docs.aws.amazon.com
3. IAM 생성
IAM은 그냥 권한을 가진 사용자이다. S3에 대한 접근 권한을 가진 사용자를 생성할 것이고 이 사용자를 통해서 PresignedURL을 발급받을 것이다. (AWS 서비스 검색 -> IAM 검색 -> 사용자 -> 사용자 생성)
사용자 이름을 설정하고 자격 증명 유형은 액세스 키를 선택하자.
다음으로 넘어가서 권한 설정을 진행하자. 나는 기존 정책에 있는 S3FullAccess를 선택했다.
그리고 사용자를 생성하면 다음과 같이 키를 얻을 수 있다. 이 키는 잃어버리면 사용자를 다시 생성해야 할 것이다. (아마도) 그러니까 CSV를 다운로드하던 잘 적어두던 하자. (사진에 있는 사용자는 이미 지워진 사용자)
4. 코드 작성
먼저 의존성을 추가해줘야 하는데, build.gradle에 추가해주도록 하자.
implementation 'software.amazon.awssdk:s3:2.17.217'
testImplementation 'software.amazon.awssdk:s3:2.17.217'
그리고 해당 의존성을 활용하여 PresignedURL을 발급받는 코드는 다음과 같다.
package ???
import static org.junit.jupiter.api.Assertions.*;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.Duration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.PresignedPutObjectRequest;
import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest;
@SpringBootTest
@ActiveProfiles("test")
class UploadServiceImplTest {
@Test
void getPreSignedUrl() {
try {
AwsCredentialsProvider credentialsProvider = StaticCredentialsProvider.create(
AwsBasicCredentials.create("access key 입력", "secret key 입력"));
/*
* preSigner example code link
* https://www.programcreek.com/java-api-examples/?api=software.amazon.awssdk.services.s3.presigner.S3Presigner
* */
S3Presigner presigner = S3Presigner.builder()
.region(Region.AP_NORTHEAST_2)
.credentialsProvider(credentialsProvider)
.build();
PutObjectRequest objectRequest = PutObjectRequest.builder()
.bucket("아까 생성한 버킷 이름")
.key("업로드할 파일의 이름")
.contentType("text/plain")
.build();
PutObjectPresignRequest presignRequest = PutObjectPresignRequest.builder()
.signatureDuration(Duration.ofMinutes(2)) // PresignedURL의 유효시간
.putObjectRequest(objectRequest)
.build();
PresignedPutObjectRequest presignedRequest = presigner
.presignPutObject(presignRequest);
String myURL = presignedRequest.url().toString();
System.out.println("Presigned URL to upload a file to: " +myURL);
System.out.println("Which HTTP method needs to be used when uploading a file: " +
presignedRequest.httpRequest().method());
// Upload content to the Amazon S3 bucket by using this URL
URL url = presignedRequest.url();
// Create the connection and use it to upload the new object by using the presigned URL
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type","text/plain");
connection.setRequestMethod("PUT");
OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
out.write("This text was uploaded as an object by using a presigned URL.");
out.close();
connection.getResponseCode();
System.out.println("HTTP response code is " + connection.getResponseCode());
}
catch (Exception e) {
e.printStackTrace();
}
}
}
위 코드를 실행하면 다음과 같이 버킷에 데이터가 업로드 되는 것을 볼 수 있다.
지금까지 PresignedURL을 발급받고 이를 통해 객체를 업로드하는 것까지 수행해보았다.
추가적으로 내가 올린 코드는 AWS 공식 문서를 바탕으로 작성되었기 때문에 코드 퀄리티에 대하여 걱정할 필요는 없을 것 같다.
reference
https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPreSignedURL.html
https://docs.aws.amazon.com/ko_kr/sdk-for-java/latest/developer-guide/examples-s3-presign.html
'Spring' 카테고리의 다른 글
단위 테스트 given-when-then 패턴과 BDDMockito (0) | 2022.08.08 |
---|---|
Spring Security Form Login 사용과 동시성 세션 제어 (0) | 2022.07.17 |
[Spring Boot] Hibernate : GenerationTarget encountered exception accepting command (0) | 2022.06.21 |
MockMvc 테스트 시 한글 깨짐 (0) | 2022.05.21 |
웹 스코프 (0) | 2022.04.30 |