

콘텐츠를 전 세계에 빠르게 배포하기 위해 AWS CloudFront(CDN)를 자주 사용합니다.
그런데 CloudFront가 속한 계정(A) 과 실제 정적 파일을 담은 S3 버킷이 있는 계정(B) 이 서로 다를 때가 있죠.
보안 격리
운영 분리
재무/청구 분리
이때 Origin Access Control(OAC) 과 S3 버킷 정책을 조합하면 퍼블릭 URL을 전혀 공개하지 않으면서 계정 간 안전하게 연동할 수 있습니다.
아래 글에서는 실제 콘솔 단계, 정책 샘플, Prefix(경로) 처리 등 실무 팁까지 모두 다룹니다.
| 역할 | 계정 | 서비스 | 비고 |
|---|---|---|---|
| CDN, 캐싱 | A | CloudFront | OAC 서명 사용 |
| 정적 파일 저장 | B | Amazon S3 | 버킷 정책으로 CloudFront만 허용 |
[User or Browser]
│
│ HTTP/HTTPS
▼
[CloudFront (Origin Access Control)]
│
│ SigV4 Signed Request
▼
(S3 Bucket - Account B)
▲
│
│ Object
▼
[CloudFront (Cache)]
▲
│
│ Cached Content
▼
[User or Browser]
| OAI(구 방식) | OAC(신 방식) | |
|---|---|---|
| 서명 방식 | Canonical User ID | SigV4 (IAM‑like) |
| 리전 제약 | Global | 리전별 지정 |
| 관리 편의성 | 중간 | 콘솔·CLI 모두 직관적 |
| 미래 지향성 | 단계적 폐지 예정 | 신규 서비스 권장 |
CloudFront 콘솔 → Distributions → 대상 배포 선택
Origins → Create origin
Origin domain: my-bucket.s3.ap-northeast-2.amazonaws.com (계정 B 버킷엔드포인트)
Origin access control settings → Create control
Sign requestsSigV4Amazon S3ap-northeast-2 (버킷 리전)저장 후, Access control 칸에 방금 만든 OAC 선택 → Create origin
`
모든 퍼블릭 액세스 차단(Block Public Access) = ON 상태를 전제로!
{
"Version":"2012-10-17",
"Statement":[
{
"Sid":"AllowCloudFrontOAC",
"Effect":"Allow",
"Principal":{"Service":"cloudfront.amazonaws.com"},
"Action":"s3:GetObject",
"Resource":"arn:aws:s3:::my-bucket/*",
"Condition":{
"StringEquals":{
"AWS:SourceArn":"arn:aws:cloudfront::123456789012:origin-access-control/ocontrol/EXAMPLE",
"AWS:SourceAccount":"123456789012"
}
}
}
]
}
cloudfront.amazonaws.com (서비스 주체)ocontrol/…)"Condition":{
"StringEquals":{
"AWS:SourceArn":[
"arn:aws:cloudfront::123456789012:origin-access-control/ocontrol/AAA111",
"arn:aws:cloudfront::123456789012:origin-access-control/ocontrol/BBB222"
],
"AWS:SourceAccount":"123456789012"
}
}
CloudFront → Origin 요청 시 자동으로 붙는 고정 Prefix
| Origin Path | Viewer 요청 | Origin 요청 (S3) |
|---|---|---|
| (빈 값) | /logo.png | /logo.png |
/assets | /logo.png | /assets/logo.png |
/review | /img/a.jpg | /review/img/a.jpg |
/로 시작 · 끝 슬래시 필요 없음/review/... 유지/... (Prefix 제거)function handler(event) {
var req = event.request;
// "/review" 앞부분 제거
req.uri = req.uri.replace(/^\/review/, '') || '/';
return req;
}
Associations
Viewer request/review/* 또는 Default (*)CloudFront Functions → Create function → 코드 입력
Build → Publish
배포의 Behaviors → Edit → Function associations → Viewer request에 붙이기
Deploy 후 테스트
curl -I https://d123.cloudfront.net/review/test.txt/test.txt 로 접근되는지 확인