학습 목표

객체 모델 — 버킷과 키, 그리고 폴더가 없다는 사실

Amazon S3는 파일 시스템이 아니라 객체 스토리지(object storage)입니다. 데이터는 버킷(bucket) 안에 객체(object)로 저장되고, 객체는 키(key)라는 문자열로 식별됩니다. 블록 단위로 일부만 고쳐 쓰는 동작이 없고, 객체는 통째로 올리거나 통째로 대체합니다.

logs/2026/07/app.log처럼 슬래시가 들어간 키를 콘솔이 폴더처럼 보여 주지만, S3에 디렉터리 구조는 존재하지 않습니다. 슬래시는 키 문자열의 일부일 뿐이고, 앞부분은 접두사(prefix)로 불립니다. 이 사실은 뒤의 성능 절에서 요청 분산의 근거가 됩니다.

S3 객체 모델과 접근 경로 — 폴더가 아니라 접두사 Amazon S3 버킷 하나가 담고 있는 객체 목록은 계층 구조가 아니라 평평한 키 목록입니다. 왼쪽 버킷 안의 네 객체는 슬래시가 들어간 키를 갖지만 그 슬래시는 디렉터리 구분자가 아니라 키 문자열의 일부입니다. 가운데는 객체 하나의 구성으로, 키와 버전 ID와 사용자 메타데이터와 본문 데이터로 이루어집니다. 오른쪽 아래는 REST 엔드포인트의 형태이며 가상 호스팅 방식에서 버킷 이름이 호스트 앞에 오고 리전이 뒤따르며 경로 부분 전체가 하나의 키가 됩니다. 콘솔에서 폴더처럼 보이는 것은 ListObjectsV2 호출에 접두사와 구분자를 주었을 때 같은 접두사를 공유하는 키들을 묶어 보여 주는 표현일 뿐이며, S3 안에 디렉터리라는 실체는 존재하지 않습니다. 버킷 — 평평한 키 목록 my-bucket logs/2026/07/app.log logs/2026/07/db.log images/logo.png index.html 키는 중첩되지 않습니다 — 전부 같은 깊이입니다 객체 하나의 구성 키 (Key) logs/2026/07/db.log 버전 ID 3sL9…Qk (버전 관리 시) 메타데이터 Content-Type, x-amz-meta-* 본문 데이터 0 바이트 ~ 50 TB 식별자 버킷 + 키 + 버전 ID REST 엔드포인트 (가상 호스팅 방식) https:// my-bucket .s3. ap-northeast-2 .amazonaws.com/ logs/2026/07/db.log 버킷 리전 키 전체가 한 덩어리 S3 에 폴더라는 실체는 없습니다 — 슬래시는 키 문자열의 일부일 뿐입니다 콘솔의 폴더 모양은 ListObjectsV2 에 prefix 와 delimiter 를 주어 같은 접두사를 묶어 보여 준 결과입니다
버킷 · 키 · 버전 ID · 메타데이터로 이루어진 S3 객체 모델과 REST 엔드포인트 형태 — 키 안의 슬래시는 디렉터리가 아니라 접두사이며, S3에 폴더라는 실체는 존재하지 않습니다
Amazon S3의 이름 공간과 크기 제약
항목 값 의미
버킷 이름의 범위 파티션 안의 전역 이름 공간 한 파티션의 모든 리전·모든 계정을 통틀어 유일해야 한다. 이미 쓰이는 이름은 만들 수 없다
버킷의 리전 생성 시 지정한 리전에 고정 데이터는 명시적으로 옮기지 않는 한 그 리전을 떠나지 않는다
계정당 범용 버킷 수 기본 할당량 10,000개 승인을 받아 늘릴 수 있으며, 할당량이 10,000을 넘으면 버킷 목록 조회는 페이지네이션이 필요하다
단일 객체 최대 크기 50 TB 2025년 12월에 5 TB에서 상향되었다. 아래 변경 이력 참조
단일 호출 복사 상한 5 GB 이보다 큰 객체를 복사하려면 멀티파트 업로드의 UploadPartCopy를 써야 한다

객체에는 데이터 외에 메타데이터가 붙습니다. Content-Type 같은 시스템 메타데이터, 사용자가 붙이는 사용자 정의 메타데이터, 그리고 접근 제어와 수명 주기 규칙의 필터로 쓰이는 객체 태그가 있습니다. 메타데이터만 따로 고칠 수는 없고, 메타데이터를 바꾸려면 객체 전체를 다시 올려야 합니다.

일관성 모델 — 강력한 읽기 후 쓰기 일관성 SAA 빈출

Amazon S3는 모든 AWS 리전에서 강력한 읽기 후 쓰기 일관성(strong read-after-write consistency)을 제공합니다. 신규 객체를 올린 직후에도, 기존 객체를 덮어쓴 직후에도, 삭제한 직후에도 다음 읽기는 항상 최신 상태를 반환합니다.

추가 요금도, 성능 저하도, 별도 설정도 없습니다. "쓰고 나서 잠깐 기다렸다 읽어야 한다", "재시도 루프를 넣어야 한다" 같은 설계는 이제 필요하지 않습니다.

신규 버킷의 현행 기본값 SAA 빈출

지금 새로 만드는 버킷은 기본적으로 닫혀 있고 기본적으로 암호화됩니다. 이 사실을 모르면 시나리오 문항에서 불필요한 조치를 정답으로 고르게 됩니다.

