Tech BlogFebruary 23, 2026Jina Yoon1 views

S3 버킷 데이터 유출 — 가장 흔한 실수 10가지

AWS S3는 강력한 스토리지 서비스이지만 잘못된 설정으로 인한 데이터 유출 사건이 끊이지 않습니다. 이 글에서는 S3 버킷 보안의 가장 흔한 10가지 실수와 각각의 해결 방법을 구체적인 설정 예시와 함께 설명합니다.

#AWS S3#클라우드 보안#데이터 유출#액세스 제어#IAM#버킷 정책#암호화#설정 오류#FRIIM CSPM#Seekurity SIEM
S3 버킷 데이터 유출 — 가장 흔한 실수 10가지
Jina Yoon

Jina Yoon

February 23, 2026

도입부: S3 데이터 유출의 심각성

Amazon S3는 클라우드 스토리지의 사실상 표준입니다. 글로벌 수백만 조직이 매일 수조 개의 객체를 S3에 저장하고 있습니다. 그러나 잘못된 설정은 가장 강력한 도구마저 위험하게 만듭니다.

Verizon DBIR 2024 보고서에 따르면 클라우드 환경의 데이터 침해 중 상당 부분이 부정확한 액세스 제어 설정으로 인해 발생합니다. S3 버킷이 실수로 공개되어 민감한 정보가 노출되는 사건은 지금도 계속 발생하고 있습니다. 특히 스타트업과 중견 기업에서 초기 구축 단계에 보안을 미흡하게 구성하는 경향이 두드러집니다.

이 글에서는 S3 버킷 보안의 가장 흔한 10가지 실수를 구체적으로 분석하고, 각 실수를 해결하기 위한 설정 방법과 모니터링 전략을 제시합니다. 실무 엔지니어라면 반드시 확인해야 할 필수 체크리스트를 준비했습니다.

배경: 클라우드 스토리지 보안의 현황

S3는 2006년 출시 이후 18년간 가장 신뢰받는 객체 스토리지 서비스로 자리 잡았습니다. 하지만 강력한 기능만큼 설정의 복잡성도 높습니다. AWS가 제공하는 액세스 제어 메커니즘은 매우 세밀하지만, 기본값(default)이 충분히 보안적이지 않다는 점이 핵심 문제입니다.

Cloud Security Alliance(CSA)의 2024 클라우드 보안 현황 보고서에 따르면, 클라우드 환경에서 가장 자주 발생하는 보안 사고는 '설정 오류'입니다. 기술적 취약점이나 제로데이 공격보다는 단순한 구성 실수가 더 큰 피해를 초래합니다. 특히 S3의 경우 버킷 정책, ACL(Access Control List), 퍼블릭 액세스 차단 설정 등 여러 계층의 제어를 동시에 관리해야 하므로 실수하기 쉽습니다.

조직이 증가할수록, 개발자와 운영 팀의 규모가 커질수록 S3 버킷 관리는 더욱 복잡해집니다. 그래서 FRIIM CSPM(클라우드 보안 포스처 관리) 같은 자동화 도구의 필요성이 대두됩니다. 구성 오류를 지속적으로 감지하고 개선하는 것이 현대적 클라우드 보안의 핵심입니다.

실수 1: 퍼블릭 액세스 차단이 활성화되지 않은 상태

가장 기본이면서도 가장 위험한 실수는 S3 버킷의 '퍼블릭 액세스 차단'(Block Public Access) 설정을 사용하지 않는 것입니다. 이 설정이 비활성화되어 있으면, 버킷 정책이나 ACL이 실수로 공개되도록 구성될 경우 누구나 데이터에 접근할 수 있습니다.

S3 버킷을 생성할 때 기본값은 '퍼블릭 액세스 차단'이 활성화되어 있으나, 이미 생성된 버킷에서는 확인이 필요합니다. 특히 여러 팀이 함께 관리하는 레거시 버킷에서는 이 설정이 해제되어 있을 가능성이 높습니다.

