Amazon S3(Simple Storage Service) 는 AWS의 object storage 서비스이다. 파일을 서버의 특정 디렉터리에 저장하는 방식이 아니라, bucket이라는 container 안에 object를 저장한다.
이미지 출처: Wikimedia Commons - Amazon-S3-Logo.svg
S3를 처음 쓸 때는 다음 세 가지 개념을 먼저 잡으면 된다.
| 개념 | 의미 |
|---|---|
| Bucket | object를 담는 최상위 container |
| Object | S3에 저장되는 파일과 metadata |
| Key | bucket 안에서 object를 식별하는 이름 |
예를 들어 다음 경로가 있다고 하자.
s3://my-blog-assets/images/logo.png
여기서 my-blog-assets는 bucket이고, images/logo.png는 object key이다.
S3를 언제 쓰는가
S3는 파일 저장소처럼 사용할 수 있지만, 일반적인 filesystem과는 다르다. Object storage이므로 파일 append나 random write보다는 object 단위 업로드/다운로드에 적합하다.
대표적인 사용 사례는 다음과 같다.
| 사용 사례 | 설명 |
|---|---|
| 정적 파일 저장 | 이미지, 동영상, PDF, CSS/JS asset |
| 백업 | DB dump, log archive |
| 데이터 레이크 | 분석용 원본 데이터 저장 |
| 배포 asset | frontend build 결과물, release artifact |
| Presigned URL | 제한된 시간 동안 private object 접근 허용 |
S3는 웹 서버에 파일을 직접 올리는 것보다 확장성과 내구성 측면에서 유리하다. 대신 권한, 공개 접근, lifecycle, 비용 관리를 신경 써야 한다.
Bucket 생성
AWS Console 기준 기본 흐름은 다음과 같다.
- AWS Console에서 S3로 이동한다.
Create bucket을 선택한다.- Region을 선택한다.
- Bucket name을 입력한다.
- Object Ownership, Block Public Access, Versioning, Encryption 설정을 확인한다.
- Bucket을 생성한다.
Bucket name은 전역적으로 unique해야 한다. 또한 생성 후 bucket name과 region은 쉽게 바꾸는 대상이 아니므로 처음에 명확하게 정하는 것이 좋다.
예시 naming:
br4c3-blog-assets-prod
br4c3-blog-backup-dev
company-service-logs-apne2
Bucket name에는 민감한 정보를 넣으면 안 된다. Object URL이나 log에 노출될 수 있기 때문이다.
Public Access
S3에서 가장 많이 실수하는 부분은 public access이다. 기본적으로는 public access를 막는 것이 안전하다.
AWS S3 console도 기본적으로 Block Public Access를 켜는 방향을 권장한다. 정적 웹사이트 hosting처럼 공개 object가 필요한 경우에만 의도적으로 풀어야 한다.
| 상황 | 권장 |
|---|---|
| 사용자 업로드 파일 | private 유지 |
| 백업 파일 | private 유지 |
| 내부 로그 | private 유지 |
| 공개 이미지 asset | CloudFront 또는 제한된 public policy 검토 |
| 정적 웹사이트 hosting | public access와 bucket policy를 명확히 설정 |
S3 object를 공개해야 한다면 다음을 구분해야 한다.
bucket 전체를 공개할 것인가?
특정 prefix만 공개할 것인가?
CloudFront를 앞에 둘 것인가?
일시적 접근이면 presigned URL로 충분한가?
대부분의 application에서는 bucket 전체 공개보다 presigned URL이나 CloudFront 조합이 더 안전하다.
Object 업로드
Console에서는 bucket에 들어간 뒤 Upload를 선택하고 파일을 추가하면 된다.
CLI를 사용하면 다음처럼 업로드할 수 있다.
aws s3 cp ./logo.png s3://my-blog-assets/images/logo.png
디렉터리를 재귀적으로 올릴 수도 있다.
aws s3 cp ./dist s3://my-blog-assets/dist --recursive
동기화가 목적이면 sync가 더 적합하다.
aws s3 sync ./dist s3://my-blog-assets/dist --delete
cp --recursive는 파일을 복사하고, sync는 local과 S3의 차이를 비교해 맞춘다.
정적 asset 배포에는 보통 sync가 편하다.
Object 다운로드
Object 하나를 다운로드하려면 다음처럼 쓴다.
aws s3 cp s3://my-blog-assets/images/logo.png ./logo.png
폴더처럼 보이는 prefix 전체를 내려받으려면 --recursive를 붙인다.
aws s3 cp s3://my-blog-assets/dist ./dist --recursive
S3에는 실제 directory가 있는 것이 아니라 key prefix가 있을 뿐이다.
images/logo.png에서 images/는 directory처럼 보이지만, 본질적으로는 object key의 일부이다.
권한 모델
S3 접근은 IAM policy, bucket policy, ACL, Block Public Access 등 여러 층에서 결정된다. 초보자는 다음 기준으로 이해하면 된다.
| 권한 요소 | 역할 |
|---|---|
| IAM policy | user/role이 어떤 S3 API를 호출할 수 있는지 결정 |
| Bucket policy | bucket 입장에서 누가 접근 가능한지 결정 |
| Block Public Access | public policy/ACL을 전역적으로 막는 안전장치 |
| ACL | object/bucket 단위 legacy access control |
최근 S3 사용에서는 ACL을 끄고 IAM policy와 bucket policy 중심으로 관리하는 것이 일반적이다.
예를 들어 특정 bucket에 object upload만 허용하려면 IAM policy는 다음 형태가 된다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:PutObject"],
"Resource": "arn:aws:s3:::my-blog-assets/uploads/*"
}
]
}
권한은 항상 최소 권한 원칙으로 시작하는 것이 좋다.
필요한 bucket만
필요한 prefix만
필요한 action만
허용한다.
Presigned URL
Private object를 일시적으로 사용자에게 제공해야 할 때 presigned URL을 사용할 수 있다. Presigned URL은 정해진 시간 동안만 유효한 서명된 URL이다.
예를 들어 AWS CLI에서는 다음처럼 만들 수 있다.
aws s3 presign s3://my-private-bucket/reports/report.pdf --expires-in 300
이 URL은 300초 동안만 접근 가능하다.
Presigned URL이 유용한 경우는 다음과 같다.
| 상황 | 설명 |
|---|---|
| private 파일 다운로드 | 로그인한 사용자에게만 일시적으로 제공 |
| 직접 업로드 | 서버를 거치지 않고 client가 S3로 업로드 |
| 민감한 파일 공유 | URL 만료 시간을 짧게 설정 |
Public bucket을 만들기 전에 presigned URL로 해결 가능한 문제인지 먼저 확인하는 것이 좋다.
Versioning
S3 Versioning을 켜면 같은 key에 여러 version의 object를 유지할 수 있다.
images/logo.png version 1
images/logo.png version 2
images/logo.png version 3
Versioning의 장점은 실수로 덮어쓰기나 삭제를 했을 때 복구 가능성이 생긴다는 것이다. 하지만 version이 계속 쌓이므로 비용도 증가할 수 있다.
운영에서는 versioning과 lifecycle rule을 함께 고려한다.
오래된 version은 30일 후 삭제
오래된 log는 Glacier 계열 storage class로 이동
임시 upload는 7일 후 삭제
Lifecycle Rule
S3는 lifecycle rule로 object를 자동 전환하거나 삭제할 수 있다.
예를 들어 log archive 정책은 다음처럼 설계할 수 있다.
| 기간 | 처리 |
|---|---|
| 0~30일 | S3 Standard |
| 30일 이후 | 저비용 storage class로 전환 |
| 365일 이후 | 삭제 |
이런 정책은 log, backup, temporary upload에 유용하다. S3는 저장 비용뿐 아니라 request, data transfer, retrieval 비용도 고려해야 하므로 lifecycle은 비용 관리에 중요하다.
정적 웹사이트와 CloudFront
S3는 정적 웹사이트 hosting에도 사용할 수 있다. 하지만 실제 서비스에서는 S3를 직접 공개하기보다 CloudFront를 앞에 두는 경우가 많다.
Browser -> CloudFront -> S3 bucket
CloudFront를 쓰면 다음 장점이 있다.
| 장점 | 설명 |
|---|---|
| CDN cache | 사용자와 가까운 edge location에서 응답 |
| HTTPS | custom domain과 TLS 설정 |
| Origin 보호 | S3 bucket을 직접 public으로 열지 않는 구조 가능 |
| 캐시 제어 | asset별 TTL 관리 |
단순 실습은 S3 static hosting만으로 충분하지만, 운영 서비스에서는 CloudFront를 같이 검토하는 것이 좋다.
삭제와 비용 정리
S3는 bucket을 만들었다고 바로 큰 비용이 발생하는 것은 아니지만, object 저장과 요청, 전송에는 비용이 발생한다. 실습 후에는 object와 bucket을 정리하는 것이 좋다.
aws s3 rm s3://my-blog-assets --recursive
aws s3 rb s3://my-blog-assets
Bucket을 삭제하려면 먼저 비어 있어야 한다. Versioning이 켜진 bucket은 delete marker와 old version까지 고려해야 하므로 정리가 더 복잡할 수 있다.
정리
S3의 핵심 모델은 단순하다.
Bucket 안에 Object를 Key로 저장한다.
접근은 IAM과 bucket policy로 제어한다.
공개 접근은 기본적으로 막고, 필요한 경우에만 의도적으로 연다.
처음 사용할 때는 다음 순서로 익히면 된다.
- Bucket을 만든다.
- Object를 업로드한다.
- IAM 권한을 최소화한다.
- Public access를 신중히 다룬다.
- Versioning과 lifecycle로 복구와 비용을 관리한다.
- 실습 후 object와 bucket을 정리한다.