신규 S3 버킷의 보안 기본값 세 가지와 꺼져 있는 하나 지금 아무 설정 없이 만든 Amazon S3 버킷의 초기 상태를 네 개의 스위치로 보여 줍니다. 퍼블릭 액세스 차단은 켜져 있고, 객체 소유권이 BucketOwnerEnforced 라서 ACL 은 완전히 비활성이며, 새로 올라오는 모든 객체는 SSE-S3 즉 AES-256 으로 자동 암호화됩니다. 세 스위치 모두 기본이 켜짐입니다. 반면 네 번째 스위치인 버킷 버전 관리는 여전히 꺼진 상태로 시작하며 이 값은 지금까지 바뀐 적이 없습니다. "S3 는 기본이 다 열려 있으니 잠가야 한다"는 오래된 설명은 2023년의 기본값 변경 이후로 틀린 말이 되었고, 실제로 직접 켜야 하는 것은 버전 관리 하나입니다. 버전 관리는 삭제와 덮어쓰기로부터의 복구, 그리고 복제 규칙의 전제 조건이기 때문에 중요합니다. 버킷을 만들고 아무 설정도 건드리지 않은 상태 스위치 세 개는 이미 켜져 있고, 하나만 꺼져 있습니다 ON 퍼블릭 액세스 차단 (Block Public Access) 계정·버킷 양쪽에서 네 설정 모두 켜짐 — 버킷 정책으로도 퍼블릭 공개가 막힙니다 기본 ON ACL 비활성 — ObjectOwnership = BucketOwnerEnforced 버킷 소유자가 모든 객체를 소유하고 ACL 은 아예 평가되지 않습니다. 권한은 정책으로만 기본 ON 신규 객체 자동 암호화 — SSE-S3 (AES-256) 업로드가 요청 헤더 없이도 저장 시 암호화됩니다. 추가 요금도 성능 저하도 없습니다 기본 OFF 버킷 버전 관리 (Versioning) 꺼짐이 기본이며 바뀐 적이 없습니다. 덮어쓰기·삭제 복구와 복제 규칙의 전제 조건입니다 기본 "S3 는 기본이 열려 있다"는 설명은 2023년 이후로 틀렸습니다 직접 켜야 하는 것은 버전 관리 하나입니다
신규 버킷의 보안 기본값 세 가지 — 퍼블릭 액세스 차단이 켜져 있고, ACL이 비활성이며, 신규 객체가 SSE-S3로 자동 암호화됩니다. 반면 버전 관리는 여전히 꺼진 상태로 시작합니다
신규 버킷 생성 직후의 기본 상태
설정 기본값 적용 시점
퍼블릭 액세스 차단 켜짐 — 퍼블릭 ACL이 붙은 버킷 생성 요청은 실패한다 2023년 4월
객체 소유권 · ACL BucketOwnerEnforced — ACL 비활성, 모든 객체를 버킷 소유자가 소유 2023년 4월
기본 암호화 SSE-S3(AES-256) 자동 적용 — 추가 요금과 성능 영향 없음 2023년 1월
버전 관리 꺼짐 — 필요하면 직접 켜야 한다 변경된 적 없음

객체 소유권이 BucketOwnerEnforced라는 것은 ACL이 아예 동작하지 않는다는 뜻입니다. 다른 계정이 이 버킷에 객체를 올려도 소유자는 버킷 소유자가 되고, 접근 제어는 전적으로 버킷 정책과 IAM 정책으로 합니다. AWS는 특별한 사유가 없는 한 이 상태를 유지할 것을 권장합니다.

스토리지 클래스 — 접근 빈도와 검색 시간이 기준

스토리지 클래스는 객체 단위 속성입니다. 같은 버킷 안에서 객체마다 다른 클래스를 쓸 수 있고, 올릴 때 지정하거나 나중에 수명 주기 규칙으로 바꿉니다. 지정하지 않으면 S3 Standard입니다.

선택 기준은 두 가지뿐입니다. 얼마나 자주 읽는가와 읽어야 할 때 얼마나 빨리 필요한가입니다. 여기에 최소 저장 기간이라는 제약이 붙어서, 자주 지우는 데이터를 차가운 클래스에 두면 오히려 손해가 나는 구간이 생깁니다.

SAA 출제 범위 스토리지 클래스 비교 — 가용 영역 수, 최소 저장 기간, 최소 청구 객체 크기
클래스 가용 영역 수 접근 시간 최소 저장 기간 최소 청구 크기
S3 Standard 3개 이상 밀리초 없음 없음
S3 Intelligent-Tiering 3개 이상 밀리초 (아카이브 티어 제외) 없음 없음
S3 Standard-IA 3개 이상 밀리초 30일 128 KB
S3 One Zone-IA 1개 밀리초 30일 128 KB
S3 Glacier Instant Retrieval 3개 이상 밀리초 90일 128 KB
S3 Glacier Flexible Retrieval 3개 이상 복원 필요 (분 ~ 시간) 90일 40 KB
S3 Glacier Deep Archive 3개 이상 복원 필요 (시간) 180일 40 KB
스토리지 클래스별 상대 저장 비용 등급. 차가운 클래스일수록 저장 비용은 내려가고 검색 비용과 제약이 올라간다는 교환 관계가 이 그림의 결론입니다. 값은 순위이며 실제 금액은 리전과 시점에 따라 다릅니다
최소 저장 기간과 최소 청구 객체 크기. 30일 · 90일 · 180일의 계단이 수명 주기 규칙에서 전환 시점을 정하는 하한선이 되고, 128 KB · 40 KB의 하한 때문에 작은 객체를 대량으로 옮기면 오히려 손해가 납니다

