
안녕하세요. 케이리버스의 Aiden입니다. 현재 케이리버스는 여러 가지 변곡점을 준비하고 있습니다. 눈에 보이는 화면은 크게 달라지지 않지만, 운영 효율화와 관련된 네 가지 거대한 마일스톤을 정리하고 있습니다.
- 서버 이벤트 주도 아키텍처 도입
- 인프라 구조 변경(K8S의 도입)
- AWS Lambda를 활용한 웹 크롤러 구축
- Github action과 argoCD를 이용한 CI/CD 자동화
각각의 항목들이 하루아침에 이루어지는 작업이 아니지만 꾸준히 진행하여 2025년 K-리그의 시작 일정에 맞게 1, 2, 3번 마일스톤을 내년 3월까지 마무리하려고 합니다. 너무 덩치가 큰 마일스톤들을 해치워야 하다 보니 케이리버스의 소식을 전달해드리는 간격이 조금씩 멀어지고 있네요…😭😢
오늘은 그런 의미로 아직 케이리버스는 살아있음을 알리고자 한 가지 이야기를 준비했습니다.

얼마 전 전 팀원이 이미지 업로드가 안된다는 버그 리포트를 보고해줬습니다. 서버를 올린 지 상당한 시간이 지났지만 미처 확인하지 못했던 이미지 업로드 기능에서 문제가 터져서 당황스러웠습니다.

문제가 무엇인지는 로그를 확인해보고 바로 깨달았습니다.
‘아 맞다… 마이그레이션 하기 전에 과금 이슈로 S3 버킷을 지워버렸다😕😕.’
오늘의 이야기는 저 에러 로그에서 시작합니다. 이번 시간엔 K-L1VERSE에 도입한 AWS S3 버킷을 자세히 알아보고 정책 설정에서 생겼던 인사이트를 공유해보겠습니다.
K-L1VERSE의 요구사항
현재 S3 버킷을 활용하고 있는 기능은 두 가지이다.
- 사용자는 게시글에 최대 10개의 이미지를 함께 등록할 수 있다.
- 유저는 프로필 사진 변경을 자유롭게 할 수 있다.

User 서버와 Board 서버에 S3 설정이 필요하고 서버 두 개에서 하나의 공통된 버킷을 디렉토리로 각각의 저장 영역을 나누어 사용할 계획이다.
또한 Front에서 이미지를 표시할 때에는 S3의 리소스 url로 바로 접근하여 이미지를 가져올 것이다.
AWS S3 버킷 생성 및 정책 편집
일단 버킷부터 만들자.
AWS S3은 Amazon Simple Storage Service의 약자로, 객체 스토리지 서비스 중 하나이다. AWS의 여타 서비스들과 마찬가지로 단순히 객체 저장 기능 외에도 상당히 많은 기능을 가지고 있다. 사용 방법이 쉬운 데에 반해 세부 설정은 복잡하므로 특별한 기준 없이 사용하도록 방치하다 보면 추후 난관을 겪을 수도 있다. 따라서 구체적인 설명과 사용법은 아래 공식 docs를 참고하자.
Amazon S3 기능 - Amazon Web Services
...
aws.amazon.com
1) 버킷 만들기

버킷은 S3에서 생성되는 최상위 디렉토리를 의미한다. 저장될 모든 “객체”는 버킷에 포함된다. 최초로 생성된 버킷은 default 상태로 private 하게 존재하며 버킷의 소유권은 이동될 수 없다.
2) 버킷 이름 설정

AWS 리전은 자동으로 본인의 접속한 웹 콘솔을 기준으로 따라간다. 필자의 경우 웹 콘솔을 서울 리전으로 선택하여 사용 중이다.
버킷의 이름은 S3 시스템에서 유일해야 한다. 서로 다른 리전이라도 중복된 이름이 존재할 수 없다. 버킷의 주소는 https://{bucketname}.s3.{Region}.amazonaws.com/{Obejct}/{keyname}의 형태이다.
3) 객체 소유권 설정

