구글링 했을 때 생각보다 정확한 정보가 없길래 글을 작성하게 되었다. 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:::생성한 버킷 이름/*"
}
]
}
다양한 정책 설정 방법은 다음 글을 참고하는 것이 좋을 것 같다.
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 |