One Zone-IA — 무엇을 내주고 싼가

S3 One Zone-IA는 데이터를 단 하나의 가용 영역에만 저장합니다. 그래서 Standard-IA보다 저렴하지만, 그 대가가 명확합니다 — 해당 가용 영역이 물리적으로 손실되면 데이터도 손실됩니다. 다른 클래스는 세 개 이상의 지리적으로 분리된 가용 영역에 저장되므로 가용 영역 하나가 사라져도 데이터가 남습니다.

따라서 One Zone-IA가 맞는 데이터는 다시 만들 수 있거나 다른 곳에 원본이 있는 데이터입니다. 원본에서 다시 생성할 수 있는 썸네일, 다른 리전에 복제본이 있는 보조 사본, 온프레미스에 원본이 남아 있는 백업의 2차 사본 같은 것들입니다.

Intelligent-Tiering — 접근 패턴을 모를 때

S3 Intelligent-Tiering은 접근 패턴을 모니터링해서 객체를 자동으로 옮기는 클래스입니다. 선택 기준은 단 하나입니다 — 접근 패턴을 모르거나 계속 변할 때 씁니다. 패턴을 이미 안다면 해당 클래스를 직접 지정하는 편이 낫습니다.

S3 Intelligent-Tiering의 접근 티어와 자동 이동 조건
티어 이동 조건 활성화
Frequent Access 업로드·전환 직후의 기본 티어 기본
Infrequent Access 연속 30일 미접근 기본
Archive Instant Access 연속 90일 미접근 기본
Archive Access 연속 90일 이상 미접근 선택 — 직접 켜야 한다
Deep Archive Access 연속 180일 이상 미접근 선택 — 직접 켜야 한다

중요한 성질이 셋 있습니다. (1) 검색 요금이 없습니다 — 티어가 어디든 읽는 데 추가 검색 요금이 붙지 않습니다. (2) 최소 저장 기간이 없습니다. (3) 대신 객체당 모니터링·자동화 요금이 붙습니다 — 그래서 아주 작은 객체가 아주 많으면 오히려 불리할 수 있습니다.

기본 세 티어는 모두 밀리초 접근이지만, 선택 티어인 Archive Access와 Deep Archive Access는 비동기 접근입니다. 이 두 티어에 있는 객체는 RestoreObject로 먼저 복원해야 읽을 수 있으므로, 애플리케이션이 즉시 읽어야 한다면 켜지 않습니다.

128 KB 미만 객체는 모니터링 대상이 아니며 자동 계층화되지 않고 Frequent Access 티어에 남습니다.

Glacier 계열 — 검색 시간이 클래스를 가른다

Glacier 계열 세 클래스의 차이는 저장 비용이 아니라 읽어야 할 때 얼마나 걸리는가입니다.

Glacier 계열 클래스의 접근 방식과 확인된 검색 시간
클래스 접근 방식 검색 시간
S3 Glacier Instant Retrieval 복원 없이 즉시 읽는다 밀리초
S3 Glacier Flexible Retrieval RestoreObject로 복원 후 읽는다 신속(Expedited) 1–5분 · 대량(Bulk) 5–12시간
S3 Glacier Deep Archive RestoreObject로 복원 후 읽는다 기본 검색 시간 12시간

복원 요청의 티어는 Expedited · Standard · Bulk 세 가지입니다. Flexible Retrieval에서 대량(Bulk) 검색은 무료이고, 신속 검색은 가장 빠른 대신 비쌉니다. 두 클래스 모두 복원 요청은 계정당 초당 최대 1,000 트랜잭션까지 처리됩니다.

Glacier 검색 옵션별 소요 시간. 신속 검색의 분 단위와 Deep Archive의 시간 단위 사이에 두 자릿수 이상의 차이가 있고, 이 간격이 "몇 시간 안에 복구해야 하는가"라는 요구사항에서 클래스를 가릅니다

수명 주기 규칙 — 전환, 만료, 그리고 비용 누수 차단

수명 주기 구성(lifecycle configuration)은 버킷에 붙이는 규칙 집합입니다. 규칙 하나는 필터(어떤 객체에), 상태(켜짐/꺼짐), 동작(무엇을)으로 이루어집니다. 필터는 키 접두사 · 객체 태그 · 객체 크기 또는 이들의 조합으로 지정할 수 있고, 한 버킷의 수명 주기 구성은 최대 1,000개 규칙까지 가질 수 있습니다.

