LabHub
배우기 러닝패스 코스

Object Storage and S3

Access Control With Users and Policies

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

서비스 사용자를 만들고 최소 권한 정책을 직접 작성해 부착하면서, 권한 범위를 접두어 단위로 좁히는 습관을 만든다.

왜 중요한가

스토리지 유출 사고의 대부분은 복잡한 공격이 아니라 넓게 열어 둔 권한에서 옵니다. "이미지만 있으니까"라며 버킷을 익명 읽기로 열었는데, 몇 달 뒤 그 버킷 아래에 백업이나 사용자 업로드가 섞여 들어가는 식입니다. 정책의 Resource 를 버킷 전체(arn:aws:s3:::bucket/*)로 잡는 것도 같은 문제입니다 — 서비스 하나의 자격 증명이 새면 버킷 전체가 노출됩니다. 접두어까지 좁혀 두면 피해가 그 접두어 안에 갇힙니다. 그리고 이것은 구현 버그에 대한 방어이기도 합니다. MinIO 의 CVE-2025-62506 은 세션 정책 우회로 권한이 상승하는 취약점이었습니다. 정책을 좁게 쓰는 습관은 그런 순간에 남는 마지막 방어선입니다.

단계

  1. mc admin user add local appuser appuser-secret-123 으로 사용자를 만들고 별칭 app 을 그 자격 증명으로 설정한다.
  2. mc ls app/lab-media 를 시도하고 결과를 /root/pol/denied.txt 에 저장한다. 파일에 denied 또는 Access Denied 문자열이 있어야 한다.
  3. /root/pol/readonly.json 에 정책을 쓴다. s3:GetObjects3:ListBucket 을 허용하고 Resourcearn:aws:s3:::lab-mediaarn:aws:s3:::lab-media/* 두 개다.
  4. mc admin policy create local labreadonly /root/pol/readonly.jsonmc admin policy attach local labreadonly --user appuser 를 실행한다. mc ls app/lab-media 가 성공해야 한다.
  5. mc cp /opt/fixtures/s3/readme.txt app/lab-media/doc/nope.txt 가 실패해야 한다. /root/pol/write.txtwrite_denied=true 를 적는다.
  6. /root/pol/imgonly.jsonResourcearn:aws:s3:::lab-media/img/* 로 좁힌 정책을 쓰고 labimgonly 로 만들어 부착한다. app/lab-media/img/logo.png 조회는 되고 app/lab-media/doc/sales.csv 조회는 실패해야 한다. /root/pol/prefix.txtimg=ok doc=denied 를 적는다.
  7. local/lab-media/public/ 접두어만 익명 다운로드로 연다. 익명 GET 이 public/ 아래 객체에는 200, private/ 아래 객체에는 403 이어야 한다. /root/pol/anon.txtpublic=200 private=403 을 적는다.

참고

서비스 사용자 만들기

mc admin user add local appuser appuser-secret-123 으로 사용자를 만들고 별칭 app 을 그 자격 증명으로 설정한다.

관리자 별칭으로 사용자를 추가합니다. 액세스 키와 시크릿 키를 정해 주세요.

정책 없는 사용자가 거부되는지 확인하기

mc ls app/lab-media 를 시도하고 결과를 /root/pol/denied.txt 에 저장한다. 파일에 denied 또는 Access Denied 문자열이 있어야 한다.

새 별칭으로 목록을 시도하면 거부됩니다. 기본은 아무 권한도 없는 것입니다.

읽기 전용 정책 작성하기

/root/pol/readonly.json 에 정책을 쓴다. s3:GetObjects3:ListBucket 을 허용하고 Resourcearn:aws:s3:::lab-mediaarn:aws:s3:::lab-media/* 두 개다.

JSON 으로 Effect, Action, Resource 를 적습니다. 목록 조회와 객체 읽기는 서로 다른 Action 입니다.

정책 부착하고 읽기 성공시키기

mc admin policy create local labreadonly /root/pol/readonly.jsonmc admin policy attach local labreadonly --user appuser 를 실행한다. mc ls app/lab-media 가 성공해야 한다.

정책을 만들고 사용자에게 붙이는 것은 별도 단계입니다.

쓰기는 여전히 거부되는지 확인하기

mc cp /opt/fixtures/s3/readme.txt app/lab-media/doc/nope.txt 가 실패해야 한다. /root/pol/write.txtwrite_denied=true 를 적는다.

읽기 전용 정책이라면 업로드가 실패해야 합니다. 실패하는 것이 정상입니다.

접두어 한정 정책 만들기

/root/pol/imgonly.jsonResourcearn:aws:s3:::lab-media/img/* 로 좁힌 정책을 쓰고 labimgonly 로 만들어 부착한다. app/lab-media/img/logo.png 조회는 되고 app/lab-media/doc/sales.csv 조회는 실패해야 한다. /root/pol/prefix.txtimg=ok doc=denied 를 적는다.

Resource 에 와일드카드를 접두어까지 붙입니다. img/ 는 되고 doc/ 는 안 되게 하세요.

특정 접두어만 익명 공개하기

local/lab-media/public/ 접두어만 익명 다운로드로 연다. 익명 GET 이 public/ 아래 객체에는 200, private/ 아래 객체에는 403 이어야 한다. /root/pol/anon.txtpublic=200 private=403 을 적는다.

버킷 전체를 여는 것과 접두어 하나만 여는 것은 사고 규모가 다릅니다.

명령 끝의 슬래시 한 글자를 조심하세요. 이 실습의 요지가 거기에 다 들어 있습니다.

mc anonymous set download local/lab-media/public   → Resource: lab-media/public*
mc anonymous set download local/lab-media/public/  → Resource: lab-media/public/*

S3 에 폴더는 없습니다. 정책이 보는 것은 문자열 접두어뿐이라, 슬래시를 빠뜨리면 public-backup.tar 처럼 public 으로 시작하기만 하는 루트 객체까지 함께 열립니다. mc anonymous get-json 으로 서버에 실제로 걸린 Resource 를 확인하세요.

규칙은 걸 때마다 덧붙습니다. 같은 버킷에 두 번 걸면 public*public/* 이 함께 남으니, 범위를 바꿀 때는 mc anonymous set none 으로 먼저 지우고 다시 거세요.