S3(Simple Storage Service)는 AWS의 무제한 객체 기반 스토리지 서비스입니다. 데이터 레이크, 웹 사이트, 모바일 애플리케이션, 백업 및 복원, 빅 데이터 분석 등 다양한 용도로 사용이 가능한 AWS의 대표 서비스 중 하나인데요, 널리 사용되는 만큼 S3 데이터 유출 사고 역시 빈번하게 발생합니다.
S3는 다양한 방법의 접근 제어 및 관리 기능을 제공하고 있어 세분화된 제어가 가능합니다. 다소 복잡할 수 있기 때문에 상황에 적절한 방법을 택해 사용할 수 있어야합니다.
1주차에서는 S3 접근을 통제하는 방법을 알아보고 통제 방법에 따라 다양한 조건에서 실습을 진행했습니다.
AWS 자격 증명이 구성되어 있는 로컬PC와 AWS 자격 증명이 구성되지 않은 EC2가 필요합니다.
(AWS 환경 구성은 스터디장인 가시다님이 제공해주신 CloudFormation 스택을 사용해 배포했습니다.)
기본적으로 버킷, 객체 등 모든 S3 리소스는 프라이빗으로 생성되며, 이를 생성한 계정인 리소스 소유자만 해당 리소스에 접근할 수 있습니다.
S3의 접근 통제 옵션은 크게 리소스 기반 정책과 사용자 기반 정책(IAM)으로 나눠 볼 수 있습니다. ACL이나 버킷 정책은 리소스 기반 정책으로, IAM 정책은 사용자 기반 정책으로 생각할 수 있습니다. 이 두 옵션을 조합해서 사용할 수도 있습니다.
✔️ 만약 리소스 기반 정책과 사용자 기반 정책이 상충한다면 어떻게 될까요 ?
동일 계정 내인지, Cross Account 상황인지에 따라 결과가 달라집니다.
내가 접근하려는 리소스가 내 계정안에 있는 리소스라면 리소스 기반과 정책 사용자 기반 정책의 합집합이,
접근하려는 리소스가 다른 계정에 위치했다면 리소스 기반과 정책 사용자 기반 정책의 교집합이 적용됩니다.
참고: https://youtu.be/zIZ6_tYujts?si=8jgNsINzq3zSvWJU&t=905
버킷 ACL, 객체 ACL 활성화 유무와 버킷 정책을 사용하여 테스트했습니다.
실습을 위해 S3 버킷을 먼저 생성해보겠습니다.
저는 IAM 자격증명이 설정 되어 있는 🖥️ 로컬 PC의 터미널에서 AWS CLI로 버킷을 생성했습니다.
aws s3api
명령어는 aws s3
보다 더 세분화된 내용과 작업을 가능하게 합니다.
# 버킷 생성 NICKNAME=<자신의닉네임> aws s3 mb s3://ahss-$NICKNAME --region ap-northeast-2
버킷을 생성하면 기본적으로 퍼블릭 액세스가 차단되어있습니다.
aws s3api get-public-access-block --bucket ahss-$NICKNAME | jq
S3 콘솔 [권한] 탭에서도 확인이 가능합니다.
이제 로컬 PC에서 파일을 만들어 S3로 업로드 해보겠습니다.
# 파일 생성 echo "memo1" > memo1.txt echo "memo2" > memo2.txt echo "memo3" > memo3.txt # S3로 업로드 aws s3 cp memo1.txt s3://ahss-$NICKNAME aws s3 cp memo2.txt s3://ahss-$NICKNAME aws s3 cp memo3.txt s3://ahss-$NICKNAME
퍼블릭 엑세스가 차단되어 있지만 IAM 자격증명이 설정되어 있는 상태이기 때문에 정상적으로 파일이 업로드 됩니다.
이제 업로드 된 객체들을 확인해 보겠습니다.
✅ 모든 퍼블릭 액세스 차단 활성화 상태
🟧 EC2 (IAM 자격증명 X)
# 업로드 객체 확인 aws s3 ls s3://ahss-$NICKNAME --human-readable
# 서명 없이 업로드 객체 확인 aws s3 ls s3://ahss-$NICKNAME --human-readable --no-sign-request
--no-sign-request
옵션은 AWS 서비스 엔드포인트에 대한 HTTP 요청 서명을 비활성화하는 부울 스위치입니다. 이렇게 하면 보안 인증이 로드되는 것을 방지할 수 있습니다. 해당 옵션값을 주자 아예 bucket을 찾지 못합니다.
✅ 모든 퍼블릭 액세스 차단 활성화 상태
🖥️ PC (IAM 자격증명 O)
IAM 자격증명이 설정되어 있어 정상적으로 조회가 가능합니다.
서명을 비활성화하자 Access가 거부되는 것을 확인할 수 있습니다.
객체 URL을 사용해 웹으로 접근하면 AccessDenied
가 표시됩니다.
2. 콘솔에서 버킷의 퍼블릭 액세스를 차단을 해제해보겠습니다.
🚫 모든 퍼블릭 액세스 차단 비활성
🟧 EC2 (IAM 자격증명 X)
버킷의 모든 퍼블릭 액세스 차단 설정을 비활성화 했으나 결과는 동일합니다.
🖥️ PC (IAM 자격증명 O), 객체 URL로 접근시에도 전과 동일한 결과가 표시됐습니다.
권한 개요가 객체를 퍼블릭으로 설정할 수 있음으로 변경되으나 객체가 자동으로 공개되지는 않았습니다.
💡 그럼 여기서 의미하는 '퍼블릭'은 무엇인지 의문이 들었습니다.
AWS에서 정의하는 퍼블릭의 의미 는 다음과 같습니다.
# 퍼블릭 { "Principal": "*", "Resource": "*", "Action": "s3:PutObject", "Effect": "Allow", "Condition": { "StringLike": {"aws:SourceVpc": "vpc-*"}} } # 퍼블릭이 아님 { "Principal": "*", "Resource": "*", "Action": "s3:PutObject", "Effect": "Allow", "Condition": {"StringEquals": {"aws:SourceVpc": "vpc-91237329"}} }
모든 퍼블릭 액세스 차단을 비활성화하면 객체에 공개적으로 접근 가능할 수 있다는 가능성이 생길 뿐, 객체에 대한 접근 가능 여부는 버킷 정책 등 여러 요소에 따라 달라진다는 것을 알 수 있었습니다.
이제부터 ACL과 버킷 정책에 따라 객체에 대한 접근 가능여부가 어떻게 달라지는지 확인해보겠습니다.
💡ACL은 언제쓸까요 ?
특별한 이유가 없다면 ACL을 비활성화하는 것이 좋습니다. ACL을 사용하면 IAM과 버킷 정책 외에 추가로 액세스를 제어할 수 있는 계층이 생성되는데, 이렇게 되면 관리의 복잡성과 구성 오류의 위험성이 증가하게 되기 때문입니다.
다만 A계정에서 B계정이 소유한 버킷에 객체를 업로드할 때, 특정 작업을 수행할 수 있는 권한을 Amazon CloudFront와 같은 AWS 서비스에 부여할 때 객체 ACL을 사용하게 됩니다. 자세한 내용은 Amazon S3에서 객체 ACL을 사용하는 사용 사례에는 어떤 것이 있나요?를 참고해주세요.
이번 실습에서는 ACL을 활성화하고 객체별 소유권을 제어해봤습니다.
1. AWS 콘솔에서 [권한] > 객체 소유권 편집을 선택합니다. ACL을 활성화하고 ACL 편집을 통해 모든 사람(퍼블릭 액세스)이 객체를 나열할 수 있도록 설정합니다.
🚫 모든 퍼블릭 액세스 차단 비활성 + 버킷 ACL 활성화
🟧 EC2 (IAM 자격증명 X)
ACL 활성화 이전과 결과는 동일합니다.
🚫 모든 퍼블릭 액세스 차단 비활성 + 버킷 ACL 활성화 - 모든 사람(퍼블릭 액세스) 나열 허용
🟧 EC2 (IAM 자격증명 X)
모든 사람에게 나열 작업을 허용했기 때문에 서명이 없는 상태에서도 버킷의 객체 나열이 가능합니다.
2. 객체 ACL
이번엔 객체별 권한을 변경해보겠습니다.
🚫 모든 퍼블릭 액세스 차단 비활성 + 버킷 ACL 활성화 + 객체 ACL - 모든 사람(퍼블릭 액세스) 읽기 허용
🟧 EC2 (IAM 자격증명 X)
객체 수준에서 모든 사람에게 읽기를 허용하자 서명 없이도 객체 다운로드가 가능합니다.
🚫 모든 퍼블릭 액세스 차단 비활성 + 버킷 ACL 활성화 + 객체 ACL - 인증된 사용자 그룹(AWS 계정이 있는 모든 사용자) 읽기 허용
🟧 EC2 (IAM 자격증명 X)
AWS 계정에서 객체에 읽기가 가능한 정책으로 AWS 계정이 아닐 경우 읽기 작업이 거부되어야합니다.
🖥️ PC (IAM 자격증명 O)
AWS 자격증명이 있는 로컬 PC에서는 어떨까요 ?
객체 ACL 설정을 유지한 상태에서 버킷 정책을 수정해보겠습니다.
다음 정책은 ahss-닉네임 버킷에 있는 객체들에 대한 GetObject 작업을 허용한다는 정책입니다.
여기에서 Principal 필드는 리소스에 대한 액세스를 허용하거나 거부할 사람, 보안 주체를 지정합니다. 특정 AWS 계정, IAM 사용자, AWS 서비스 등이 주체가 될 수 있습니다. 다음 정책과 같이 Principal 필드에서 와일드카드 "*"를 사용하면 모든 보안 주체에 적용되어 익명의 사용자에게도 접근을 허용하게 됩니다.
{ "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadGetObject", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::ahss-닉네임/*" } ] }
S3 접근 제어는 제어에 관여하는 정책들이 많아 다소 복잡하게 느껴질 수 있습니다. AWS에서 IAM Access Analyzer라는 액세스 분석기를 제공하고 있으니 활용해보시면 좋을 것 같습니다.
# 버킷에 객체 모두 삭제 aws s3 rm s3://ahss-$NICKNAME --recursive # 실습에 사용한 S3 버킷 삭제 aws s3 rb s3://ahss-$NICKNAME # 확인 aws s3 ls
S3 보안 강화를 위한 AWS 공식 Workshop이나 자료들을 참고하여 S3 보안을 강화할 수 있습니다.
S3의 기능 중 하나인 Pre-signed URL을 사용하여 임시적으로만 객체에 접근할 수 있게 하고, Security Best Practice를 준수하도록 설정해보겠습니다.
Pre-Signed URL을 사용하면 사용자가 AWS 계정이나 권한이 없어도, 버킷 정책 수정 없이 특정 객체에 대한 액세스가 가능하도록 설정할 수 있습니다. 통지서 같은 것들이 SMS로 수신됐을 때 특정 기간동안 링크만으로도 내 정보에 접근할 수 있는 경우가 있는데요, Pre- Signed URL을 사용하면 이런 작업이 가능합니다.
최소 1분에서 최대 7일까지 유효한 URL을 생성할 수 있습니다.
🖥️ PC (IAM 자격증명 O) 에서 다음 명령을 실행해보겠습니다.
# 버킷생성 aws s3 mb s3://ahss-$NICKNAME-presign --region ap-northeast-2 # 확인 aws s3 ls aws s3api get-public-access-block --bucket ahss-$NICKNAME-presign | jq # 그림파일 다운로드 curl https://www.nasa.gov/sites/default/files/thumbnails/image/main_image_star-forming_region_carina_nircam_final-5mb.jpg -o jameswebb.jpg # S3로 업로드 aws s3 cp jameswebb.jpg s3://ahss-$NICKNAME-presign # 파일 확인 aws s3 ls s3://ahss-$NICKNAME-presign --human-readable aws s3api list-objects --bucket ahss-$NICKNAME-presign | jq
Pre-signed URL을 생성합니다. URL이 유효하게 지속될 시간을 --expires-in 옵션값으로 입력해줍니다. 600은 10분을 의미합니다.
aws s3 presign s3://ahss-$NICKNAME-presign/jameswebb.jpg --expires-in 600
✅ 모든 퍼블릭 액세스 차단 활성화 상태이지만생성된 URL을 브라우저에 입력했더니 다음과 같이 객체가 표시되는 것을 확인할 수 있었습니다.
안전한 통신을 위해 HTTPS를 사용한 연결이 아니면 버킷에 접근이 불가능하도록 하는 정책을 설정합니다.
{ "Id": "S3-Security-Deny-unless-HTTPS", "Version": "2012-10-17", "Statement": [{ "Action": "s3:*", "Effect": "Deny", "Principal": "*", "Resource": "arn:aws:s3:::ahss-닉네임-presign/*", "Condition": { "Bool": { "aws:SecureTransport": false } } }] }
정책을 추가하고 http, https 로 객체를 호출해 보겠습니다.
# object's metadata 정보 확인 : endpoint-url 옵션 설정 >> http? https? 확인 aws s3api head-object --bucket ahss-$NICKNAME-presign --key jameswebb.jpg --endpoint-url http://s3.ap-northeast-2.amazonaws.com aws s3api head-object --bucket ahss-$NICKNAME-presign --key jameswebb.jpg --endpoint-url https://s3.ap-northeast-2.amazonaws.com
✅ 모든 퍼블릭 액세스 차단 활성화
🖥️ PC (IAM 자격증명 O)
버킷을 생성하면 기본 암호화가 SSE-S3(S3 관리 키)으로 구성되어 있습니다. SSE-KMS를 사용하도록 버킷 암호화 기본값을 업데이트하여 새 객체가 SSE-KMS(KMS 관리 키)를 사용하도록 설정합니다. 두 방식 모두 안전하지만 AWS의 IDC가 털려서 S3 키가 유출된다면...? 일반적으로 KMS 관리 키가 더 보안 수준이 높다고 간주됩니다. 서버 측 암호화(SSE-C, SSE-S3, SSE-KMS, DSSE-KMS)를 사용하여 생성된 객체 복제
# 객체 업로드 echo "123456789abcdefg" > textfile aws s3api put-object --key text02 --body textfile --bucket ahss-$NICKNAME-presign # object's metadata 정보 확인 : ServerSideEncryption 확인 aws s3api head-object --bucket ahss-$NICKNAME-presign --key text02 | jq
이를 응용해서 ServerSideEncryption": "aws:kms" 이 아닌 객체는 업로드 금지하도록 버킷 정책을 설정할 수도 있습니다.
{ "Id": "S3-Security-Deny-unless-SSE-KMS", "Version": "2012-10-17", "Statement": [{ "Effect": "Deny", "Principal": "*", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::ahss-$NICKNAME-presign/*", "Condition": { "StringNotEquals": { "s3:x-amz-server-side-encryption": "aws:kms" } } }] }
AWS Config는 리소스의 구성 및 관계에 대한 지속적인 진단, 감사 및 평가를 수행하는 서비스입니다.
사용자가 직접 규칙을 설정할 수도 있고, AWS에서 제공하는 관리형 규칙을 사용해 편리하게 감사 및 추적이 가능합니다. access key 관리 주기, acm 만료 일자 확인 등 리소스와 관련된 항목들을 규칙으로 설정해두고 이를 위반할 시 알림을 받도록 구성하여 리소스 관리에 대한 가시성을 높일 수 있습니다.
S3 bucket과 관련된 규칙도 제공하고 있는데요, 여기서 s3 bucket이 Public 상태가 될 경우를 추적하는 규칙을 추가해보겠습니다.
규칙을 추가해두면 위반된 리소스를 탐지하고 내용을 표시해줍니다.
Config 위반 알림이 발생 시 Slack으로 알람을 받도록 설정해두면 매번 콘솔에서 확인하지 않아도 쉽게 리소스 변경 추적이 가능하겠죠 ?
S3는 자주 사용하지만 보통 로그 저장용으로 사용하여 완전히 프라이빗하게 구성해서 사용하고 있어 세분화된 제어를 해보지는 않았었습니다. S3와 권한 문제는 알면 알수록 복잡하고, 테스트해 볼 경우의 수가 무궁무진하다고 느꼈습니다. EC2에서는 404가, PC에서는 403에러가 발생하는 이유에 대해서도 다뤄보려 합니다. 아직 부족한 부분이 많지만 첫걸음을 뗐다고 생각하면서 차근차근 공부해보겠습니다. :)
CloudNet@팀의 AHSS(AWS Hacking & Security 스터디) 학습 내용과 제가 공부한 내용을 정리한 글입니다. 더 좋은 방법이나 틀린 내용이 있으면 말씀해주세요 :)
AWS 인스턴스 메타데이터와 IMDS (0) | 2023.09.07 |
---|---|
키페어 없이 AWS CLI를 사용하여 EC2 인스턴스에 SSH로 연결하기 (0) | 2023.06.21 |
System Manager로 특정 시간에 EC2 인스턴스 시작/중지 자동화하기 (0) | 2023.06.03 |
EC2 상태 변경 알람 Slack으로 받아보기 (0) | 2023.06.01 |
AWS User Notifications로 AWS EC2 상태 변경 알람 받기 (0) | 2023.05.25 |
댓글 영역