스토리지 클래스 수명주기 전환 타임라인 객체 하나가 만들어진 날부터 210일까지의 시간축 위에서 수명주기 규칙이 어떻게 클래스를 옮기는지 보여 줍니다. 0일부터 30일까지는 S3 Standard, 30일부터 90일까지는 S3 Standard-IA, 90일부터 180일까지는 S3 Glacier Instant Retrieval 또는 Flexible Retrieval, 180일 이후는 S3 Glacier Deep Archive 구간입니다. 각 구간 아래의 막대는 그 클래스의 최소 저장 기간으로 Standard-IA 는 30일, Glacier 계열은 90일, Deep Archive 는 180일입니다. 이 기간을 채우기 전에 삭제하거나 다른 클래스로 옮기면 남은 일수만큼의 저장 요금이 그대로 청구됩니다. 초기 표시자는 45일에 있으며 그 시점의 클래스는 S3 Standard-IA 입니다. 아래 주의 카드는 128 KB 미만 객체가 Standard-IA 나 One Zone-IA 로 전환되지 않는다는 예외를 표시합니다. 이 그림은 금액을 다루지 않고 클래스가 언제 바뀌는가와 어떤 전환이 규칙 위반인가만 다룹니다. 객체 하나가 시간축을 따라 옮겨 다닙니다 수명주기 규칙은 객체 생성 후 경과 일수를 기준으로 클래스를 바꿉니다 45일째 S3 Standard S3 Standard-IA 즉시 접근 · 검색 요금 발생 S3 Glacier Instant / Flexible Retrieval Instant 는 즉시 · Flexible 은 복원 요청 필요 S3 Glacier Deep Archive 0일 30일 90일 180일 경과 일수 → 최소 저장 기간 — 이 막대가 끝나기 전에 삭제하거나 옮기면 남은 일수만큼 저장 요금이 청구됩니다 없음 30일 90일 180일 최소 저장 기간을 채우기 전의 전환 128 KB 미만 객체는 전환 대상에서 빠집니다 Standard-IA · One Zone-IA · Glacier Instant Retrieval · Intelligent-Tiering 으로 가는 전환에 적용됩니다 45일째 — 지금 이 객체의 클래스는 S3 Standard-IA 입니다 전환 시점은 객체 생성일 기준이며, 옮겨 간 클래스의 최소 저장 기간이 다시 시작합니다
객체 하나가 경과 일수에 따라 S3 Standard에서 Standard-IA(30일), Glacier 계열(90일), Deep Archive(180일)로 전환되는 타임라인 — 최소 저장 기간을 어기는 전환과 128 KB 미만 객체의 전환 제외 조건을 함께 표시합니다

전환 규칙의 제약

수명 주기 전환에는 시험에서 반복되는 제약이 셋 있습니다.

만료와 비현재 버전 정리

만료(expiration) 동작은 객체를 지웁니다. 버전 관리가 켜진 버킷에서는 현재 버전의 만료가 삭제 마커를 남기는 것이고, 실제로 저장 용량을 줄이려면 비현재 버전 만료를 함께 설정해야 합니다. 만료된 삭제 마커를 정리하는 동작도 따로 있습니다.

불완전 멀티파트 업로드 정리 SAA 빈출

멀티파트 업로드를 시작하고 완료도 중단도 하지 않으면, 이미 올라간 파트가 계속 저장되고 계속 과금됩니다. 이 파트들은 객체 목록에 보이지 않습니다. 그래서 "버킷에 든 게 별로 없는데 요금이 계속 늘어난다"는 상황이 만들어집니다. 전형적인 비용 누수이고, 원인을 모르면 영원히 찾지 못합니다.

해결은 수명 주기 규칙의 AbortIncompleteMultipartUpload 동작입니다. 시작 후 지정한 일수가 지난 불완전 업로드의 파트를 S3가 자동으로 지웁니다. 신규 버킷을 만들 때 기본으로 넣어 두는 규칙이라고 생각하는 편이 좋습니다.

lifecycle.json — 전환 · 비현재 버전 만료 · 불완전 멀티파트 업로드 정리를 한 구성에 담은 예시
{
  "Rules": [
    {
      "ID": "logs-tiering",
      "Status": "Enabled",
      "Filter": { "Prefix": "logs/" },
      "Transitions": [
        { "Days": 30,  "StorageClass": "STANDARD_IA" },
        { "Days": 90,  "StorageClass": "GLACIER" },
        { "Days": 180, "StorageClass": "DEEP_ARCHIVE" }
      ],
      "Expiration": { "Days": 2555 }
    },
    {
      "ID": "expire-noncurrent-versions",
      "Status": "Enabled",
      "Filter": {},
      "NoncurrentVersionExpiration": { "NoncurrentDays": 90 },
      "ExpiredObjectDeleteMarker": true
    },
    {
      "ID": "abort-incomplete-multipart-uploads",
      "Status": "Enabled",
      "Filter": {},
      "AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 }
    }
  ]
}
apply-lifecycle.sh — 수명 주기 구성 적용과 미완료 업로드 확인 (버킷 이름은 예시입니다)
aws s3api put-bucket-lifecycle-configuration \
  --bucket example-app-logs \
  --lifecycle-configuration file://lifecycle.json

# 목록에 보이지 않는 미완료 멀티파트 업로드를 직접 확인합니다.
aws s3api list-multipart-uploads \
  --bucket example-app-logs \
  --query 'Uploads[].[Key,Initiated,UploadId]' \
  --output table

버저닝, 삭제 마커, MFA Delete, Object Lock

버전 관리를 켜면 같은 키에 쓸 때마다 새 버전 ID가 붙은 버전이 쌓입니다. 상태는 비활성 · Enabled · Suspended 세 가지이고, 한 번 켠 뒤에는 완전한 비활성 상태로 되돌릴 수 없습니다. 중지(Suspended)하면 새 버전이 더 생기지 않을 뿐, 이미 쌓인 버전은 그대로 남습니다.

삭제 마커 — 지운 게 아니라 가린 것

버전 관리 버킷에서 버전 ID 없이 DELETE를 호출하면 객체가 지워지는 것이 아니라 삭제 마커(delete marker)가 최신 버전으로 올라갑니다. 이후 일반 GET은 404를 반환하지만, 데이터는 이전 버전으로 그대로 남아 있고 계속 과금됩니다.

MFA Delete

MFA Delete를 켜면 다음 두 작업에 MFA 장치의 인증 코드가 추가로 필요합니다.

