문제 상황#

stacks/audit-security/에서 CloudTrail을 활성화하려고 terraform apply 실행.

에러#

Error: creating CloudTrail Trail (playball-audit-trail): InsufficientS3BucketPolicyException: 
Incorrect S3 bucket policy is detected for bucket: playball-audit-logs

원인 분석#

순환 의존성(Circular Dependency):

CloudTrail 생성 → S3 bucket policy에 CloudTrail 쓰기 권한 필요
  ↕
S3 bucket policy → CloudTrail ARN 참조 필요 (module.cloudtrail.source_arn)
  ↕
CloudTrail ARN → CloudTrail이 생성되어야 존재

코드에서 dynamic "statement"module.cloudtrail.source_arn != null일 때만 policy를 추가하도록 했는데, CloudTrail이 아직 안 만들어졌으니 source_arn = null → dynamic block 스킵 → policy에 CloudTrail 권한 없음 → CloudTrail 생성 실패.

dynamic "statement" {
  for_each = module.cloudtrail.source_arn != null ? [1] : []  # ← null이라 빈 리스트
  content {
    sid    = "AWSCloudTrailAclCheck"
    ...
    values = [module.cloudtrail.source_arn]  # ← null
  }
}

해결#

CloudTrail ARN은 리소스 생성 전에도 형식이 예측 가능하므로, locals에서 미리 구성:

locals {
  trail_arn = "arn:aws:cloudtrail:${local.aws_region}:${local.account_id}:trail/${local.project_name}-audit-trail"
}

bucket policy에서 module output 대신 local.trail_arn 사용:

# 수정 후 - dynamic 제거, local ARN 직접 참조
statement {
  sid    = "AWSCloudTrailAclCheck"
  effect = "Allow"
  principals {
    type        = "Service"
    identifiers = ["cloudtrail.amazonaws.com"]
  }
  actions   = ["s3:GetBucketAcl"]
  resources = [aws_s3_bucket.audit_logs.arn]
  condition {
    test     = "StringEquals"
    variable = "aws:SourceArn"
    values   = [local.trail_arn]
  }
}

교훈#

AWS 리소스 중 ARN 형식이 결정적(deterministic)인 것들은 생성 전에 미리 구성할 수 있다:

arn:aws:cloudtrail:{region}:{account}:trail/{name}
arn:aws:s3:::{bucket-name}
arn:aws:iam::{account}:role/{role-name}

이런 경우 module output의 순환 참조를 피하려면 locals에서 ARN을 직접 구성하는 패턴을 쓰면 된다.

추가 이슈: S3 버킷 이름 충돌#

처음에 project_name = "goormgb" → 버킷 goormgb-audit-logs 생성 시도 → BucketAlreadyExists 에러. 메인 계정(497012402578)에서 이미 사용 중인 이름이었음. S3 버킷은 전역 유니크이므로, 계정별로 다른 prefix(playball-)를 사용해야 한다.

goormgb-audit-logs      → 메인 계정에서 이미 사용 중
playball-audit-logs     → CA 계정용으로 변경

파일#

  • 301-playball-terraform/stacks/audit-security/main.tf
  • 301-playball-terraform/modules/cloudtrail/main.tf