ES /docs

failed to calculate captured size for Facility ID: 6, error: User: arn:aws:iam::619071347432:user/sy

RCA: failed to calculate captured size — S3 PutObject IAM permission denied

Overview#

What Happened#

2026-04-24 04:31 UTC 경, cupixvista-api-worker 서비스의 cron job Cupix::Cron::Facility.flush_stale_captured_size가 42개 Facility에 대해 captured size를 계산하려고 시도했으나, S3 PutObject 권한 부족으로 전량 실패했다. Production, QA, Staging 3개 환경 모두 동일 증상이 발생했으며, IAM 정책이 허용하는 버킷 이름(cupix-cupixvista-prod-data-*)과 애플리케이션이 실제 사용하는 버킷 이름(cupix-cupixworks-prod-data-stage-uswe2)이 불일치하는 것이 원인이다.

Quick Facts#

Field Value
exception.class Aws::S3::Errors::AccessDenied
exception.message User: arn:aws:iam::619071347432:user/system/tesla-api-production-86ob is not authorized to perform: s3:PutObject
top_frame app/services/cupix/voxel_service.rb:20
env production, us-west-2

Affected Teams#

Team / Domain Error Count Impact
cupixvista-api-worker (Facility) 96 (3 환경 합산) 42개 Facility의 captured size 계산 실패, voxel reality capture CSV 미생성

Timeline#

  1. 04:06:28Z — Staging 환경에서 최초 에러 발생 (tesla-api-stage-7lol)
  2. 04:31:15Z — QA 환경 에러 발생 (tesla-api-qa-fltp)
  3. 04:31:21Z — Production 환경 에러 발생 (tesla-api-production-86ob), 클러스터 감지
  4. 04:31:21Z — 약 25분간 총 96건 에러 발생 후 cron batch 완료

Error Log#

Datadog Logs

text
failed to calculate captured size for Facility ID: 6, error: User: arn:aws:iam::619071347432:user/system/tesla-api-production-86ob is not authorized to perform: s3:PutObject on resource: "arn:aws:s3:::cupix-cupixworks-prod-data-stage-uswe2/tesla/voxel/reality_captures/facility_key=6meqt9/2026-04-24.csv" because no identity-based policy allows the s3:PutObject action

Impact#

  • Service: cupixvista-api-worker
  • 발생 횟수: 96 (Production 30건 + QA/Stage 66건)
  • 최초 발생: 2026-04-24T04:06:28Z (Stage), 2026-04-24T04:31:21Z (Production)
  • 최근 발생: 2026-04-24T04:31:21Z
  • 영향 범위: 42개 Facility의 captured size 계산 실패. Voxel reality capture CSV가 S3에 업로드되지 않아 downstream Athena 쿼리 및 captured area 계산이 불가능.

Root Cause Summary#

CupixVista 환경(cupix-aws5)의 Terraform IAM 정책이 cupix-cupixvista-prod-data-* 패턴의 S3 버킷에 대한 접근만 허용하지만, Rails 애플리케이션의 $DATA_PIPELINE_BUCKET_PREFIXLAUNCH_MODE와 무관하게 항상 cupixworks를 사용하여 cupix-cupixworks-prod-data-stage-uswe2 버킷에 쓰기를 시도한다. 이 IAM 정책과 실제 버킷 이름의 불일치로 인해 모든 s3:PutObject 요청이 AccessDenied로 거부된다.

Technical Analysis#

Code Path#

1. Cron 스케줄러 — 4시간마다 :31분에 실행

config/schedule.rb:105ruby
runner 'Cupix::Cron::Facility.flush_stale_captured_size'

2. Cron handler — stale 상태의 Facility를 최대 30개씩 순회하며 captured size 계산

lib/cupix/cron/facility.rb:80-96ruby
def self.flush_stale_captured_size
  session = Cupix::Tesla.internal_user_session
  Facility.where(captured_size_state: :stale).limit(30).each do |facility|
    facility.calculate_captured_size(session: session)
  rescue => e
    logger.warn("Failed to flush stale captured size for Facility #{facility.id}")
  end
end

