【问题标题】:How to avoid S3 bucket policy conflict如何避免 S3 存储桶策略冲突
【发布时间】:2021-03-26 19:09:09
【问题描述】:

我目前有两个(可能是冲突的)S3 存储桶策略,它们在 Terraform 上显示出永久性差异。在展示部分代码之前,我将尝试对结构进行概述。

我目前正在使用一个模块,它:

  1. 将 IAM 角色和一个 S3 存储桶作为输入
  2. 将 S3 存储桶策略附加到输入的角色
  3. 将 S3 存储桶(允许 VPC)策略附加到输入的 S3 存储桶

我创建了一些代码(sn-p 而非完整代码)来说明模块的外观。

政策如下:

# S3 Policy to be attached to the ROLE
data "aws_iam_policy_document" "foo_iam_s3_policy" {
  statement {
    effect    = "Allow"
    resources = ["${data. s3_bucket.s3_bucket.arn}/*"]
    actions   = ["s3:GetObject", "s3:GetObjectVersion"]
  }
  statement {
    effect    = "Allow"
    resources = [data.s3_bucket.s3_bucket.arn]
    actions   = ["s3:*"]
  }
}

# VPC Policy to be attached to the BUCKET
data "aws_iam_policy_document" "foo_vpc_policy" {
  statement {
    sid       = "VPCAllow"
    effect    = "Allow"
    resources = [data.s3_bucket.s3_bucket.arn, "${data.s3_bucket.s3_bucket.arn}/*"]
    actions   = ["s3:GetObject", "s3:GetObjectVersion"]
    condition {
      test     = "StringEquals"
      variable = "aws:SourceVpc"
      values   = [var.foo_vpc]
    }
    principals {
      type        = "*"
      identifiers = ["*"]
    }
  }
}

政策附件如下所示:

# Turn policy into a resource to be able to use ARN
resource "aws_iam_policy" "foo_iam_policy_s3" {
  name        = "foo-s3-${var.s3_bucket_name}"
  description = "IAM policy for foo on s3"
  policy      = data.aws_iam_policy_document.foo_iam_s3_policy.json
}

# Attaches s3 bucket policy to IAM Role
resource "aws_iam_role_policy_attachment" "foo_attach_s3_policy" {
  role       = data.aws_iam_role.foo_role.name
  policy_arn = aws_iam_policy.foo_iam_policy_s3.arn
}

# Attach foo vpc policy to bucket
resource "s3_bucket_policy" "foo_vpc_policy" {
  bucket = data.s3_bucket.s3_bucket.id
  policy = data.aws_iam_policy_document.foo_vpc_policy.json
}

现在让我们跳出模块,这里创建了 S3 存储桶(我提到的将被输入到模块中的那个),并且需要将另一个策略附加到它(S3 存储桶)。所以在模块之外,我们:

  1. 为上述模块提供一个 S3 存储桶作为输入(与 IAM 角色一起)
  2. 创建一个策略以允许某些 IAM 角色将对象放入上述存储桶中
  3. 将创建的策略附加到存储桶

政策如下:

# Create policy to allow bar to put objects in the bucket
    data "aws_iam_policy_document" "bucket_policy_bar" {
      statement {
        sid       = "Bar IAM access"
        effect    = "Allow"
        resources = [module.s3_bucket.bucket_arn, "${module. s3_bucket.bucket_arn}/*"]
        actions   = ["s3:PutObject", "s3:GetObject", "s3:ListBucket"]
        principals {
          type        = "AWS"
          identifiers = [var.bar_iam]
        }
      }
    }

它的附件看起来像:

    # Attach Bar bucket policy
    resource "s3_bucket_policy" "attach_s3_bucket_bar_policy" {
      bucket = module.s3_bucket.bucket_name
      policy = data.aws_iam_policy_document.bucket_policy_bar.json
    }

(更多上下文:基本上 foo 是一个数据库,需要 VPC 和 s3 附加到角色才能对存储桶进行操作,而 bar 是一个需要将数据写入存储桶的外部服务)

出了什么问题

当我尝试计划/应用时,Terraform 显示总是有变化,并显示 bar 的 S3 存储桶策略 (bucket_policy_bar) 和附加在模块内的 VPC 策略 (foo_vpc_policy) 之间的覆盖。

事实上,我遇到的错误听起来像是here 所描述的:

此资源的使用与 aws_iam_policy_attachment 资源并将永久显示 两者都定义的区别。

