오브젝트 스토리지에서의 유출은 보통 침입을 동반하지 않는다. 누군가 시스템에 침입한 것도, 자격 증명을 훔친 것도 아니며, 로그에도 이상한 점이 보이지 않는다. 설정이 데이터를 공개 상태로 만들었을 뿐이다.
아무도 침입하지 않았는데 데이터가 새는 이유
침입
취약점이나 자격 증명 → 침입 → 데이터 반출
패치, 인증, 모니터링이 각각 막을 기회를 가진다
설정 오류(공개 버킷)
URL을 안다(또는 추측한다) → 가져간다
'인증이 우회됐다'가 아니라, 애초에 인증이 필요 없었다
이 유형이 잡기 어려운 이유는 접근이 부정한 것으로 보이지 않기 때문이다. 공격자는 실제로 공개된 엔드포인트에 평범한 GET 요청을 보낼 뿐이라, 침입 탐지나 로그 이상 탐지가 잡을 것이 거의 없다. 공개 디렉터리에 절대 두면 안 되는 것과 같은 문제가, 서버가 아니라 스토리지에서 일어나는 것이다.
네 가지 설정은 각각 다른 것을 막는다
S3 퍼블릭 액세스 차단(Block Public Access)은 서로 독립된 네 가지 설정이며, 어떤 조합으로든 적용할 수 있다. 이름이 비슷해서 하나의 스위치처럼 취급되기 쉽지만, 각각 막는 것이 다르다.
- BlockPublicAcls
- 새 공개 ACL을 적용하려는 시도를 실패시킨다(
PutBucketAcl,PutObjectAcl, 공개 ACL을 붙인PutObject). 기존 정책과 ACL은 바뀌지 않으므로, 이미 있는 공개 ACL은 그대로 남는다 - IgnorePublicAcls
- 버킷과 객체의 공개 ACL을 S3가 모두 무시하게 한다. 공개 ACL을 붙인
PutObject는 여전히 성공한다(BlockPublicAcls와의 차이). 기존 ACL을 지우지 않고, 새 공개 ACL 설정도 막지 않는다 - BlockPublicPolicy
- 공개 접근을 허용하는 버킷 정책을 거부한다(
PutBucketPolicy와 관련 액세스 포인트 호출). 기존 정책에는 영향을 주지 않는다 - RestrictPublicBuckets
- 공개 정책이 있는 버킷에 대한 접근을 AWS 서비스 주체와 소유 계정 안의 승인된 사용자로 제한한다. 특정 계정에 대한 비공개 위임을 포함해 교차 계정 접근을 막는다(AWS 서비스 주체는 제외)
네 가지 모두에 공통되지만 거의 모두가 놓치는 성질
위의 모든 항목에 기존 정책과 ACL은 바뀌지 않는다고 적혀 있다는 점에 주목하라. 문서는 그 결과를 직접 밝힌다. 퍼블릭 액세스 차단 설정은 기존 정책이나 ACL을 바꾸지 않으므로, 차단 설정을 해제하면 공개 정책이나 ACL이 있는 버킷·객체가 다시 공개된다는 것이다.
즉 차단을 켰다고 위험이 사라진 것이 아니다. 지금 접근을 막고 있을 뿐, 공개 정책과 ACL은 그대로 있다. 조사하느라 잠시 해제하거나, 다른 계정으로 복사하거나, Terraform 차이(diff)가 설정을 되돌리면, 어느 경우든 데이터는 다시 공개된다. 목표 상태를 '차단이 켜져 있다'가 아니라 '차단을 꺼도 공개되지 않는다'로 정하라.
'공개'의 정의는 생각보다 넓다
본인은 비공개라고 생각하는 버킷도 S3가 공개로 평가할 수 있다.
공개로 평가되는 경우
・AllUsers나 AuthenticatedUsers에 권한을 주는 ACL. 후자는 회사 직원 전체가 아니라 AWS 계정을 가진 모든 사람을 뜻한다
・와일드카드나 정책 변수가 들어간 값으로 주체를 지정한 버킷 정책
・너무 넓은 aws:SourceIp 범위(IPv4에서 /8보다 넓음, IPv6에서 /32보다 넓음, 사설 대역 제외)
S3는 버킷 정책이 공개라고 먼저 가정한 뒤 비공개로 볼 수 있는지 평가한다. 애매하면 공개로 평가된다.
비공개로 평가되는 경우
와일드카드 없는 고정 값으로 접근을 제한하는 정책. 주체, CIDR 블록 집합, aws:SourceArn, aws:SourceVpc, aws:SourceVpce, aws:SourceOwner, aws:SourceAccount 등이다.
문서의 예시: aws:SourceVpc를 vpc-*로 두면 공개이고, vpc-91237329 같은 고정 값으로 두면 공개가 아니다. '좁혔다'와 '고정 값으로 좁혔다'가 그 판단의 두 갈래다.
차단은 버킷별이 아니라 계정 단위로 켠다
문서는 BlockPublicPolicy를 계정 단위로 적용하라고 권한다. 버킷 정책으로 사용자에게 그 버킷의 퍼블릭 액세스 차단 설정을 바꾸는 권한을 줄 수 있기 때문이다.
버킷 단위만
버킷 정책을 바꿀 수 있는 사람 → 차단을 끄는 정책을 넣는다 → 버킷을 공개할 수 있게 된다
계정 단위
버킷 정책이 다시 쓰여도 S3가 공개 정책을 차단한다
액세스 포인트, 버킷, 계정의 설정이 서로 다르면 S3는 가장 제한적인 조합을 적용한다. 더 엄격한 설정이 이기므로, 위 단계(계정)에서 제한하면 아래 단계에서 풀 수 없다. 스토리지에 적용한 최소 권한이다.
고치는 순서
숨기기 전에 무엇이 공개돼 있는지 본다
차단부터 켜면 노출은 멈추지만, 동시에 무엇이 노출돼 있었는지 볼 수 없게 된다. BlockPublicAcls의 설명도 바로 그 점을 말한다. 기존 정책과 ACL을 점검하고 다듬고 바꿀 수 있게 하면서 공개 접근을 막는다는 것이다. AWS는 IAM Access Analyzer for S3를 제공하며, 이 도구는 ACL이나 정책이 공개 접근을 허용하는 버킷을 나열하고 결과마다 접근의 출처와 수준을 보여 준다. 먼저 거기서 목록을 만든다.
계정 단위로 네 가지 설정을 모두 켠다
AWS는 계정(그리고 각 버킷)에 네 가지 퍼블릭 액세스 차단 설정을 모두 켜라고 권한다. Security Hub 컨트롤 S3.8이 확인하는 것이 이것이다. 먼저 애플리케이션이 공개 접근 없이 동작하는지 확인하라. 정적 웹사이트 호스팅처럼 정말로 공개가 필요한 것이 있다면, 통제를 전체적으로 건너뛰지 말고 그 경우만 개별적으로 조정한다.
공개 ACL과 정책을 실제로 없앤다(가장 중요한 단계)
차단은 기존 공개 정책이나 공개 ACL을 지우지 않는다. 1단계에서 만든 목록으로 돌아가 삭제하거나 다시 쓴다. 그래야 비로소 '차단을 꺼도 공개되지 않는' 상태가 된다. 대부분의 팀은 2단계에서 멈추며, 이 글이 말하고 싶은 핵심이 바로 이것이다.
공개해야 하는 버킷은 넣는 것을 관리한다
공개 접근이 정말 필요하다면, 공개 버킷에는 공개돼도 괜찮은 것만 들어가도록 스토리지를 나눈다. 백업, 데이터베이스 덤프, 고객 목록은 공개 자산과 같은 버킷에 두지 않는다. 버킷에 무엇을 넣느냐가 거기서 얼마나 샐 수 있는지를 정한다. 같은 생각의 서버 쪽 버전은 공유 호스팅에서 .env를 외부에서 읽히지 않게 하기에 있다.
파일 이름에 기대지 않는다
'아무도 URL을 모른다'는 접근 제어가 아니다(추측 가능한 식별자와 같은 문제). 추측할 수 없는 이름은 추가 안전장치일 뿐, 권한 확인을 대신하지 않는다. 잠시 공유해야 할 때는 스스로 만료되는 수단, 즉 기한이 있는 서명 URL을 쓰고 공개 설정은 닫아 둔다.
이 사이트의 관점: 설정 사고는 상태를 점검할 수 있어야 줄어든다
버킷 노출이 반복되는 이유는 사람들이 부주의해서가 아니라 상태가 보이지 않아서다. 파일 권한이나 서버 설정과 달리, 스토리지가 공개인지는 정책, ACL, 계정 설정, 액세스 포인트라는 네 층의 조합으로 정해지며 어느 하나만 봐서는 답이 나오지 않는다. 이런 영역에서 우리는 사람의 주의에 기대지 말고 조합을 기계가 평가하게 하자는 입장이다. 위 단계에서 제한해 아래에서 풀 수 없게 하고, 공개·비공개 판정을 대신 내려 주는 도구로 정기적으로 다시 점검한다. '조심한다'는 통제가 아니다. 의존성에 대해 내린 결론(osv-scanner 시작하기)과 같다.
출처(1차 자료)
- Amazon Web Services, "Blocking public access to your Amazon S3 storage"(Amazon S3 사용 설명서) — docs.aws.amazon.com(네 가지 설정의 동작, 차단이 기존 정책·ACL을 바꾸지 않는다는 서술, '공개'의 정의, 계정 단위 적용을 권하는 이유는 모두 이 문서에서 가져왔다)
다음에 읽을 글
- 배치: 공개 디렉터리에 절대 두면 안 되는 것 / 공유 호스팅에서 .env를 외부에서 읽히지 않게 하기
- 자격 증명: .env와 API 키의 무엇이 위험한가 / SSH 키와 최소 권한
- 점검: 자산 점검 체크리스트
- 같은 '설정으로 새는' 유형: 서브도메인 탈취와 남은 DNS 레코드
FAQ
Q퍼블릭 액세스 차단을 켜면 안전한가요?
지금 당장은 밖에서 접근할 수 없는 상태지만, 위험이 사라진 것은 아닙니다. AWS 문서는 퍼블릭 액세스 차단 설정이 기존 정책이나 ACL을 바꾸지 않으며, 따라서 차단 설정을 해제하면 공개 정책이나 ACL이 있는 버킷·객체가 다시 공개된다고 명시합니다. 공개 정책과 ACL은 차단 아래에 그대로 남아 있습니다. 목표는 '차단이 켜져 있다'가 아니라 '차단을 꺼도 공개되는 것이 없다'이며, 이를 위해서는 공개 정책과 ACL 자체를 삭제해야 합니다.
Q설정은 버킷별로 하나요, 계정 단위로 하나요?
계정 단위입니다. BlockPublicPolicy에 대해 문서는 그 이유를 설명합니다. 버킷 정책으로 사용자에게 그 버킷의 퍼블릭 액세스 차단 설정을 바꾸는 권한을 줄 수 있으므로, 버킷 정책을 바꿀 수 있는 사람이라면 차단을 끄는 정책을 넣을 수 있습니다. 계정 전체에 설정을 켜 두면 사용자가 버킷 정책을 바꿔도 S3가 공개 정책을 차단합니다. 버킷 단위 설정은 버킷 정책을 편집할 수 있는 사람이 풀 수 있습니다.
Q정확히 무엇이 '공개'로 취급되나요?
대부분이 생각하는 것보다 넓은 정의입니다. ACL은 미리 정의된 AllUsers나 AuthenticatedUsers 그룹에 권한을 주면 공개입니다. AuthenticatedUsers는 회사 직원 전체가 아니라 AWS 계정을 가진 모든 사람을 뜻합니다. 버킷 정책의 경우 S3는 먼저 정책이 공개라고 가정한 뒤 비공개로 볼 수 있는지 평가하며, 와일드카드나 정책 변수 없이 고정된 값으로 접근을 제한할 때만 비공개로 인정됩니다. 매우 넓은 범위(IPv4에서 /8보다 넓은 범위)의 aws:SourceIp를 쓰는 정책도 공개로 평가됩니다.
Q새로 만든 버킷은 기본적으로 안전한가요?
문서에 따르면 기본적으로 새 버킷, 액세스 포인트, 객체는 공개 접근을 허용하지 않습니다. 하지만 사용자가 버킷 정책, 액세스 포인트 정책, 객체 권한을 바꿔 허용할 수 있다고도 적혀 있습니다. 즉 기본값은 안전한 쪽이고, 사고는 거의 모두 누군가 일부러, 또는 작업 때문에 잠시 그 기본값에서 벗어난 곳에서 일어납니다. 기본값에 기대지 마세요. 현장에서 끌 수 없는 통제(계정 단위 차단)와, 상태가 바뀌었을 때 알아차릴 수단이 둘 다 필요합니다.