“객체”란, 데이터와 메타데이터를 구성하고 있는 S3의 저장 단위이다. 객체마다 각각의 접근 권한(객체 소유권)의 설정이 가능하다.

이때, “객체 소유권”은 버킷에 업로드된 객체를 소유한 사람과 결과적으로 해당 객체를 관리하고 액세스 할 권한이 있는 사람을 결정한다.
ACL(액세스 제어 목록) 설정을 활성화하게 되면 액세스 권한이 있는 사람과 해당 개체의 액세스 수준을 결정하고, 객체 소유자는 버킷 정책을 재정의하여 특정 사용자 또는 그룹에게 별도의 권한을 설정할 수 있다. ACL 설정을 비활성화하게 되면 객체에 대한 액세스는 버킷 정책에 의해서만 결정된다.
버킷 정책
버킷 정책(Bucket Policy)은 버킷을 사용할 권한을 가진 사용자들 별로 각각의 행위에 대한 권한 범위에 대한 설정을 의미한다. 버킷 정책과 ACL이 크게 다를 것 없는 것처럼 들릴 수도 있다.
둘 다 버킷에 대한 액세스를 제한하고 허용하는 권한 설정임에는 공통점이 있지만 버킷 정책은 버킷에 대해서만 권한 설정이 가능하고 ACL은 버킷뿐만 아니라 객체에 따로 권한 설정이 가능하다는 점, 버킷 정책은 JSON을 통해 세분화된 권한을 설정할 수 있지만 ACL은 세분화된 액세스 모드를 제공하지 않는다는 점에서 차이점을 보인다.
버킷을 성공적으로 생성했다면 버킷 정책을 세부적으로 편집할 수 있다.
ACL 설정(K-L1VERSE에서는 비활성화되어 있지만 한번 알고 가자)
다시 돌아와서 결국 ACL을 비활성, 활성하느냐의 차이는 “누가 버킷에 업로드된 객체의 소유권을 맡을 것인가”이다. 아래 캡처를 살펴보자.

- Bucket Owner Preferred : 이 설정을 활성화하면 S3 버킷을 소유한 AWS 계정이 해당 버킷에 업로드된 모든 객체의 소유자가 된다. 따라서 버킷 소유자는 객체를 삭제하고 액세스를 제어하는 기능을 포함하여 버킷 내에 저장된 객체를 완전히 제어할 수 있다.
- Object Writer : Object Writer란 객체를 S3 버킷에 업로드하는 AWS 계정 또는 IAM 사용자이다. 객체를 업로드하는 작업을 수행하는 데 사용되는 자격 증명에 따라 결정되며 AWS 계정, IAM 계정, 익명 사용자 등이 될 수 있다. 이 설정을 활성화하면 Object Writer는 수정 또는 삭제를 포함한 객체 관리에 해당되는 모든 권한을 가진다.
AWS의 권장

AWS에서 제공하는 권한 관리와 보안 관제 등 자동화된 감사를 원한다면 ACL 대신 버킷 정책을 사용하도록 ACL을 비활성화하는 것이 권장된다. ACL은 사실 레거시 방식으로 간주되고 있으므로 “다중 계정 간 액세스”, “객체별 세부 권한 관리”, “레거시 시스템과의 통합” 등의 특별한 경우가 아니라면 ACL 설정은 굳이 필요가 없다.
K-L1VERSE의 정책은?
K-L1VERSE의 경우도 ACL을 굳이 활성화할 필요가 없었다. AWS 권장 사항과 S3 관리 방식에 비추어 볼 때, 버킷 정책(Bucket Policy)과 IAM 권한으로 충분히 액세스 제어가 가능하다.
4) 버킷 퍼블릭 액세스 차단 설정

