이지은님의 블로그
250326 - AWS 사용하기(S3): Simple Storage Service, Bucket Policy, CloudFront, 버킷 생성 및 spring 연결 본문
250326 - AWS 사용하기(S3): Simple Storage Service, Bucket Policy, CloudFront, 버킷 생성 및 spring 연결
queenriwon3 2025. 3. 26. 11:49▷ 오늘 배운 것
AWS설정을 하면서 배운 내용을 정리하고자한다.
AWS관련 내용은 3개의 블로그 포스팅을 하고자하는데, (1) AWS와 EC2 개념, (2) RDS의 개념을 정리하고 EC2와 Spring 프로젝트를 연결하는 방법(프로젝트), (3) S3에 이미지저장하기 로 포스팅을 할 계획이다.
AWS 사용하기(1) (EC2): https://queenriwon3.tistory.com/139
250320 - AWS 사용하기(EC2): EC2 인스턴스 생성, 탄력적 IP(Elastic IP), 추가터미널에서 SSH 클라이언트로
▷ 오늘 배운 것AWS설정을 하면서 배운 내용을 정리하고자한다. AWS관련 내용은 3개의 블로그 포스팅을 하고자하는데, (1) AWS와 EC2 개념, (2) RDS의 개념을 정리하고 EC2와 Spring 프로젝트를 연결하
queenriwon3.tistory.com
AWS 사용하기(2) (RDS): https://queenriwon3.tistory.com/141
250324 - AWS 사용하기(RDS): Storage Auto Scaling, Read Replicas, Multi AZ, RDS와 EC2 연결 및 접속 실습
▷ 오늘 배운 것AWS설정을 하면서 배운 내용을 정리하고자한다.AWS관련 내용은 3개의 블로그 포스팅을 하고자하는데, (1) AWS와 EC2 개념, (2) RDS의 개념을 정리하고 EC2와 Spring 프로젝트를 연결하는
queenriwon3.tistory.com
<<목차>>
1. S3와 CloudFront
1) Amazon S3(Simple Storage Service)
2) S3 버킷 정책(Bucket Policy)
3) CloudFront
2. S3 버킷 생성 및 연결
1) S3 버킷 생성
2) 버킷 > [특정버킷] > 권한 > 버킷정책 > 편집에서 정책 생성
3) spring 프로젝트와 연결
4) S3업로드 확인
1. S3와 CloudFront
:웹 서비스 배포
1) Amazon S3(Simple Storage Service)
Amazon S3는 AWS에서 제공하는 인터넷 스토리지 서비스이다. S3는 대규모 데이터 저장이 가능하며, 높은 내구성과 안정성을 제공한다.
S3의 기능
- 정적 웹 사이트 호스팅: 웹사이트를 인터넷에 배포 가능
- 멀티미디어 파일 저장 및 스트리밍: 이미지, 동영상 등의 저장과 스트리밍
- 애플리케이션 데이터 저장: 데이터베이스 백업 및 애플리케이션 데이터 저장
- 백업 및 복원: 시스템 백업 및 복원 기능
- 아카이브: 장기 보관 데이터를 위한 스토리지 제공
S3 서비스의 장점
- 높은 내구성, 가용성 및 안정성
- 손쉬운 사용 및 관리
- 보안성: 다양한 접근 제어 기능 지원
- 높은 확장성: 데이터 증가에 따른 유연한 확장 가능
1️⃣ Buckets & Objects
S3에서는 데이터를 버킷(Bucket)과 객체(Object) 단위로 저장
- 버킷(Bucket): 데이터를 저장하는 컨테이너 역할 (최상위 폴더 개념)
- 객체(Object): S3에 저장된 개별 파일
- 키(Key): 객체를 식별하는 경로
2) S3 버킷 정책(Bucket Policy)
S3의 접근 제어는 버킷 정책(Bucket Policy)를 통해 설정 가능. JSON 형식의 문서를 사용하여 객체 접근을 제어가능
(예시 - IAM 사용자 USERNAME이 특정 버킷에 접근할 수 있도록 허용)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowUserToGetBucket",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNT-ID:user/USERNAME"
},
"Action": "s3:GetBucketLocation",
"Resource": "arn:aws:s3:::BUCKET-NAME"
}
]
}
1️⃣ ARN (Amazon Resource Name)
AWS 리소스의 고유 식별자
3) CloudFront
CloudFront는 AWS의 CDN(Content Delivery Network) 서비스로, 전 세계 사용자에게 콘텐츠(파일, 동영상 등)를 빠르게 전송
CloudFront의 기능 및 장점
- 빠른 콘텐츠 전송: 세계 곳곳에 분산된 엣지 로케이션(Edge Location)을 활용하여 사용자와 가까운 위치에서 콘텐츠 제공
- HTTPS 적용 가능: CloudFront를 사용하면 SSL/TLS 인증서를 통해 HTTPS 적용 가능
- 보안 강화: DDoS 공격 방어, WAF(Web Application Firewall) 연계 가능
👉 CloudFront와 S3를 함께 사용하는 이유
- S3는 정적 파일을 저장하는 스토리지 역할을 담당
- CloudFront는 CDN 기능을 제공하여 콘텐츠 전송 속도를 개선하고, HTTPS를 지원하며, 보안을 강화함
2. S3 버킷 생성 및 연결
1) S3 버킷 생성
이름까지 설정후 버킷 생성
2) 버킷 > [특정버킷] > 권한 > 버킷정책 > 편집에서 정책 생성
정책 생성기에서 설정후 JSON 값 가져오기
{
"Version": "2012-10-17",
"Id": "Policy1742455559758",
"Statement": [
{
"Sid": "Stmt1742455509912",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::expert-image/*"
}
]
}
arn에 /*를 붙이고 저장
3) spring 프로젝트와 연결
1️⃣ 의존성 추가
implementation 'io.awspring.cloud:spring-cloud-aws-starter-s3:3.3.0'
implementation platform('software.amazon.awssdk:bom:2.27.21')
implementation 'software.amazon.awssdk:s3'
2️⃣ 환경변수 설정
spring:
cloud:
aws:
credentials:
access-key: ${ACCESS_KEY}
secret-key: ${SECRET_KEY}
s3:
bucketName: ${BUCKET_NAME}
region:
static: ap-northeast-2
stack:
auto: false
3️⃣ S3Config
@Configuration
public class S3Config {
@Value("${spring.cloud.aws.credentials.access-key}")
private String accessKey;
@Value("${spring.cloud.aws.credentials.secret-key}")
private String secretKey;
@Bean
public S3Client s3Client() {
AwsBasicCredentials credentials = AwsBasicCredentials.create(accessKey, secretKey);
return S3Client.builder()
.credentialsProvider(StaticCredentialsProvider.create(credentials))
.region(Region.AP_NORTHEAST_2)
.build();
}
}
4️⃣ Controller
@RestController
@RequestMapping("/images")
@RequiredArgsConstructor
public class ImageController {
private final S3ImageUploadService imageService;
@PostMapping
public ResponseEntity<ImageResponse> upload(
@ModelAttribute MultipartFile image
) {
String imageUrl = imageService.uploadImage(image);
return ResponseEntity.ok(new ImageResponse(imageUrl));
}
}
5️⃣ S3Service
@Slf4j
@Service
@RequiredArgsConstructor
public class S3ImageUploadService implements ImageService {
private static final long MAX_FILE_SIZE = 5 * 1024 * 1024;
private final S3Client s3Client;
@Value("${spring.cloud.aws.s3.bucketName}")
private String bucket;
/**
* S3에 이미지 업로드
*/
public String uploadImage(MultipartFile image) {
validateFile(image);
String fileName = UUID.randomUUID() + "_" + image.getOriginalFilename();
try {
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
.bucket(bucket)
.key(fileName)
.contentType(image.getContentType())
.contentLength(image.getSize())
.build();
// S3 업로드
PutObjectResponse response = s3Client.putObject(
putObjectRequest,
software.amazon.awssdk.core.sync.RequestBody.fromBytes(image.getBytes())
);
if (response.sdkHttpResponse().isSuccessful()) {
return fileName;
} else {
throw new RuntimeException("S3 업로드 실패: " + response.sdkHttpResponse().statusText().orElse("Unknown error"));
}
} catch (IOException e) {
throw new RuntimeException("파일 업로드 중 오류 발생", e);
}
}
/**
* 파일 검증: 허용된 파일 형식 및 크기 체크
*/
private void validateFile(MultipartFile image) {
if (image.isEmpty()) {
throw new IllegalArgumentException("파일이 비어 있습니다.");
}
// 파일 확장자 검사 (MIME 타입 외에도 확장자로 검사)
String fileExtension = Objects.requireNonNull(image.getOriginalFilename()).substring(image.getOriginalFilename().lastIndexOf('.') + 1).toLowerCase();
if (!Set.of("jpg", "jpeg", "png").contains(fileExtension)) {
throw new IllegalArgumentException("허용되지 않는 파일 형식입니다. (jpg, jpeg, png만 가능)");
}
if (image.getSize() > MAX_FILE_SIZE) {
throw new IllegalArgumentException("파일 크기가 5MB를 초과할 수 없습니다.");
}
}
}
파일 검증 및 파일 업로드
4) S3업로드 확인
파일을 업로드하여 S3에 업로드된 파일경로 확인