Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

이지은님의 블로그

250326 - AWS 사용하기(S3): Simple Storage Service, Bucket Policy, CloudFront, 버킷 생성 및 spring 연결 본문

TIL

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의 기능 및 장점
  1. 빠른 콘텐츠 전송: 세계 곳곳에 분산된 엣지 로케이션(Edge Location)을 활용하여 사용자와 가까운 위치에서 콘텐츠 제공
  2. HTTPS 적용 가능: CloudFront를 사용하면 SSL/TLS 인증서를 통해 HTTPS 적용 가능
  3. 보안 강화: 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 업로드된 파일경로 확인