S3의 퍼블릭 액세스 차단은 버킷이나 객체에 대해 퍼블릭 액세스를 제한하거나 금지하기 위해 제공되는 추가적인 보안 레벨이다. 이를 통해 데이터가 의도치 않게 공개되는 일을 방지한다.
총 5가지의 설정이 존재한다. 하나하나 순서대로 살펴보자.
- 모든 퍼블릭 액세스 차단
- 아래 설명할 4개의 설정을 모두 활성화한다. 각각의 설정을 독립적으로 활성화하고 싶다면 이 설정을 비활성화하고 필요한 설정만 키도록 하자.
- 새 ACL을 통해 퍼블릭 액세스 차단
- 새로 생성되는 객체나 버킷에 퍼블릭 권한을 부여하는 ACL을 허용하지 않는다.
- 이 설정은 기존 ACL에는 영향을 주지 않는다.
- 임의의 ACL을 통해 퍼블릭 액세스 차단
- 기존 및 새로 생성된 객체나 버킷의 ACL이 퍼블릭 권한을 부여하지 못하도록 완전히 차단한다.
- ACL을 사용하는 방식을 사실상 비활성화한다고 볼 수 있다.
- 퍼블릭 버킷 정책 차단
- 버킷 정책을 통해 버킷과 객체가 퍼블릭 액세스를 가지지 못하도록 차단한다.
- 주로 버킷 수준에 적용되며, 퍼블릭으로 설정을 시도할 시 거부된다.
- 교차 계정 액세스 차단
- 다른 AWS 계정에서 버킷이나 객체에 퍼블릭 권한을 부여하는 정책을 허용하지 않는다.
K-L1VERSE의 정책은?
다시 한번 언급하지만, 케이리버스의 S3 운영을 위한 기능 요구사항은 아래 두 가지이다.
- “와글”에 등록된 이미지를 S3에 저장, 프론트에서 S3 URL로 바로 리소스를 조회
- 유저의 프로필 사진을 “S3”에 저장, 프론트에서 S3 URL로 바로 리소스를 조회
K-L1VERSE의 기능을 고려하여 계산된 퍼블릭 액세스 차단 정책은 아래와 같은 결론으로 내렸다.
💡와글 이미지와 프로필 사진은 공개적인 읽기 권한이 필요할 수 있으므로 특정 경로에만 제한적으로 퍼블릭 액세스를 허용해야 하고 수정 및 삭제 등의 활동은 권한 있는 사용자만 수행하도록 버킷 정책을 선언한다.
- Block Public ACLs: true로 설정하여 퍼블릭 ACL을 통한 접근을 막는다.
- Ignore Public ACLs: true로 설정하여 퍼블릭 ACL을 무시한다.
- Block Public Bucket Policies: false로 설정하여 이미지에 대한 퍼블릭 읽기 액세스를 허용한다.
- Restrict Public Buckets: false로 설정하여 이미지에 대한 퍼블릭 읽기 액세스를 허용한다.

5) 버킷 버전 관리와 태그-선택사항

버킷 버전 관리는 파일을 버전별로 관리해 주는 버저닝 기능이다. 물론 추가적인 비용을 지불해야 하지만 사용자가 실수로 파일을 삭제해도 복원할 수 있다.
K-L1VERSE에서는 더이상의 과금은 계획에 없으므로 쿨하게 넘어간다.
태그는 서비스를 운영하다 버킷이 많아지면, 버킷들을 그룹화시키는 Label이다. 서비스 운영에 따라 사용하는 방법이 달라지므로 추후 운영 단계에서 고민하고 지금은 넘어가자(어처피 당장은 버킷이 하다…).
6) 기본 암호화

버킷에 저장되는 모든 새 객체를 암호화하여 저장하는 설정이다. AWS에서 지정한 디폴트 설정으로 유지한다.
7) 버킷 만들기

