강의

멘토링

커뮤니티

인프런 커뮤니티 질문&답변

taeho Kim님의 프로필 이미지
taeho Kim

작성한 질문수

실무에서 사용중인 AWS 클라우드 IAM 이해와 보안

1.9. Path 사용 예시 살펴보기

terraform destroy 로 s3 bucket을 삭제할 경우

해결된 질문

작성

·

17

1

1. 무엇을 하고 싶으신가요?

해당 실습을 조금 더 빠르고 간편하게 재현하고 싶어서 s3 bucket과 안에 오브젝트 파일을 생성하는 부분까지 테라폼 코드로 프로비저닝 하였습니다.

 

강의를 보며 결과까지 모두 확인을 하였고, 이제 위 리소스들을 전부 destroy 하고 싶습니다.

 

2. 언제, 어떤 오류가 발생하시나요?

terraform apply를 할 경우,
Role 3개와
버킷, 버킷 정책, 오브젝트 파일

총 6개의 리소스가 생성됩니다.

 

terraform state list를 통해 관리 대상을 확인해보아도 6개의 리소스를 확인할 수 있습니다.

그런데 terraform destroy 명령을 수행할 경우
버킷을 제외한 5개의 리소스만 삭제 플랜에 출력되는 것을 확인하였고 이대로 진행할 경우

결국 empty한 s3 bucket만 남아 따로 cli 명령이나 콘솔에서 삭제를 해주어야합니다.

 

3. 어떤 시도를 해보셨나요?

내부 오브젝트 파일 때문이라는 가설을 세우고

force_destroy = true

속성을 true로 지정하였지만 버킷 내부 객체까지만 삭제되었고 버킷은 삭제되지 않습니다.

이후 권한 문제라는 가설을 세워보았지만 s3 액세스 정책을 deny 기반으로 ListBucket을 지정하였기 때문에 해당 가설도 기각하였습니다.

 

4. 작성한 코드를 공유해주세요.

data "aws_caller_identity" "this" {}

# IAM Role
resource "aws_iam_role" "this" {
    count = 2
    name = "thbins-${count.index}"
    path = "/dev/"
    assume_role_policy = jsonencode({
        Version = "2012-10-17"
        Statement = [
            {
                Action = "sts:AssumeRole"
                Effect = "Allow"
                Principal = {
                    # AWS = "${data.aws_caller_identity.this.arn}"
                    AWS = "arn:aws:iam::${data.aws_caller_identity.this.account_id}:root"
                }
            },
        ]
    })
    managed_policy_arns = ["arn:aws:iam::aws:policy/AdministratorAccess"]
}

resource "aws_iam_role" "this2" {
    name = "thbins-2"
    path = "/"
    assume_role_policy  = jsonencode({
        Version = "2012-10-17"
        Statement = [
            {
                Action = "sts:AssumeRole"
                Effect = "Allow"
                Principal = {
                    # AWS = "${data.aws_caller_identity.this.arn}"
                    AWS = "arn:aws:iam::${data.aws_caller_identity.this.account_id}:root"
                }
            },
        ]
    })
    managed_policy_arns = ["arn:aws:iam::aws:policy/AdministratorAccess"]
}

# S3
variable "bucket_name" {
  description = "S3 bucket name (must be globally unique)"
  type        = string
}

resource "aws_s3_bucket" "test" {
  bucket = var.bucket_name
  force_destroy = true # 버킷 안에 객체를 생성하기 때문에 해당 속성을 true로 지정한다.
}

data "aws_iam_policy_document" "test_bucket" {
  statement {
    sid    = "Statement1"
    effect = "Deny"

    principals {
      type        = "AWS"
      identifiers = ["*"]
    }

    actions = [
      "s3:ListBucket",
    ]

    resources = [
      aws_s3_bucket.test.arn,
      "${aws_s3_bucket.test.arn}/*",
    ]

    condition {
      test     = "StringNotLike"
      variable = "aws:PrincipalArn"

      values = [
        # 여기서 account_id를 하드코딩하지 않고 자동으로 맞춰줌
        "arn:aws:iam::${data.aws_caller_identity.this.account_id}:role/dev/*",
      ]
    }
  }
}

resource "aws_s3_bucket_policy" "test" {
  bucket = aws_s3_bucket.test.id
  policy = data.aws_iam_policy_document.test_bucket.json
}

resource "aws_s3_object" "test_file" {
  bucket = aws_s3_bucket.test.id
  key    = "test_success.txt"
  content = "This is a test file for IAM path-based S3 access demo.\n"

  # 선택: 텍스트 파일임을 명시
  content_type = "text/plain"
}

답변 1

0

천강민님의 프로필 이미지
천강민
지식공유자

안녕하세요.

좋은 질문 감사드립니다.

 

먼저.. 경험하기 어려운 일을 당하셔서 많이 당황하셨을 것 같습니다.

https://stackoverflow.com/questions/79581321/terraform-thinks-s3-bucket-has-been-deleted-after-adding-a-bucket-policy

위 링크를 보면 근본 원인을 설명하고 있는데요. 간단히만 말씀드리면,

S3 HeadBucket API는 버킷이 없는 것과 권한이 없는 것을 구분하지 않아서 그렇습니다.

현재 코드가 s3:ListBucket API에 대해서 Deny 하는 정책이다 보니 생성은 정상적으로 되는데, 삭제하는 경우에는 권한이 없는 것임에도 불구하고 버킷이 제거된 것으로 판단하게 되는거죠.

그렇기에 아래처럼 정책을 Allow 기반으로 변경해주면 정상적으로 동작하게 됩니다.

data "aws_iam_policy_document" "test_bucket" {
  statement {
    sid    = "Statement1"
    effect = "Allow"

    principals {
      type        = "AWS"
      identifiers = ["*"]
    }

    actions = [
      "s3:ListBucket",
    ]

    resources = [
      "arn:aws:s3:::${var.bucket_name}",
      "arn:aws:s3:::${var.bucket_name}/*",
    ]

    condition {
      test     = "StringLike"
      variable = "aws:PrincipalArn"

      values = [
        # 여기서 account_id를 하드코딩하지 않고 자동으로 맞춰줌
        "arn:aws:iam::${data.aws_caller_identity.this.account_id}:role/*",
      ]
    }
  }
}

참고 부탁드립니다. 감사합니다.

천강민 드림.

taeho Kim님의 프로필 이미지
taeho Kim

작성한 질문수

질문하기