다음은 AWS CLI를 사용하여 모든 S3 버킷의 퍼블릭 액세스 차단 설정을 확인하는 명령어입니다.

aws s3api list-buckets --query 'Buckets[*].Name' --output text | tr '\t' '\n' | while read bucket; do
  echo "Checking bucket: $bucket"
  aws s3api get-public-access-block --bucket "$bucket" 2>/dev/null || echo "No public access block configured for $bucket"
done

결과에서 'NoSuchPublicAccessBlockConfiguration' 오류가 나타나거나 설정이 모두 'false'로 표시된다면 즉시 수정해야 합니다. 다음 명령어로 퍼블릭 액세스 차단을 활성화합니다.

aws s3api put-public-access-block \
  --bucket my-bucket \
  --public-access-block-configuration \
  "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"

이 설정은 네 가지 차단 옵션을 모두 활성화합니다. BlockPublicAcls와 IgnorePublicAcls는 ACL을 통한 공개 접근을 차단하고, BlockPublicPolicy와 RestrictPublicBuckets은 버킷 정책과 액세스 포인트를 통한 공개 접근을 차단합니다.

실수 2: 버킷 정책에서 Principal을 "*"로 설정

S3 버킷 정책이 필요한 경우, 정책에 포함된 Principal(주체)을 부주의하게 "*"로 설정하면 누구나 해당 버킷에 접근할 수 있습니다. 이는 특정 IAM 역할이나 계정에만 접근을 허용하려던 의도와 정반대의 결과를 초래합니다.

예를 들어, 특정 Lambda 함수만 S3 버킷에서 객체를 읽도록 의도했다면, Principal을 해당 Lambda 실행 역할로 명시해야 합니다. 하지만 정책 작성 과정에서 테스트 목적으로 "*"를 사용한 후 원래 값으로 변경하지 않는 실수가 자주 발생합니다.