자 이제 버킷 생성에 필요한 모든 설정이 끝났다. 버킷 만들기를 클릭하자. 추가적인 버킷 설정은 버킷을 생성한 후에 필요하다.
8) 여기까지 테스트
자 여기까지 버킷 설정이 잘 되었는지 확인해보자.

웹 콘솔에서 업로드 기능은 드래그 앤 드롭 등을 지원하므로 손쉽게 직접 파일을 추가할 수 있다.
파일 추가가 완료되었다면 파일 세부정보 속성에 들어가 객체 URL을 눌러보자. 브라우저를 통해서 접속을 시도하게 될 것이다.

그리고 현재는 아무런 버킷 정책이 설정되지 않아 단순한 퍼블릭 조회 액세스에 대해서 차단한 상태이므로 브라우저를 통한 직접적인 접근은 불가능할 것이다.

자 이제, 원하는 성격에 맞게 버킷 정책을 수정해야 한다.
9) 버킷 정책 반영
요구 사항을 만족하기 위한 목표는 아래 두 가지로 정리되었다.
- 게시글 이미지: 특정 디렉터리(/post/*)에서 퍼블릭 조회 액세스를 허용. 단, 수정 액세스/삭제 액세스에 대해서 정해진 IAM 사용자(Board 서버)만 권한 허용
- 사용자 프로필 사진: 특정 디렉터리(/profiles/*)에서 퍼블릭 조회 액세스 허용. 단, 수정 액세스/삭제 액세스에 대해서 정해진 IAM 사용자(User 서버)만 권한 허용
다음은 두 가지 요구사항을 반영한 통합된 버킷 정책이다.
{
"Id": "K-L1VERSE S3 Policy",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowPublicReadForPostImages",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<bucket-name>/post/*"
},
{
"Sid": "AllowPutOrDeleteForPostImages",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<board-account-id>:user/<board-account-name>"
},
"Action": [
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::<bucket-name>/post/*"
},
{
"Sid": "AllowPublicReadForProfileImages",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<bucket-name>/profile/*"
},
{
"Sid": "AllowPutOrDeleteForProfileImages",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<user-account-id>:user/<user-account-name>"
},
"Action": [
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::<bucket-name>/profile/*"
}
]
}
버킷 정책을 쉽게 작성하고 싶은 사람은 아래 서비스를 이용하자.
AWS Policy Generator
Click below to edit. To save the policy, copy the text below to a text editor. Changes made below will not be reflected in the policy generator tool....
awspolicygen.s3.amazonaws.com
K-L1VERSE 정상화
이제 사진 업로드 서비스를 정상적으로 운영할 수 있습니다. SNS에서 필수적인 기능이었던 만큼 잘 구현했던 기능이었는데 빠르게 정상화할 수 있어서 다행이라고 생각하고 있습니다😊.

기능을 구현하고 처리하는 데 있어서 사이드 프로젝트 상황일 때와 비교할 수 없이 실제 운영을 준비하는 상황일 때 생각할 게 많은 것 같습니다. 하나의 기능에 모든 권한을 허용하여 빠르게 기능부터 올리던 과거와 달리 구체적인 상황과 복잡도를 고민하는 경험은 많은 도움이 되고 있습니다.
여러분 아직 케이리버스는 살아있습니다! 운영을 위해서 조금만 재정비하고 하루빨리 국내 프로 축구 SNS로서 서비스되는 날을 위해 불철주야 노력하도록 하겠습니다!
응원해 주셔서 감사합니다 :)
'K-L1VERSE' 카테고리의 다른 글
K-L1VERSE의 EDD 도입기 (3) | 2024.12.13 |
---|---|
CRA 프로젝트 vite로 migration하기 - 본론 (1) | 2024.10.01 |
CRA 프로젝트 vite로 migration하기 - 서론 (1) | 2024.10.01 |
Nginx + react 배포, Nginx 500 error (13 Permission denied) 해결 (0) | 2024.09.19 |
Lightsail vs EC2 (0) | 2024.09.12 |
댓글