제약이 까다롭습니다. 버킷을 소유한 계정의 루트 사용자만 활성화할 수 있고, 콘솔로는 켤 수 없어 AWS CLI나 API를 써야 하며, 수명 주기 구성과 함께 쓸 수 없습니다. 요청은 HTTPS여야 합니다.

enable-versioning.sh — 버전 관리와 MFA Delete 활성화 (버킷 이름과 시리얼 번호는 예시입니다)
aws s3api put-bucket-versioning \
  --bucket example-app-data \
  --versioning-configuration Status=Enabled

# MFA Delete 는 루트 사용자만, CLI 또는 API 로만 켤 수 있습니다.
aws s3api put-bucket-versioning \
  --bucket example-app-data \
  --versioning-configuration Status=Enabled,MFADelete=Enabled \
  --mfa "arn:aws:iam::123456789012:mfa/root-account-mfa-device 123456"

Object Lock — WORM 보존

S3 Object Lock은 한 번 쓰면 여러 번 읽을 수 있는(write-once-read-many, WORM) 모델로 객체 버전을 보호합니다. 규정 준수 요구를 만족시키는 장치입니다. 버전 관리가 켜져 있어야 하고, 보호는 객체 버전 단위로 적용됩니다.

Object Lock의 보존 모드와 법적 보존
방식 동작 해제
거버넌스 모드(Governance) 대부분의 사용자가 삭제·덮어쓰기를 할 수 없다 s3:BypassGovernanceRetention 권한이 있으면 우회할 수 있다
규정 준수 모드(Compliance) 계정의 루트 사용자를 포함해 누구도 삭제·덮어쓰기를 할 수 없다 불가 — 보존 모드 변경도, 보존 기간 단축도 안 된다
법적 보존(Legal hold) 기간 없이 무기한 보호한다 권한을 가진 사용자가 명시적으로 해제한다

보존 기간은 객체마다 직접 지정하거나 버킷 기본 설정으로 줄 수 있습니다. 기본 설정을 쓰면 객체가 들어올 때마다 생성 시각에 기간을 더해 보존 만료 시각이 계산됩니다. 같은 키에 새로 PUT하면 새 버전이 만들어지고 이전 버전은 원래 보존 기간을 유지합니다.

복제 — CRR과 SRR은 목적이 다르다

복제(replication)는 버킷 사이에 객체를 자동으로, 비동기적으로 복사합니다. 원본과 대상 버킷은 같은 계정일 수도 다른 계정일 수도 있습니다.

S3 복제의 전제 조건과 세 가지 제약 왼쪽 원본 버킷에서 오른쪽 대상 버킷으로 객체가 복제되는 흐름입니다. 양쪽 버킷 모두 버전 관리가 켜져 있어야 하며 한쪽이라도 꺼져 있으면 복제 규칙을 만들 수 없습니다. 원본 버킷 안에는 규칙을 만들기 전부터 있던 객체와 규칙을 만든 뒤 올라온 객체가 있는데, 자동으로 대상에 도착하는 것은 규칙 생성 이후의 객체뿐입니다. 기존 객체를 옮기려면 S3 Batch Operations 의 배치 복제를 따로 실행해야 합니다. 세 번째 제약은 삭제 마커 전파이며 DeleteMarkerReplication 은 기본이 비활성이라 원본에서 객체를 지워도 대상에는 삭제 마커가 생기지 않습니다. 같은 리전이면 SRR, 다른 리전이면 CRR 이라 부르지만 이 세 제약은 양쪽 모두에 똑같이 적용됩니다. 복제는 버전 관리 위에서만 동작합니다 원본 버킷 버전 관리 ON 규칙 생성 이전 객체 이미 버킷에 있던 것들 규칙 생성 이후 객체 새로 올라온 것들 복제 규칙 같은 리전 = SRR 다른 리전 = CRR 복제 안 됨 비동기 복제 대상 버킷 버전 관리 ON 비어 있습니다 배치 복제를 실행해야 채워집니다 규칙 생성 이후 객체 여기만 자동으로 채워집니다 외우면 되는 제약 세 가지 1 버전 관리 필수 원본과 대상 양쪽 모두 켜져 있어야 합니다. 하나라도 꺼져 있으면 규칙 생성 자체가 거부됩니다 2 기존 객체는 제외 규칙을 만들기 전에 있던 객체는 옮겨지지 않습니다. S3 Batch Operations 의 배치 복제를 따로 실행합니다 3 삭제 마커는 선택 DeleteMarkerReplication 은 기본이 비활성입니다. 원본에서 지워도 대상에는 삭제 마커가 생기지 않습니다 "복제를 켰는데 예전 파일이 안 보인다"는 고장이 아니라 설계입니다 복제는 규칙이 생긴 뒤의 쓰기에만 반응합니다 — 과거는 배치 복제의 몫입니다
복제 규칙의 전제와 제약 — 원본과 대상 양쪽에 버전 관리가 필요하고, 규칙을 만들기 전에 있던 객체는 자동으로 복제되지 않으며, 삭제 마커 전파는 기본이 아니라 선택 사항입니다
교차 리전 복제(CRR)와 동일 리전 복제(SRR)의 용도
구분 교차 리전 복제 (CRR) 동일 리전 복제 (SRR)
대상 위치 다른 AWS 리전 같은 AWS 리전
대표 용도 지리적으로 떨어진 곳에 보관해야 하는 규정 준수, 사용자와 가까운 리전에 사본을 두어 지연 시간 단축, 리전 장애 대비 여러 버킷·여러 계정의 로그를 한 버킷으로 모으기, 운영 계정과 테스트 계정 사이 데이터 동기화, 데이터 주권 요구를 지키면서 사본 유지
판단 키워드 "다른 리전", "리전 장애", "지리적 거리", "다른 대륙 사용자" "같은 리전 안에서", "데이터가 리전을 벗어나면 안 된다", "로그 집계"

