들어가며
S3 접근 제어 설계를 정리한 지 시간이 좀 지났다. 그 사이에 버킷이 늘었고, 사람이 바뀌었고, 급하게 열어준 것들이 생겼다.
설계 문서는 "이렇게 하기로 했다"를 적은 것이지 "지금 이렇다"를 보장하지 않는다. 그래서 실제 상태를 한 번 훑기로 했다. 이런 점검은 문서를 다시 읽어서는 아무것도 나오지 않고, 리소스를 하나씩 열어봐야 나온다.
무엇을 볼지 먼저 정했다
항목을 즉흥적으로 고르면 점검할 때마다 결과가 달라진다. 그래서 각 항목이 어떤 사고를 막는지를 기준으로 목록을 만들었다.
| 점검 항목 | 막으려는 상황 |
|---|---|
| 퍼블릭 액세스 차단 | 실수로 붙인 정책 하나로 버킷이 공개되는 것 |
| 서버측 암호화 | 저장 매체 수준에서 데이터가 노출되는 것 |
| 버킷 정책의 Principal과 Action 범위 | 필요 이상의 권한이 남아 있는 것 |
| HTTPS 강제 | 전송 구간에서 데이터와 서명이 노출되는 것 |
| Access Key 로테이션 | 유출된 키가 계속 유효한 것 |
| 액세스 로깅 | 사고 이후에 무슨 일이 있었는지 모르는 것 |
점검 결과 한눈에 보기
총 8개 버킷을 점검했다.