但我将策略附加到 S3 而不是角色,所以我不确定此警告是否适用于我的情况。

为什么我的政策有冲突?我该如何避免这种冲突?

编辑: 为澄清起见,我有一个 S3 存储桶,我需要将两个策略附加到该存储桶。一种允许 VPC 访问(foo_vpc_policy,在模块内创建),另一种(bucket_policy_bar)允许 IAM 角色将对象放入存储桶中

【问题讨论】:

  • 您能说明一下您的设置吗?所以你有两个桶,一个在模块module.aws_s3_bucket,另一个在module.s3_bucket,你想混合他们的策略吗?
  • 嗨@Marcin。我已经编辑了我的问题。让我知道是否可以提供任何进一步的说明
  • 那么module.s3_bucket.bucket_namemodule.aws_s3_bucket.bucket_arn 指的是同一个存储桶,尽管它们位于不同的模块中?
  • 它们指的是同一个桶(它也是同一个模块)。我在提出问题时犯了错字(在我的实际代码中它们是相同的)。将修复问题+1
  • @Marcin 基本上是同一个桶。它是在s3.tf 中的模块外部创建的,然后有两个(应该是独立的)步骤:1. 将其传递给模块(附加一些 VPC 访问策略) 2. 附加一个赋予 IAM 角色访问权限的策略存储桶(发生在s3.tf) 数据库需要 VPC 访问才能从 S3 获取数据。并且需要 IAM 角色访问权限,以便外部工具可以将文件放入存储桶。我本来希望有两个策略附加到存储桶上。但我最终遇到了冲突

标签: amazon-web-services terraform


【解决方案1】:

总会有变化

没错。 aws_s3_bucket_policy 在存储桶上设置新策略。它向其中添加新语句。

由于您为同一个存储桶调用aws_s3_bucket_policy 两次,第一次在module.s3_bucket 模块中,然后在父模块中第二次(我猜),父模块将简单地尝试在存储桶上设置新政策。当你再次执行terraform apply/plan 时,terraform 会检测到module.s3_bucket 中定义的策略不同,并会尝试更新它。所以你基本上会得到一个圆圈,每个apply 都会将存储桶策略更改为新的。

我不知道允许您更新(即添加新语句)到现有存储桶策略的 terraform 资源。因此,我会尝试重新考虑您的设计,以便您只执行aws_s3_bucket_policy 一次,其中包含您需要的所有语句。

【讨论】:

  • 假设我获得了带有 VPC 策略的模块的输出。那么我是否只需要(以某种方式)合并主模块中的策略?
  • @alt-f4 是的,我认为应该可以。您可以使用动态块在aws_iam_policy_document 中生成statement 的数量,以生成一个最终策略文档,然后将其放置在存储桶中。
【解决方案2】:

感谢Marcin 的提示,我能够通过将模块内的策略附件作为可选附件来解决问题,例如:

# Attach foo vpc policy to bucket
resource "s3_bucket_policy" "foo_vpc_policy" {
  count  = var.attach_vpc_policy ? 1 : 0 # Only attach VPC Policy if required
  bucket = data.s3_bucket.s3_bucket.id
  policy = data.aws_iam_policy_document.foo_vpc_policy.json
}

所有情况下的策略都已添加为模块的输出,例如:

# Outputting only the statement, as it will later be merged with other policies
output "foo_vpc_policy_json" {
  description = "VPC Allow policy json (to be later merged with other policies that relate to the bucket outside of the module)"
  value       = data.aws_iam_policy_document.foo_vpc_policy.json
}

对于需要延迟附加政策的情况(等待与其他政策一起附加),我通过source_json 内联政策)

data "aws_iam_policy_document" "bucket_policy_bar" {
  # Adding the VPC Policy JSON as a base for this Policy (docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document)
  source_json = module.foor_.foo_vpc_policy_json # here we add the statement that has
  statement {
    sid       = "Bar IAM access"
    effect    = "Allow"
    resources = [module.s3_bucket_data.bucket_arn, "${module.s3_bucket_data.bucket_arn}/*"]
    actions   = ["s3:PutObject", "s3:GetObject", "s3:ListBucket"]
    principals {
      type        = "AWS"
      identifiers = [var.bar_iam]
    }
  }
}

【讨论】:

    猜你喜欢
    • 2016-12-23
    • 2019-08-02
    • 2011-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-26
    • 2021-01-19
    • 2021-03-31
    相关资源
    最近更新 更多