inblog logo
|
LifeLog, DevLog
    AWS

    S3, RDS

    KYJTHEYJ's avatar
    KYJTHEYJ
    Jan 31, 2026
    S3, RDS
    Contents
    S3, RDS 의 필요성S3구조보안EC2 연동RDS

    S3, RDS 의 필요성

    운영 환경의 안정적인 상태를 유지하려면 Stateless 구조를 유지해야한다

    그래야 교체와 확장이 용이하고 데이터의 유지보수성이 좋아진다

    그러므로 외부 스토리지와 외부 DB 서비스가 필요하다

    • S3 → 외부 파일 저장소

    • RDS → 외부 DB 서비스

    다양한 서버의 인스턴스를 외부 저장소, 외부 DB 서비스를 이용하게 하면
    가용성도 좋고 Stateless 구조를 유지할 수 있다

    EC2 의 Stateless 유지

    S3

    S3는 AWS가 서비스하는 외부 파일 저장 스토리지 서비스이다

    S3 생성

    우측 상단 버킷 만들기

    다음엔 이름과 ACL 제어 활성화 여부, 퍼블릭 액세스 차단 여부,
    암호화 방식을 설정하면 된다, 우선은 기본 체크 된 내역 그대로 진행한다

    암호화 방식에 대해서는 추후 AWS 가 익숙해지면 포스트 하려한다

    구조

    Bucket

    파일을 담는 저장소 컨테이너 → 폴더와 비슷하다

    • 이름은 리전 전체를 통틀어서 고유해야한다

    • 소문자, 숫자, 하이픈만 허용

    • 문자, 숫자로 시작하며 3~63자 이내

      💡

      [프로젝트명]-[환경]-[용도] 가 보편적이다
      testPj-prod-uploads 같이 짓는다

    Object

    저장된 파일

    Key

    오브젝트의 고유 경로, 이름

    예시

    s3://test_bucket -> bucket
    ├─test/ -> key 의 일부
    │	├─profile/
    │	│    └─test_user1.docs -> key (test/profile/test_user1.docs)
    │	└─test.log -> key (test/test.log)
    └─result
    	└─result.log -> key (result/result.log)
    

    보안

    Public Access 는 전부 차단 되어 있음

    최소 권한만 부여해야함

    필요시엔 IAM Policy 사용

    EC2 연동

    • Spring Cloud AWS 의존성 추가

      • 만약 Parameter store 도 이용 중이면 통합 관리 하는 것이 좋다

    // BOM으로 Spring Cloud AWS Starter 버전 통합 관리
    implementation platform('io.awspring.cloud:spring-cloud-aws-dependencies:4.0.0-RC1')
    implementation 'io.awspring.cloud:spring-cloud-aws-starter-parameter-store'
    implementation 'io.awspring.cloud:spring-cloud-aws-starter-s3'
    • 추가로 yml에 region 설정이 필요하다

    # S3 region 설정
    spring:
      cloud:
        aws:
          region:
            static: ap-northeast-2
    • 파일 크기도 제한하는 것이 좋다

      servlet:
        multipart:
          max-file-size: 10MB
    • 간단한 컨트롤러와 서비스, DTO를 만들어
      업로드와 다운로드 응답을 받을 수 있게 만든다

    • 그런데 S3 는 퍼블릭 액세스가 차단되어있다
      허용하기 위해서 일일히 IAM 을 지정하는 것이 맞을까?
      → Presinged URL 사용

    • Presigned URL은 임시로 접근을 허용하는 서명된 URL
      유효시간을 지녀서 유효시간 내엔 접근이 가능하게 할 수 있음

      💡

      Presigned URL은 임시로 접근을 허용하는 서명된 URL
      유효시간을 지녀서 유효시간 내엔 접근이 가능하게 할 수 있음

      @RestController
      @RequiredArgsConstructor
      public class FileController {
      
          private final S3Service s3Service;
      
          @PostMapping("/files/upload")
          public ResponseEntity<FileUploadResponse> upload(@RequestParam("file") MultipartFile file) {
              String key = s3Service.upload(file);
              return ResponseEntity.ok(new FileUploadResponse(key));
          }
      
          @GetMapping("/files/download-url")
          public ResponseEntity<FileDownURLResponse> getDownloadUrl(@RequestParam String key) {
              URL url = s3Service.getDownloadUrl(key);
              return ResponseEntity.ok(new FileDownURLResponse(url.toString()));
          }
      }
      
      //-----
      
      @Service
      @RequiredArgsConstructor
      public class S3Service {
          // Presigned URL은 임시로 접근을 허용하는 서명된 URL,
          // 유효시간을 지녀서 유효시간 내엔 접근이 가능하게 할 수 있음
          private static final Duration PRESIGNED_URL_EXPIRATION = Duration.ofMinutes(10);
      
          private final S3Template s3Template;
      
          @Value("${spring.cloud.aws.s3.bucket}")
          private String bucket;
      
          public String upload(MultipartFile file) {
              try {
                  String key = "uploads/" + UUID.randomUUID() + "_" + file.getOriginalFilename();
                  s3Template.upload(bucket, key, file.getInputStream());
                  return key;
              } catch (IOException e) {
                  throw new RuntimeException("파일 업로드 실패", e);
              }
          }
      
          public URL getDownloadUrl(String key) {
              return s3Template.createSignedGetURL(bucket, key, PRESIGNED_URL_EXPIRATION);
          }
      }
    • IAM Policy 설정

      {
          "Version": "2012-10-17",
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": ["s3:PutObject", "s3:GetObject"],
                  "Resource": "arn:aws:s3:::{버킷 이름}/{업로드 파일이 담길 폴더명 or 경로}/*"
              }
          ]
      }
      • s3:PutObject → 업로드, s3:GetObject → 다운로드

    • IAM user 에 IAM policy 를 연결 하고 Access key를
      CLI나 로컬로 받아준다, 지금은 개발 코드에서 활용할 것이므로 로컬 코드로 받았다

      // yml 내에
      spring.cloud.credentials.access-key, secret-key 설정이 필요하다
      
      // EC2 환경이라면 굳이 credentials 가 필요하진 않다
      // 다만 Presigned URL의 만료시간이 최대 12시간으로 고정된다
    • 이제 세팅은 완료 되었으니 Postman으로 업로드와 다운로드를 테스트 해보자

      다운로드 URL

    RDS

    RDS 는 AWS 에서 서비스하는 데이터베이스 서비스이다

    AWS 가 대신 백업과 유지관리 기간에 패치를 하며
    리전 별 AZ에 복제본을 유지하므로 장애조치가 가능하며
    콘솔에서 쉽게 스펙 변경을 통해 확장이 가능하다

    인바운드 규칙만 설정하면 쉽게 사용 가능하다

    RDS 의 VPC 내 서브넷 위치는 기본적으로 알 수가 없다
    퍼블릭 액세스를 허용해도 EC2 상으로 접근하는 것이 안전하다

    그러므로 SSH 접근을 통해 로컬 환경의 툴에서도 접근하는 것이 좋다

    모든 DB 툴에서도 이와 같이 SSH 로 EC2 연결 후에 Host 를 잡아주면 잘 잡힌다
    Share article
    Contents
    S3, RDS 의 필요성S3구조보안EC2 연동RDS

    LifeLog, DevLog - https://github.com/KYJTHEYJ

    RSS·Powered by Inblog