다음은 잘못된 정책의 예입니다.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/*"
    }
  ]
}

이제 올바른 정책을 보겠습니다. 특정 AWS 계정 내의 특정 IAM 역할만 접근을 허용합니다.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:role/my-lambda-role"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/*"
    }
  ]
}

정책을 변경한 후에는 AWS CLI로 검증합니다.

aws s3api get-bucket-policy --bucket my-bucket --output text | jq .

FRIIM CSPM은 이러한 정책을 자동으로 스캔하여 위험한 Principal 설정을 감지합니다. 수십 개 이상의 버킷을 관리하는 조직이라면 자동화 도구 없이 이를 놓치기 쉽습니다.

실수 3: 서버 측 암호화(SSE)를 활성화하지 않음

S3에 저장된 데이터는 기본적으로 암호화되지 않습니다. 아니, 정확히 말하면 AWS가 관리하는 기본 암호화는 있지만, 고객이 암호화 키를 제어하지 못합니다. 민감한 정보를 다루는 조직이라면 반드시 서버 측 암호화(SSE: Server-Side Encryption)를 명시적으로 활성화해야 합니다.

S3는 세 가지 SSE 옵션을 제공합니다. SSE-S3(AWS 관리 키), SSE-KMS(AWS KMS 관리 키), SSE-C(고객 제공 키). 대부분 조직은 SSE-KMS를 선택하여 자신의 KMS 마스터 키로 암호화합니다.

다음 명령어로 버킷의 기본 암호화를 활성화합니다.

aws s3api put-bucket-encryption \
  --bucket my-bucket \
  --server-side-encryption-configuration '{
    "Rules": [
      {
        "ApplyServerSideEncryptionByDefault": {
          "SSEAlgorithm": "aws:kms",
          "KMSMasterKeyID": "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"
        }
      }
    ]
  }'

버킷에 업로드되는 모든 객체는 이제 지정된 KMS 키로 자동 암호화됩니다. 암호화 키에 대한 접근은 별도의 IAM 정책으로 제어할 수 있습니다.

aws s3api get-bucket-encryption --bucket my-bucket

이 명령어로 현재 암호화 설정을 확인할 수 있습니다. 암호화를 활성화하지 않은 버킷은 '예상치 못한 응답' 오류를 반환합니다.

실수 4: 버전 관리와 MFA Delete를 활성화하지 않음

S3의 버전 관리(Versioning)는 실수로 삭제하거나 덮어쓰인 객체를 복구할 수 있는 기능입니다. 이를 활성화하지 않으면 누군가 객체를 삭제했을 때 즉시 영구 손실됩니다. 또한 MFA Delete를 함께 활성화하면, 버전 삭제 시 MFA 인증을 요구하여 추가 보호를 제공합니다.

다음은 버전 관리를 활성화하는 명령어입니다.

aws s3api put-bucket-versioning \
  --bucket my-bucket \
  --versioning-configuration Status=Enabled

MFA Delete는 더욱 강력한 보호를 제공하지만, 설정 및 관리가 복잡합니다. 루트 계정의 액세스 키와 MFA 장치가 필요합니다. 이로 인해 많은 조직이 이 기능을 활성화하지 않습니다. 하지만 규제가 엄격한 산업(금융, 의료)이라면 MFA Delete 활성화를 고려해야 합니다.

버전 관리를 활성화한 후에는 이전 버전이 저장되므로 스토리지 비용이 증가합니다. 따라서 생명 주기 정책(Lifecycle Policy)을 함께 구성하여 오래된 버전을 자동 삭제하거나 저비용 스토리지로 전환해야 합니다.

실수 5: 로깅(Access Logging)을 활성화하지 않음

S3 버킷에 대한 모든 액세스 기록을 남기지 않으면, 데이터 유출 사건 발생 시 누가 언제 어떤 데이터에 접근했는지 파악할 수 없습니다. 액세스 로깅은 사후 분석(forensics)의 가장 중요한 증거입니다.

S3 Access Logging은 버킷에 대한 모든 요청을 기록하고, 다른 S3 버킷에 로그를 저장합니다. 로그는 일반 텍스트 형식이 아닌 Amazon S3 Log Format으로 저장되며, 분석을 위해 자동 파싱해야 합니다.

먼저 로그를 저장할 별도의 S3 버킷을 생성합니다. 그 후 로깅 버킷에 대한 쓰기 권한을 AWS의 S3 로깅 서비스에 부여합니다.

aws s3api put-bucket-logging \
  --bucket my-bucket \
  --bucket-logging-status '{
    "LoggingEnabled": {
      "TargetBucket": "my-logging-bucket",
      "TargetPrefix": "s3-access-logs/"
    }
  }'

로그를 저장하는 버킷 자체도 액세스 로깅을 활성화하면 무한 루프를 피할 수 있습니다. 대신 정기적으로 로그를 분석해야 합니다.

로그 분석에는 여러 도구를 사용할 수 있습니다. Athena(SQL 쿼리)를 사용하여 로그를 쿼리하거나, CloudWatch Logs로 수집하거나, Seekurity SIEM으로 중앙화하여 위협 탐지와 함께 분석할 수 있습니다.

실수 6: CloudTrail을 구성하지 않음

S3 Access Logging은 S3 데이터 평면(객체 read/write)의 로그를 남기지만, CloudTrail은 관리 평면(IAM 정책 변경, 버킷 설정 수정)의 로그를 남깁니다. 만약 공격자가 버킷 정책을 몰래 수정해서 자신에게 접근 권한을 부여한다면, Access Log에는 기록되지 않습니다.

CloudTrail은 AWS 계정의 모든 API 호출을 기록합니다. 특히 S3 관리 API(put-bucket-policy, delete-bucket-versioning 등)를 모니터링하면, 버킷 설정이 언제 누구에 의해 변경되었는지 확인할 수 있습니다.

조직 수준에서 CloudTrail을 활성화합니다. 다음은 AWS Management Console이나 CLI를 통한 예시입니다.

aws cloudtrail create-trail \
  --name my-organization-trail \
  --s3-bucket-name my-cloudtrail-bucket \
  --region us-east-1
aws cloudtrail start-logging --trail-name my-organization-trail

CloudTrail 로그 역시 중대한 증거이므로, 로그 자체를 보호해야 합니다. CloudTrail이 저장된 S3 버킷에는 강력한 액세스 제어와 로그 검증(Log File Integrity Validation)을 활성화해야 합니다.

실수 7: 객체 Lock을 고려하지 않음

규제 산업(금융, 의료, 법무)에서는 한번 저장한 데이터를 일정 기간 수정하거나 삭제할 수 없어야 합니다. WORM(Write Once Read Many) 모델을 구현해야 하는 것입니다. S3 Object Lock은 이를 가능하게 합니다.

Object Lock을 활성화하면, 각 객체에 대해 보존 기간(Retention Period)을 설정할 수 있습니다. 보존 기간이 끝날 때까지 객체는 삭제되지 않습니다. 또한 Legal Hold를 설정하면, 수동으로 해제할 때까지 객체는 영구적으로 보호됩니다.

Object Lock은 버킷 생성 시에만 활성화할 수 있습니다. 다음 명령어로 새로운 버킷을 Object Lock과 함께 생성합니다.

aws s3api create-bucket \
  --bucket my-locked-bucket \
  --region us-east-1 \
  --object-lock-enabled-for-bucket

기존 버킷에 Object Lock을 추가할 수 없으므로, 규제 요구사항이 있다면 미리 계획하여 버킷을 생성해야 합니다.

실수 8: 크로스 계정 접근을 안전하지 않게 구성

다른 AWS 계정의 사용자나 역할이 S3 버킷에 접근해야 하는 경우, 버킷 정책과 IAM 정책을 함께 구성해야 합니다. 이 과정에서 실수하면 의도하지 않은 계정에 접근을 허용할 수 있습니다.

크로스 계정 접근의 올바른 패턴은 다음과 같습니다. 버킷이 있는 계정(Account A)에서 다른 계정(Account B)의 특정 역할에 접근을 허용합니다.

먼저 Account A의 S3 버킷 정책에 Account B의 역할을 Principal로 지정합니다.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::987654321098:role/cross-account-role"
      },
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::my-bucket",
        "arn:aws:s3:::my-bucket/*"
      ]
    }
  ]
}

그리고 Account B의 cross-account-role IAM 정책도 S3 접근을 명시합니다.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::my-bucket",
        "arn:aws:s3:::my-bucket/*"
      ]
    }
  ]
}

두 정책이 일치할 때만 접근이 허용됩니다. 한쪽 정책만 명시하면 접근이 거부됩니다. 이 '거부는 기본값'이라는 원칙(Principle of Least Privilege)이 실수하기 쉬운 부분입니다.

실수 9: S3 Select와 같은 고급 기능의 보안을 간과

S3 Select는 S3 객체에 저장된 데이터를 SQL 쿼리로 부분 검색할 수 있는 기능입니다. 매우 편리하지만, 이 기능도 적절한 IAM 권한으로 제어해야 합니다. S3 Select 권한 없이 GetObject 권한만 있는 사용자는 전체 객체를 다운로드해야 하므로, 네트워크 대역폭과 비용이 증가합니다.

또한 S3 Transfer Acceleration, CloudFront 배포, S3 Multi-Region Access Points 등 S3의 여러 부가 기능도 각각 별도의 보안 고려사항이 있습니다. 예를 들어 CloudFront로 S3 콘텐츠를 배포하면서 S3 OAC(Origin Access Control)를 활성화하지 않으면, 누구나 S3 URL을 직접 접근할 수 있습니다.

각 기능을 도입하기 전에 보안 문서를 읽고, 최소 권한 원칙에 따라 필요한 IAM 권한만 부여해야 합니다.

실수 10: 정기적인 보안 감사와 모니터링을 하지 않음

위의 9가지 실수를 모두 피했다 해도, 시간이 지나면서 설정이 변경되거나 새로운 버킷이 잘못 구성될 수 있습니다. 정기적인 보안 감사가 없으면, 문제를 발견하는 데 몇 개월이 걸릴 수 있습니다.

AWS Config는 S3 버킷의 설정을 추적하고, 정책 위반을 자동 감지합니다. 예를 들어 'S3 Bucket Public Read Prohibited' 규칙을 활성화하면, 버킷이 공개되는 순간 알림을 받습니다.

aws configservice put-config-rule \
  --config-rule '{
    "ConfigRuleName": "s3-bucket-public-read-prohibited",
    "Description": "Checks that S3 buckets do not allow public read",
    "Source": {
      "Owner": "AWS",
      "SourceIdentifier": "S3_BUCKET_PUBLIC_READ_PROHIBITED"
    }
  }'

FRIIM CSPM은 AWS Config보다 더욱 포괄적인 보안 포스처 관리를 제공합니다. 수백 개의 S3 버킷을 자동 스캔하고, 위험한 설정을 대시보드에서 한눈에 파악할 수 있습니다. 또한 설정 변경 이력을 추적하여, 언제 누가 정책을 수정했는지 확인할 수 있습니다.

정기적인 감시 외에도 분기별 또는 연간 수동 감사를 수행해야 합니다. 특히 조직 구조가 변경되거나 프로젝트가 종료될 때 미사용 버킷을 정리하고, 불필요한 권한을 제거해야 합니다.

일반적인 오류와 해결 방법

S3 보안을 구현하면서 마주치는 일반적인 문제들을 정리했습니다.

문제: 버킷 정책을 수정했는데 적용되지 않음 버킷 정책은 변경 후 즉시 적용되지만, 캐싱으로 인해 지연될 수 있습니다. CloudFront 배포 뒤에 있다면 캐시를 무효화해야 합니다. 또한 버킷 정책과 IAM 정책이 모두 일치해야 하므로, 양쪽을 함께 검토하세요.

문제: 암호화를 활성화한 후 기존 객체가 암호화되지 않음 S3 버킷의 기본 암호화 설정은 변경 이후에 업로드되는 객체에만 적용됩니다. 기존 객체를 암호화하려면 S3 Batch Operations를 사용하여 대량 복호화 및 재암호화를 수행해야 합니다.

문제: 버전 관리를 활성화한 후 비용이 갑자기 증가함 S3 버전 관리는 삭제된 객체도 이전 버전으로 유지하므로, 저장 공간 사용량이 급증할 수 있습니다. 생명 주기 정책으로 오래된 버전을 자동 삭제하거나 Intelligent-Tiering으로 비용을 절감하세요.

문제: 특정 AWS 계정에서 S3 접근 권한 거부 발생 Bucket Policy와 IAM Policy 중 하나라도 명시적 거부(Deny)가 있으면 접근이 차단됩니다. 두 정책을 함께 검토하고, AWS Policy Simulator로 접근 권한을 사전 검증하세요.

AWS Policy Simulator는 다음 URL에서 접근할 수 있습니다: https://policysim.aws.amazon.com/

실전 사례: 금융 회사의 S3 보안 개선

한 중견 금융 회사(익명)는 클라우드 마이그레이션 초기 단계에서 500개 이상의 S3 버킷을 생성했습니다. 초기에는 빠른 구축이 최우선이었기 때문에, 보안 설정은 최소한으로만 구성되었습니다.

외부 보안 감사 결과, 다음과 같은 문제가 발견되었습니다:

  • 430개 버킷에서 퍼블릭 액세스 차단이 비활성화됨
  • 120개 버킷에서 로깅이 구성되지 않음
  • 80개 버킷에서 암호화가 활성화되지 않음
  • 모든 버킷에서 버전 관리 미활성화

금융감독 규정(전자금융감독규정)에 따라 3개월 내 개선이 필수였습니다. 회사는 다음과 같은 조치를 취했습니다:

첫 번째 단계: FRIIM CSPM을 도입하여 모든 S3 버킷의 현재 보안 포스처를 파악했습니다. 대시보드에서 우선순위별로 문제를 분류하고, 자동 치료 정책(Auto-Remediation)을 설정했습니다.

두 번째 단계: 자동 스크립트를 작성하여 모든 버킷에 퍼블릭 액세스 차단과 암호화를 일괄 적용했습니다. 로깅과 버전 관리는 운영 팀이 수동으로 구성했습니다.

세 번째 단계: CloudTrail과 AWS Config를 조직 수준에서 활성화하고, 로그를 중앙화된 로깅 계정으로 수집했습니다. Seekurity SIEM을 통해 S3 관리 이벤트를 실시간으로 모니터링했습니다.

개선 결과:

  • 위험한 S3 버킷 정책: 100% 수정
  • 규정 준수 증명: 3개월 내 완료
  • 보안 사건 탐지 시간: 평균 2주 → 1일 이내로 단축
  • 수동 감사 작업: 월 40시간 → 5시간으로 감소

이 회사는 이후 신규 버킷 생성 시 자동으로 보안 설정이 적용되도록 Service Control Policy(SCP)를 통한 강제 정책을 설정했습니다. 이를 통해 향후 실수가 재발하지 않도록 보장했습니다.

향후 전망: S3 보안의 진화

AWS는 지속적으로 S3의 보안 기능을 강화하고 있습니다. 최근의 주목할 만한 변화는 다음과 같습니다.

1. 기본 보안 강화 AWS는 2024년부터 새로운 S3 계정 설정을 점진적으로 변경하여 모든 버킷의 퍼블릭 액세스를 기본적으로 차단합니다. 이는 업계 모범 사례를 기본값으로 만드는 의도입니다.

2. AI 기반 위협 탐지 AWS GuardDuty는 S3 데이터 이벤트를 분석하여 비정상적인 접근 패턴을 감지합니다. KYRA AI Sandbox 같은 도구와 함께 사용하면, S3에 저장된 악성 파일도 자동 검사할 수 있습니다.

3. 제로 트러스트 아키텍처 지원 AWS는 Verified Permissions와 같은 새로운 권한 관리 서비스를 개발하고 있어, 더욱 세밀한 접근 제어가 가능해질 것입니다.

앞으로 클라우드 보안은 구성 오류 방지에서 지속적인 모니터링과 AI 기반 이상 탐지로 진화할 것입니다. 조직은 이 변화에 대응하기 위해 자동화 도구와 중앙화된 모니터링 체계를 미리 준비해야 합니다.

결론: S3 보안을 위한 실행 계획

S3 데이터 유출은 대부분 기술적 취약점이 아닌 설정 오류로 인해 발생합니다. 따라서 가장 효과적인 방어는 올바른 설정입니다. 이 글에서 소개한 10가지 실수를 피하기 위한 핵심 사항을 정리합니다.

  • 즉시 실행 항목: 모든 S3 버킷의 퍼블릭 액세스 차단을 활성화하고, 버킷 정책의 Principal "*" 설정을 제거하세요. 이 두 가지만으로도 대부분의 S3 유출 사건을 방지할 수 있습니다.
  • 단기 개선 항목: 서버 측 암호화, 액세스 로깅, CloudTrail을 활성화합니다. 각 기능의 로그를 안전하게 보호하고 정기적으로 검토하세요.
  • 중기 전략: FRIIM CSPM을 도입하여 지속적인 보안 포스처 감시를 자동화합니다. AWS Config 규칙을 구성하고, 정책 위반을 자동으로 치료하는 프로세스를 구축하세요.
  • 지속적 모니터링: CloudTrail 이벤트와 S3 Access Log를 Seekurity SIEM으로 중앙화하여, 비정상적인 접근 패턴을 실시간으로 탐지합니다.

S3는 안전한 서비스입니다. 하지만 강력한 도구일수록 잘못 사용할 위험도 큽니다. 이 글의 체크리스트를 참고하여 조직의 S3 환경을 지금 바로 감사하시기 바랍니다.

Tags

#AWS S3#클라우드 보안#데이터 유출#액세스 제어#IAM#버킷 정책#암호화#설정 오류#FRIIM CSPM#Seekurity SIEM