복제의 전제 조건과 기본 동작

삭제 동작이 특히 자주 출제됩니다. 버전 ID를 명시한 삭제는 대상 버킷에 전파되지 않습니다 — 악의적·실수 삭제로부터 사본을 지키기 위한 설계입니다. 버전 ID 없이 삭제해 생긴 삭제 마커는 최신 규칙 형식에서 기본적으로 복제되지 않고, 필요하면 삭제 마커 복제를 따로 켜야 합니다.

복제로 함께 넘어가는 것과 넘어가지 않는 것도 구분해 둡니다. 객체 메타데이터·태그·ACL 갱신·Object Lock 보존 정보는 함께 복제되고, 다른 규칙이 만들어 낸 복제본은 다시 복제되지 않습니다(연쇄 복제 없음). 복제 시 대상의 스토리지 클래스를 바꾸거나 복제본 소유자를 대상 계정으로 바꿀 수 있습니다.

복제 시간이 예측 가능해야 한다면 S3 복제 시간 제어(S3 RTC)를 켭니다. 신규 객체의 99.99%를 15분 안에 복제하며 서비스 수준 계약이 뒷받침합니다. 배치 복제에는 적용되지 않습니다.

replication.json — 다른 리전 버킷으로 복제하며 대상 클래스를 바꾸는 규칙 (계정 ID와 버킷 이름은 예시입니다)
{
  "Role": "arn:aws:iam::123456789012:role/s3-replication-role",
  "Rules": [
    {
      "ID": "crr-to-dr-region",
      "Priority": 1,
      "Status": "Enabled",
      "Filter": { "Prefix": "critical/" },
      "DeleteMarkerReplication": { "Status": "Enabled" },
      "Destination": {
        "Bucket": "arn:aws:s3:::example-dr-bucket",
        "StorageClass": "STANDARD_IA"
      }
    }
  ]
}

암호화 — 키를 누가 쥐는가 SAA 빈출

서버 측 암호화에는 서로 배타적인 네 가지 옵션이 있습니다. 기능 차이가 아니라 키를 누가 만들고, 누가 보관하고, 사용 기록이 어디에 남는가가 다릅니다. 선택 기준도 거기서 나옵니다.

S3 암호화 네 가지의 키 관리 주체 비교 SSE-S3, SSE-KMS, SSE-C, 클라이언트 측 암호화를 네 개의 열에 놓고 키를 누가 만드는가, 키가 어디에 저장되는가, 요청마다 키를 보내야 하는가, 키 사용 호출이 AWS CloudTrail 에 기록되는가를 비교합니다. SSE-S3 는 AWS 가 키를 만들고 S3 내부에 두며 키 사용 기록이 남지 않습니다. SSE-KMS 는 AWS KMS 에 있는 키를 쓰고 Decrypt 와 GenerateDataKey 호출이 CloudTrail 에 그대로 남으므로 누가 언제 어떤 객체를 복호화했는지 추적할 수 있고 키 정책으로 권한을 따로 나눌 수 있습니다. SSE-C 는 고객이 키를 보관하고 요청마다 HTTPS 로 키를 보내며 S3 는 키를 저장하지 않습니다. 클라이언트 측 암호화는 데이터가 S3 에 닿기 전에 이미 암호문이라 S3 는 평문을 본 적이 없습니다. "키 사용을 감사해야 한다" 또는 "키를 직접 회전하고 접근 권한을 따로 통제해야 한다"는 요구는 강조된 SSE-KMS 열을 가리킵니다. 키는 어디에 있고, 누가 만들고, 사용 기록이 남는가 서버 측 암호화 — S3 가 복호화합니다 클라이언트 측 SSE-S3 SSE-KMS SSE-C 클라이언트 측 CSE 비교 항목 키를 만드는 주체 AWS 고객 또는 AWS KMS 키 고객 고객 키가 저장되는 곳 S3 서비스 내부 AWS KMS 고객 쪽 S3 는 저장 안 함 고객 쪽 또는 KMS 요청마다 키를 보내는가 아니오 아니오 키 ID 만 지정 예 — 매 요청 HTTPS 필수 아니오 이미 암호문 키 사용이 CloudTrail 에 남지 않음 남습니다 Decrypt 남지 않음 S3 는 모름 (KMS 쓰면 남음) 판별 단서 기본값 그대로 손댈 것 없음 감사 · 회전 권한 분리 키를 AWS 에 맡길 수 없음 전송 전부터 암호화 필요 "키 사용을 감사해야 한다" · "키를 직접 회전한다" · "복호화 권한을 따로 나눈다" 세 요구는 전부 SSE-KMS 로 수렴합니다
암호화 네 가지의 키 관리 주체 비교 — 키를 누가 만들고 어디에 두는지, 키 사용 호출이 AWS CloudTrail에 기록되는지가 갈리며, "키 사용을 감사해야 한다"는 요구가 SSE-KMS를 지목하는 이유가 여기 있습니다
서버 측 암호화 네 가지의 키 관리 주체와 선택 기준
방식 API 값 키 관리 이럴 때 고른다
SSE-S3 AES256 S3가 키를 만들고 관리한다 암호화 요구는 있지만 키를 직접 통제할 필요는 없다. 신규 객체의 기본값이다
SSE-KMS aws:kms AWS KMS 키를 쓴다. 고객 관리형 키를 지정할 수 있다 키 정책으로 접근을 통제하고, 키 사용 호출을 CloudTrail로 감사하며, 교체 주기를 통제해야 한다
DSSE-KMS aws:kms:dsse KMS 키로 이중 계층 암호화를 적용한다 규정이 다중 계층 암호화를 명시적으로 요구한다
SSE-C 요청 헤더로 키 전달 고객이 키를 제공하고 S3는 저장하지 않는다 키를 AWS 밖에서 관리해야 한다. 키를 잃으면 데이터를 영원히 못 읽는다