3. Error wrapper — 예외를 catch하여 에러 메시지를 로깅 (이 로그가 Datadog에 수집됨)

app/models/concerns/voxel_module.rb:19-27ruby
def calculate_captured_size(session: nil)
  calculate_captured_size!(session: session)
rescue => e
  logger.error("failed to calculate captured size for #{self.class.name} ID: #{id}, error: #{e.message}")
end

4. Service 호출 — Facility인 경우 VoxelService로 위임

app/models/concerns/voxel_module.rb:46-56ruby
def calculate_captured_size!(session: nil, **kwargs)
  if is_a?(Facility)
    Cupix::VoxelService.calculate_captured_size!(facility: self, session: session)
  end
end

5. S3 PutObject (실패 지점) — CSV를 S3에 업로드

app/services/cupix/voxel_service.rb:14-28ruby
def calculate_captured_size!(facility: nil, session: nil, **kwargs)
  # ... validations ...
  reality_captures_s3_object(facility.key).put(
    body: reality_captures_csv(facility),
    content_type: 'text/csv',
    acl: 'bucket-owner-full-control',
    tagging: { ... }.to_query
  )
  # ... then calls captured_area! API ...
end

6. S3 Object 경로 구성 — 버킷 이름에 $DATA_PIPELINE_BUCKET_PREFIX 사용

app/services/cupix/voxel_service.rb:188-194ruby
def reality_captures_s3_object(facility_key)
  Cupix::StorageService.object(
    region: Cupix::Tesla.region,
    bucket_name: "#{$DATA_PIPELINE_BUCKET_PREFIX}-stage-#{Cupix::Tesla.region_code}",
    key: "tesla/voxel/reality_captures/facility_key=#{facility_key}/#{DateTime.now.strftime('%Y-%m-%d')}.csv"
  )
end

7. $DATA_PIPELINE_BUCKET_PREFIX 정의LAUNCH_MODE와 무관하게 항상 cupixworks 사용

config/environments/production.rb:202ruby
$DATA_PIPELINE_BUCKET_PREFIX = "#{ENV['TENANT'] || 'cupix'}-cupixworks-#{Rails.env.delete_suffix('uction')}-data"

TENANT=cupix, Rails.env=production일 때 "production".delete_suffix("uction") = "prod"$DATA_PIPELINE_BUCKET_PREFIX = "cupix-cupixworks-prod-data" → 최종 버킷: cupix-cupixworks-prod-data-stage-uswe2

8. Terraform IAM 정책sse_bucket_prefix_name으로 버킷 패턴 결정

cupix-infrastructure/cupix-service/api-eb/main.tf:89-90hcl
data_pipeline_s3_bucket        = local.is_production ? (local.is_cupix_tenant ? "arn:aws:s3:::${var.tenant}-${var.sse_bucket_prefix_name}-prod-data-*" : ...) : ...
data_pipeline_s3_bucket_object = local.is_production ? (local.is_cupix_tenant ? "arn:aws:s3:::${var.tenant}-${var.sse_bucket_prefix_name}-prod-data-*/*" : ...) : ...

CupixVista production (cupix-aws5)에서 sse_bucket_prefix_name = "cupixvista" → IAM 정책이 허용하는 패턴: arn:aws:s3:::cupix-cupixvista-prod-data-*

불일치 요약:

  • IAM 정책 허용 패턴: cupix-cupixvista-prod-data-*
  • 앱이 사용하는 버킷: cupix-cupixworks-prod-data-stage-uswe2
  • cupixvistacupixworksAccessDenied

Log Evidence#

Datadog 쿼리:

text
service:cupixvista-api-worker status:error

96건의 에러 로그에서 42개 고유 Facility ID가 동일한 s3:PutObject 권한 오류를 보였다. 3개 환경(Production, QA, Staging)의 IAM user 모두 동일 실패:

text
[04:31:15Z] tesla-api-stage-7lol → AccessDenied (Facility 4, 9, 10, 12)
[04:31:17Z] tesla-api-qa-fltp → AccessDenied (Facility 5, 6, 12, 14, 15, 25, 28, ...)
[04:31:21Z] tesla-api-production-86ob → AccessDenied (모든 production Facility)