| 항목 | 양호 | 주의 |
|---|---|---|
| 퍼블릭 액세스 차단 | 7개 | 1개 (전체 미차단) |
| 서버측 암호화 (AES256) | 8개 전체 | 없음 |
| 버전 관리 | 1개 | 대부분 미설정 |
| HTTPS 강제 (DenyInsecureTransport) | 3개 | 일부 누락 |
| 액세스 로깅 | 0개 | 전체 미설정 |
설계의 핵심이었던 접근 통제(퍼블릭 차단, 암호화)는 대체로 지켜지고 있었다. 반면 사고가 난 뒤에 필요한 항목(액세스 로깅, 버전 관리)은 거의 비어 있었다. 급할 때 먼저 챙기는 것과 나중에 필요한 것이 이렇게 나뉜다는 게 표에서 그대로 보였다.
Presigned URL 전용 IAM User 점검
Presigned URL 서명 전용 IAM User를 prod와 dev로 분리해 운영 중이다.
권한 설계
{
"Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
"Resource": [
"arn:aws:s3:::[bucket-name]/[prefix-1]/*",
"arn:aws:s3:::[bucket-name]/[prefix-2]/*",
"arn:aws:s3:::[bucket-name]/[prefix-3]/*"
]
}특정 prefix에만 접근을 제한해 최소 권한 원칙을 적용했다. Presigned URL은 서명한 주체의 권한 범위 안에서만 동작하기 때문에, 이 유저의 권한을 좁히는 것이 곧 URL로 할 수 있는 일을 좁히는 것이 된다. 서명 유저를 따로 둔 이유가 여기에 있다.
Access Key 상태
| 환경 | 키 경과일 | 마지막 사용 | 상태 |
|---|---|---|---|
| prod | 42일 | 21일 전 | 실제 사용 여부 확인 필요 |
| dev | 42일 | 3일 전 | 정상 사용 중 |
90일 로테이션 권장 기준 안에 있지만, prod 키가 21일간 쓰이지 않은 점이 눈에 걸렸다. 쓰이지 않는 키가 더 위험하다. 아무도 사용하지 않으면 누가 언제 가져다 써도 이상한 점을 눈치채기 어렵기 때문이다. 경과일만 보지 말고 마지막 사용일을 같이 봐야 하는 이유다.
확인 결과에 따라 셋 중 하나를 택한다. 실제로 쓰이는데 주기가 긴 것이라면 그대로 두고, 대체된 것이라면 삭제하고, 용도를 아무도 모르면 비활성화 후 반응을 본다.
버킷 정책 분석
양호한 패턴
운영과 개발의 주요 버킷은 다음 패턴을 따르고 있었다.
- 사내 IP 기반 접근 제한
- Presigned 전용 IAM User에게 특정 prefix만 허용
DenyInsecureTransport로 HTTP 전면 차단
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": ["arn:aws:s3:::[bucket-name]", "arn:aws:s3:::[bucket-name]/*"],
"Condition": {
"Bool": { "aws:SecureTransport": "false" }
}
}Deny 문을 쓴 게 핵심이다. IAM 정책에서 Allow를 아무리 좁혀도, 버킷 정책에 Allow가 넓게 열려 있으면 다른 경로로 들어올 수 있다. Deny는 어떤 Allow보다 우선하므로, "이것만은 절대 안 된다"를 버킷 쪽에 박아두는 방식이 확실하다.
위험 발견: 퍼블릭 액세스 미차단 버킷
개발 버킷 하나에서 문제가 나왔다.
- 퍼블릭 액세스 차단 4개 항목이 모두 미설정
- 버킷 정책에
"Principal": "*"와"Action": "s3:*"허용 - IP 제한은 있으나 HTTPS 강제 조건 없음
개발 버킷이라 괜찮지 않느냐는 이야기가 나올 수 있어서, 왜 급한 항목으로 분류했는지 적어둔다.
- 개발 버킷에도 실제 데이터의 복사본이 들어가는 경우가 많다
s3:*는 읽기만이 아니라 쓰기와 삭제까지 포함한다. 데이터 유출보다 변조나 삭제가 더 곤란한 경우가 있다- 계정 안에서 이런 상태가 하나 허용되면, 다음에도 같은 방식으로 버킷이 만들어진다
즉 지금 이 버킷이 얼마나 중요한지가 아니라, 이 상태가 유지될 때 무엇이 가능해지는지로 판단했다. 같은 기준으로 퍼블릭 액세스 차단 가이드에서도 "차단 비활성 + 정책 없음" 상태를 주의로 분류했다.
발견된 문제점과 권장 조치
긴급 (보안 위험)
| 문제 | 조치 |
|---|---|
| 퍼블릭 액세스 차단 미설정 | 4개 항목 모두 활성화 |
버킷 정책에 s3:* + Principal:* 허용 | 최소 권한으로 축소 (Get/Put/List만) |
| HTTPS 미강제 | aws:SecureTransport 조건 추가 |
| Access Key 90일 로테이션 초과 (온프레미스 서버용, 약 160일) | 즉시 키 로테이션 |
주의 (운영 개선)
| 문제 | 조치 |
|---|---|
| ECS Task Role에 버킷 전체 권한 | presign 전용 유저로 분리했으므로 Task Role의 S3 권한 축소 검토 |
fullaccess 유저에 s3:* 권한 | 필요한 Action만 남기도록 축소 |
| 버전 관리 미설정 (운영 버킷) | 데이터 보호를 위해 활성화 검토 |
DenyInsecureTransport 누락 | 버킷 정책에 HTTP 차단 Deny 문 추가 |
| 액세스 로깅 미설정 (전체) | 감사 추적을 위해 활성화 검토 |
버전 관리는 전부 켜는 게 답이 아니라서, 판단 기준을 따로 정리했다(S3 버킷 버전 관리 적용 가이드). 액세스 로깅도 마찬가지로 대상과 보존 기간을 정하고 켜야 한다.
정상 항목
- presign 전용 IAM User 생성 (prod와 dev 분리)
- presign 유저 인라인 정책의 prefix 제한
- 주요 버킷 퍼블릭 차단
- 전체 버킷 서버측 암호화 (AES256)
- 주요 버킷 DenyInsecureTransport 적용
정상 항목을 굳이 적는 이유는 다음 점검 때문이다. 무엇이 확인됐는지 남겨두지 않으면 매번 전부를 처음부터 다시 본다.
정리
- Presigned URL 관련 8개 버킷과 IAM 자원을 전수 점검했다
- 개발 버킷 1개에서 퍼블릭 미차단과 과도한 권한이 발견돼 즉시 조치 대상으로 분류했다
- Access Key는 경과일뿐 아니라 마지막 사용일까지 봐야 한다
- 접근 통제는 대체로 지켜졌지만, 사고 이후에 필요한 로깅과 버전 관리는 비어 있었다
- 점검 항목과 정상 판정 근거를 표로 남겨 다음 점검의 출발점을 만들었다
배운 점
설계는 시간이 지나면 실제와 어긋난다. 대부분은 원칙대로였는데 버킷 하나가 예외였고, 그건 문서를 다시 읽어서는 찾을 수 없는 종류였다. 설계 문서와 실제 상태를 맞춰보는 작업은 따로 필요하다.
쓰이지 않는 자격증명이 더 위험하다. 경과일만 보던 기준에 마지막 사용일을 추가한 게 이번 점검의 수확이다. 아무도 쓰지 않는 키는 누가 가져다 써도 티가 나지 않는다.
위험도는 지금의 중요도가 아니라 가능한 일로 판단한다. 개발 버킷이라는 이유로 넘기지 않은 건, 그 상태에서 무엇이 가능해지는지를 봤기 때문이다. 같은 기준을 퍼블릭 액세스 차단 가이드에서도 썼다.
이 작업은 반복되어야 하므로 사람이 하면 안 된다. 전수 점검은 한 번 하면 그 시점의 사진일 뿐이다. 그래서 항목을 규칙으로 옮겼고, 그 결과가 AWS Config 기반 인프라 규정 준수 모니터링이다. 점검은 일회성 작업이 아니라 상태를 유지하는 일에 가깝다.
이어 읽기
- S3 버킷 접근 제어 및 Presigned URL 운영 전략: 점검 대상이 된 설계의 원본
- AWS Config 기반 인프라 규정 준수 모니터링: 같은 점검을 규칙으로 자동화한 결과
- S3 퍼블릭 액세스 차단 가이드: 발견된 문제를 조치하는 기준