SSE-KMS에서 키를 지정하지 않으면 AWS 관리형 키(aws/s3)가 쓰이고, 고객 관리형 키를 지정하면 키 정책·권한 부여·교체를 직접 통제할 수 있습니다. 키 사용은 KMS API 호출이므로 CloudTrail에 남고, 이것이 감사 요구가 있을 때 SSE-KMS가 답이 되는 이유입니다.

대신 객체마다 KMS 호출이 발생하므로 요청량이 많으면 KMS 요청 한도에 걸릴 수 있습니다. S3 버킷 키(S3 Bucket Key)를 켜면 KMS 호출 횟수를 줄일 수 있습니다.

SSE-C는 키를 요청마다 함께 보내고 S3는 그 키를 저장하지 않습니다. 암호화에 쓴 뒤 폐기하므로, 키를 분실하면 객체를 복호화할 방법이 없습니다. 키가 요청에 실려 가므로 HTTPS가 필수입니다.

네 가지 모두 서버 측 암호화입니다. 클라이언트 측 암호화(client-side encryption)는 별개로, 데이터를 S3에 보내기 전에 애플리케이션이 직접 암호화하는 방식입니다. "AWS가 평문을 절대 볼 수 없어야 한다"는 요구에만 씁니다.

bucket-encryption.json — 고객 관리형 KMS 키를 버킷 기본 암호화로 지정하고 버킷 키를 켜는 구성 (키 ARN은 예시입니다)
{
  "Rules": [
    {
      "ApplyServerSideEncryptionByDefault": {
        "SSEAlgorithm": "aws:kms",
        "KMSMasterKeyID": "arn:aws:kms:ap-northeast-2:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab"
      },
      "BucketKeyEnabled": true
    }
  ]
}

접근 제어 — 요청은 어디서 막히는가

S3 요청이 통과하는 접근 제어 관문의 순서 Amazon S3 로 들어온 요청이 위에서 아래로 네 개의 관문을 지납니다. 첫 관문은 퍼블릭 액세스 차단으로 익명 요청과 퍼블릭 부여만을 대상으로 하며 여기서 걸리면 버킷 정책을 아무리 열어도 소용이 없습니다. 둘째는 버킷 정책이며 리소스 기반 정책이라 명시적 거부가 있으면 여기서 결과가 확정됩니다. 셋째는 요청 주체에 붙은 IAM 자격 증명 기반 정책이고 허용이 어디에도 없으면 암묵적 거부로 끝납니다. 넷째는 객체 ACL 인데 신규 버킷은 ObjectOwnership 이 BucketOwnerEnforced 라 ACL 이 비활성이므로 평가 자체가 일어나지 않습니다. 왼쪽 분기는 프리사인 URL 로, URL 자체가 권한을 새로 만드는 것이 아니라 서명한 주체의 권한을 빌려 오는 것이므로 같은 관문을 똑같이 통과하며 서명자가 권한을 잃으면 URL 도 함께 죽습니다. 접근이 막혔을 때는 어느 관문에서 막혔는지를 이 순서대로 짚어 나가면 됩니다. 요청은 위에서 아래로 관문을 지납니다 — 어디서 막혔는지가 진단의 전부입니다 프리사인 URL URL 은 권한을 새로 만들지 않습니다. 서명한 주체의 권한을 그대로 빌려 옵니다. 서명자가 권한을 잃으면 URL 도 함께 죽습니다 S3 API 요청 서명된 요청 (IAM 주체) 또는 익명 요청 1. 퍼블릭 액세스 차단 익명·퍼블릭 부여만 대상 · 계정과 버킷 양쪽 차단 — 버킷 정책이 열려 있어도 무시됩니다 2. 버킷 정책 (리소스 기반) 버킷에 붙은 정책 · 교차 계정 허용도 여기서 명시적 Deny 는 여기서 확정됩니다 3. IAM 정책 (자격 증명 기반) 요청 주체에 붙은 정책 · SCP 와 권한 경계도 함께 허용이 없으면 암묵적 거부 4. 객체 ACL BucketOwnerEnforced 가 기본 — 평가 안 됨 비활성이라 사실상 없는 관문입니다 허용 — 객체에 접근합니다 앞 관문에서 막히면 뒤 관문이 열려 있어도 소용없습니다 — 진단은 항상 위에서부터
S3 요청이 퍼블릭 액세스 차단, 버킷 정책, IAM 정책, ACL(기본 비활성)을 차례로 통과하는 경로 — 프리사인 URL은 서명한 주체의 권한을 빌린다는 사실을 별도 분기로 표시합니다

버킷 정책과 ACL

접근 제어 수단은 세 가지입니다. IAM 정책(주체에 붙임), 버킷 정책(리소스에 붙임), 그리고 ACL(현행 기본값에서는 비활성)입니다.