동일 S3 버킷에 대한 Lambda(cupixworks-prod-data-voxel) 작업은 정상 수행 — 버킷 자체는 존재하고 접근 가능하며, IAM user 정책만 문제:

text
service:cupixworks-prod-data-voxel "cupix-cupixworks-prod-data-stage-uswe2"
→ info level, VoxelService::RemoveAthenaCache 정상 동작

Cron job의 warn 로그가 error 로그와 1:1 매칭:

text
[warn] class=Cupix::Cron::Facility func=flush_stale_captured_size
"Failed to flush stale captured size for Facility {N}"

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 IAM 정책의 버킷 이름 패턴과 앱이 사용하는 실제 버킷 이름 불일치 Terraform의 sse_bucket_prefix_name=cupixvista vs Rails의 $DATA_PIPELINE_BUCKET_PREFIXcupixworks 사용 (config/environments/production.rb:202). 에러 메시지에 no identity-based policy allows the s3:PutObject action 명시. 3개 환경 모두 동일 실패. Confirmed
H2 S3 버킷 정책 변경 또는 버킷 삭제 3개 환경이 동시에 영향을 받음 Lambda(cupixworks-prod-data-voxel)가 동일 버킷에 정상 접근 중. 에러 메시지가 "no identity-based policy" — bucket policy가 아닌 IAM user policy 문제 명시 Rejected
H3 AWS IAM 정책이 최근 변경/삭제됨 이전에 정상 동작했다면 정책 변경이 원인일 수 있음 Terraform 코드 분석 결과, sse_bucket_prefix_name이 CupixVista 환경에서 원래 cupixvista로 설정됨. Rails 코드도 원래부터 cupixworks 하드코딩. 즉, 이 기능이 CupixVista 환경에 새로 도입되면서 기존 불일치가 처음 노출된 것으로 추정 Rejected

Fix Recommendation#

즉시 조치 (Critical)#

옵션 A (Terraform 수정 — 권장): IAM 정책에 cupixworks 버킷 패턴을 추가

  • cupix-infrastructure/cupix-service/api-eb/main.tf:89-90data_pipeline_s3_bucket local에 cupix-cupixworks-prod-data-* 패턴도 허용하도록 수정
  • 이 방법이 Rails 코드 변경 없이 즉시 적용 가능하며, 다른 서비스에 영향을 주지 않음

옵션 B (Rails 수정): $DATA_PIPELINE_BUCKET_PREFIXLAUNCH_MODE에 따라 cupixvista 또는 cupixworks를 사용하도록 변경

  • config/environments/production.rb:202LAUNCH_MODE == 'CUPIXVISTA'일 때 prefix를 cupixvista로 설정
  • 그러나 이 경우 실제 S3 버킷이 cupix-cupixvista-prod-data-stage-uswe2로 존재해야 하므로 버킷 생성도 필요할 수 있음

단기 개선 (1주 이내)#

  • $DATA_PIPELINE_BUCKET_PREFIX와 Terraform의 sse_bucket_prefix_name 간 일관성 확보. 환경 변수화하여 양쪽에서 동일한 값을 참조하도록 리팩터링
  • QA, Staging 환경도 동일 수정 적용 확인

장기 개선 (재발 방지)#

  • CupixVista와 CupixWorks 환경 간 S3 버킷 네이밍 규칙 통일 또는 문서화
  • IAM 정책 테스트를 CI/CD에 포함 — Terraform plan 시 S3 접근 패턴이 실제 애플리케이션 코드와 일치하는지 검증

Monitoring#

  • Facility captured size 실패율 모니터링:
text
service:cupixvista-api-worker "failed to calculate captured size" status:error
  • S3 AccessDenied 에러 전반 모니터링:
text
service:cupixvista-api-worker "is not authorized to perform" status:error

Risk Assessment#

  • Risk level: medium — captured size 계산이 전면 중단되어 voxel reality capture 데이터가 누락되지만, 서비스 전체 장애는 아님
  • 예상 복잡도: standard — Terraform IAM 정책 수정 1곳 변경으로 해결 가능하나, 3개 환경 모두 적용 및 검증 필요