퍼블릭 액세스 차단은 이 모든 것보다 앞에서 동작합니다. 버킷 정책이 퍼블릭 접근을 허용하더라도 차단이 켜져 있으면 요청은 거부됩니다. 계정 수준과 버킷 수준 양쪽에서 설정할 수 있고, 어느 한쪽이라도 차단하면 차단됩니다.

bucket-policy.json — HTTPS가 아닌 요청과 암호화되지 않은 업로드를 거부하는 버킷 정책 (버킷 이름은 예시입니다)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyInsecureTransport",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::example-app-data",
        "arn:aws:s3:::example-app-data/*"
      ],
      "Condition": { "Bool": { "aws:SecureTransport": "false" } }
    },
    {
      "Sid": "DenyUnencryptedUploads",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::example-app-data/*",
      "Condition": {
        "StringNotEquals": { "s3:x-amz-server-side-encryption": "aws:kms" }
      }
    }
  ]
}

프리사인 URL — 서명자의 권한을 빌린다

프리사인 URL(presigned URL)은 버킷 정책을 고치지 않고 한시적으로 객체를 내려받거나 올릴 수 있게 하는 장치입니다. 핵심 성질은 하나입니다 — URL은 그것을 만든 주체의 자격 증명과 권한으로 동작합니다. 받는 쪽은 AWS 자격 증명이 없어도 되고, 만든 쪽이 권한이 없으면 URL도 동작하지 않습니다.

프리사인 URL의 유효 기간 — 서명에 쓴 자격 증명이 상한을 정한다
서명에 쓴 자격 증명 최대 유효 기간
IAM 인스턴스 프로파일 최대 6시간
AWS STS 임시 자격 증명 영구 자격 증명으로 서명한 경우 최대 36시간
IAM 사용자 (서명 버전 4) 최대 7일

콘솔에서 만들면 1분에서 12시간 사이로 지정할 수 있고, AWS CLI나 SDK로 만들면 최대 7일까지 지정할 수 있습니다. 임시 자격 증명으로 만들었다면 URL에 적힌 만료 시각과 무관하게 자격 증명이 만료되는 순간 URL도 만료됩니다. 만료 전까지는 여러 번 재사용할 수 있습니다.

presign.sh — 1시간 동안 유효한 다운로드 URL 생성 (버킷과 키는 예시입니다)
aws s3 presign s3://example-app-data/reports/2026-07.pdf \
  --expires-in 3600

정적 웹사이트 호스팅

버킷을 정적 웹사이트로 게시할 수 있습니다. 인덱스 문서와 오류 문서를 지정하고 리다이렉션 규칙을 줄 수 있습니다. 시험에서 주의할 점은 두 가지입니다.

Requester Pays

기본적으로 버킷 소유자가 저장 요금과 데이터 전송 요금을 모두 냅니다. Requester Pays를 켜면 요청자가 요청 요금과 다운로드 요금을 내고, 소유자는 저장 요금만 냅니다. 공개 데이터셋을 배포하되 전송 비용을 떠안고 싶지 않을 때 씁니다.

성능 — 접두사, 멀티파트, 전송 가속화

접두사별 요청 성능

S3는 요청률에 맞춰 자동으로 확장합니다. 확인된 기준은 파티션된 접두사 하나당 초당 최소 3,500건의 PUT·COPY·POST·DELETE와 초당 최소 5,500건의 GET·HEAD입니다. 버킷 안의 접두사 개수에는 제한이 없습니다.

그래서 읽기 성능을 늘리는 방법은 단순합니다 — 접두사를 나눠 병렬화합니다. 접두사 10개로 나누면 초당 55,000건의 읽기까지 확장할 수 있습니다. 다만 확장은 점진적이며 즉시 일어나지 않습니다. 확장이 진행되는 동안 503 Slow Down 오류가 보일 수 있고, 확장이 끝나면 사라집니다.

멀티파트 업로드

큰 객체는 멀티파트 업로드로 나누어 병렬 전송합니다. 처리량이 올라가고, 실패한 파트만 다시 올리면 되며, 업로드를 중간에 멈췄다 재개할 수 있습니다.

내려받을 때는 바이트 범위 요청(byte-range fetch)으로 한 객체를 여러 구간으로 나누어 병렬로 받을 수 있습니다. 앞부분만 필요할 때 앞부분만 받는 용도로도 씁니다.

multipart-upload.sh — 상위 수준 명령이 멀티파트를 자동 처리하는 임계값 설정 (버킷 이름은 예시입니다)
# 상위 수준 명령은 임계값을 넘는 파일을 자동으로 멀티파트 업로드합니다.
aws configure set default.s3.multipart_threshold 64MB
aws configure set default.s3.multipart_chunksize 16MB

aws s3 cp ./large-dataset.tar s3://example-app-data/datasets/

# 전송 가속화 엔드포인트를 사용하려면 설정을 켭니다.
aws configure set default.s3.use_accelerate_endpoint true

Transfer Acceleration

S3 Transfer Acceleration은 버킷 단위 기능으로, Amazon CloudFront의 엣지 로케이션에 먼저 데이터를 받은 뒤 AWS 내부의 최적화된 경로로 버킷까지 전달합니다. 멀리 떨어진 클라이언트가 한 버킷으로 대용량을 올릴 때 효과가 있습니다.

흔한 오해

시험 포인트 정리

확인 문제

이 장의 핵심을 확인하는 10문항입니다. 키보드만으로 완주할 수 있습니다 — 숫자키 1~5로 선택지를 고르고 Enter로 제출합니다.

이어서 볼 곳

공식 문서 출처

이 장의 수치 · 기본값 · 동작은 모두 아래 문서에서 확인했습니다.