有没有办法使用terraform将IAM Bucket策略语句附加到现有语句中?

有没有办法使用terraform将IAM Bucket策略语句附加到现有语句中?,terraform,Terraform,我目前在一个中央帐户中有一个集中的S3存储桶,可通过多个其他子帐户访问。我希望通过采用现有IAM bucket策略,动态更新每个子帐户的bucket策略,并附加一条新语句,允许调用帐户的IAM角色访问bucket 我尝试将aws_iam_policy_文档和source_json与新语句结合使用。但是,所有这些都会覆盖现有语句 我试图实现的是将这个现有的策略json合并或附加到一个新语句中。有什么办法可以做到这一点吗 有人有管理跨帐户s3 bucket策略并动态更新策略以允许从子帐户中的角色访问

我目前在一个中央帐户中有一个集中的S3存储桶,可通过多个其他子帐户访问。我希望通过采用现有IAM bucket策略,动态更新每个子帐户的bucket策略,并附加一条新语句,允许调用帐户的IAM角色访问bucket

我尝试将aws_iam_policy_文档和source_json与新语句结合使用。但是,所有这些都会覆盖现有语句

我试图实现的是将这个现有的策略json合并或附加到一个新语句中。有什么办法可以做到这一点吗


有人有管理跨帐户s3 bucket策略并动态更新策略以允许从子帐户中的角色访问的工作示例吗?

我也有类似的情况,我的解决方法很复杂,涉及外部脚本和空资源。在我的情况下,我使用了多个terraform工作区,每个工作区都有自己的cloudfront分布,但所有工作区都使用S3存储桶作为其中一个源。对于每个工作区,我需要将工作区的cloudfront源访问标识附加到bucket的策略中,而不替换或销毁该策略中已经存在的条目

bucket是手动创建的(在terraform之外),并作为数据资源导入

我有3个外部脚本(虽然它可能是一个更复杂的脚本)-一个用于创建具有新标识的策略,一个用于创建不带标识的策略(用于
destroy
),另一个用于实际应用创建的策略(由null资源使用,直接调用
aws
命令)

附加_bucket_policy.sh

#!/bin/bash

set -eo pipefail

# To be called as an external data resource program by terraform
# Usage: append_bucket_policy.sh <bucket name> <principal to append>
#
# Retrieves the current principals in bucket policy for <bucket name>, appends <principal to append>, uniqs the output to remove any duplicates, concats the principals into a comma seperated string, and outputs a json blob that terraform can understand
# In terraform, the variable is split on commas to create a list, which is used in the "identifiers" of an iam policy document resource, and re-applied to the bucket

IFS='
'

# this likely won't work with more complex bucket policies, but it does the job for cloudfront origin access identities
CURRENT=$(aws --region us-west-2 s3api get-bucket-policy --bucket "${1}" | jq --raw-output '.Policy' | jq '.Statement[].Principal.AWS[]')

TEMP=$(for i in ${CURRENT} ; do
  printf "%s\n" "${i},"
done
printf "\"%s\"" "${2},")

NEW=$(echo "${TEMP}" | sort | uniq | tr -d '\n')

jq -n --arg principals "${NEW}" '.principals = $principals' | sed 's/\\\"//g'

#!/bin/bash

set -eo pipefail

IFS='
'

CURRENT=$(aws --region us-west-2 s3api get-bucket-policy --bucket "${1}" | jq --raw-output '.Policy' | jq '.Statement[].Principal.AWS[]')

TEMP=$(for i in ${CURRENT} ; do
  printf "%s\n" "${i},"
done | egrep -v "${2}")

NEW=$(echo "${TEMP}" | sort | uniq | tr -d '\n')

jq -n --arg principals "${NEW}" '.principals = $principals' | sed 's/\\\"//g'

#!/bin/bash

# apply bucket policy generated by append_bucket_policy.sh

set -eo pipefail

# may fail to apply if the origin access identity was just created, wait a few seconds
sleep 10

RESULT=$(aws --region us-west-2 s3api put-bucket-policy --bucket "${1}" --policy "${2}")

jq -n --arg result "${RESULT}" '.result = $result' | sed 's/\\\"//g'

应用_bucket_policy.sh

#!/bin/bash

set -eo pipefail

# To be called as an external data resource program by terraform
# Usage: append_bucket_policy.sh <bucket name> <principal to append>
#
# Retrieves the current principals in bucket policy for <bucket name>, appends <principal to append>, uniqs the output to remove any duplicates, concats the principals into a comma seperated string, and outputs a json blob that terraform can understand
# In terraform, the variable is split on commas to create a list, which is used in the "identifiers" of an iam policy document resource, and re-applied to the bucket

IFS='
'

# this likely won't work with more complex bucket policies, but it does the job for cloudfront origin access identities
CURRENT=$(aws --region us-west-2 s3api get-bucket-policy --bucket "${1}" | jq --raw-output '.Policy' | jq '.Statement[].Principal.AWS[]')

TEMP=$(for i in ${CURRENT} ; do
  printf "%s\n" "${i},"
done
printf "\"%s\"" "${2},")

NEW=$(echo "${TEMP}" | sort | uniq | tr -d '\n')

jq -n --arg principals "${NEW}" '.principals = $principals' | sed 's/\\\"//g'

#!/bin/bash

set -eo pipefail

IFS='
'

CURRENT=$(aws --region us-west-2 s3api get-bucket-policy --bucket "${1}" | jq --raw-output '.Policy' | jq '.Statement[].Principal.AWS[]')

TEMP=$(for i in ${CURRENT} ; do
  printf "%s\n" "${i},"
done | egrep -v "${2}")

NEW=$(echo "${TEMP}" | sort | uniq | tr -d '\n')

jq -n --arg principals "${NEW}" '.principals = $principals' | sed 's/\\\"//g'

#!/bin/bash

# apply bucket policy generated by append_bucket_policy.sh

set -eo pipefail

# may fail to apply if the origin access identity was just created, wait a few seconds
sleep 10

RESULT=$(aws --region us-west-2 s3api put-bucket-policy --bucket "${1}" --policy "${2}")

jq -n --arg result "${RESULT}" '.result = $result' | sed 's/\\\"//g'


很抱歉,这太复杂了,可能不是100%合适,但它在过去对我很有效,可能会激发你的一些想法。我也欢迎有更好的方法来做这件事

我也遇到过类似的情况,我的解决方法很复杂,涉及到外部脚本和空资源。在我的情况下,我使用了多个terraform工作区,每个工作区都有自己的cloudfront分布,但所有工作区都使用S3存储桶作为其中一个源。对于每个工作区,我需要将工作区的cloudfront源访问标识附加到bucket的策略中,而不替换或销毁该策略中已经存在的条目

bucket是手动创建的(在terraform之外),并作为数据资源导入

我有3个外部脚本(虽然它可能是一个更复杂的脚本)-一个用于创建具有新标识的策略,一个用于创建不带标识的策略(用于
destroy
),另一个用于实际应用创建的策略(由null资源使用,直接调用
aws
命令)

附加_bucket_policy.sh

#!/bin/bash

set -eo pipefail

# To be called as an external data resource program by terraform
# Usage: append_bucket_policy.sh <bucket name> <principal to append>
#
# Retrieves the current principals in bucket policy for <bucket name>, appends <principal to append>, uniqs the output to remove any duplicates, concats the principals into a comma seperated string, and outputs a json blob that terraform can understand
# In terraform, the variable is split on commas to create a list, which is used in the "identifiers" of an iam policy document resource, and re-applied to the bucket

IFS='
'

# this likely won't work with more complex bucket policies, but it does the job for cloudfront origin access identities
CURRENT=$(aws --region us-west-2 s3api get-bucket-policy --bucket "${1}" | jq --raw-output '.Policy' | jq '.Statement[].Principal.AWS[]')

TEMP=$(for i in ${CURRENT} ; do
  printf "%s\n" "${i},"
done
printf "\"%s\"" "${2},")

NEW=$(echo "${TEMP}" | sort | uniq | tr -d '\n')

jq -n --arg principals "${NEW}" '.principals = $principals' | sed 's/\\\"//g'

#!/bin/bash

set -eo pipefail

IFS='
'

CURRENT=$(aws --region us-west-2 s3api get-bucket-policy --bucket "${1}" | jq --raw-output '.Policy' | jq '.Statement[].Principal.AWS[]')

TEMP=$(for i in ${CURRENT} ; do
  printf "%s\n" "${i},"
done | egrep -v "${2}")

NEW=$(echo "${TEMP}" | sort | uniq | tr -d '\n')

jq -n --arg principals "${NEW}" '.principals = $principals' | sed 's/\\\"//g'

#!/bin/bash

# apply bucket policy generated by append_bucket_policy.sh

set -eo pipefail

# may fail to apply if the origin access identity was just created, wait a few seconds
sleep 10

RESULT=$(aws --region us-west-2 s3api put-bucket-policy --bucket "${1}" --policy "${2}")

jq -n --arg result "${RESULT}" '.result = $result' | sed 's/\\\"//g'

应用_bucket_policy.sh

#!/bin/bash

set -eo pipefail

# To be called as an external data resource program by terraform
# Usage: append_bucket_policy.sh <bucket name> <principal to append>
#
# Retrieves the current principals in bucket policy for <bucket name>, appends <principal to append>, uniqs the output to remove any duplicates, concats the principals into a comma seperated string, and outputs a json blob that terraform can understand
# In terraform, the variable is split on commas to create a list, which is used in the "identifiers" of an iam policy document resource, and re-applied to the bucket

IFS='
'

# this likely won't work with more complex bucket policies, but it does the job for cloudfront origin access identities
CURRENT=$(aws --region us-west-2 s3api get-bucket-policy --bucket "${1}" | jq --raw-output '.Policy' | jq '.Statement[].Principal.AWS[]')

TEMP=$(for i in ${CURRENT} ; do
  printf "%s\n" "${i},"
done
printf "\"%s\"" "${2},")

NEW=$(echo "${TEMP}" | sort | uniq | tr -d '\n')

jq -n --arg principals "${NEW}" '.principals = $principals' | sed 's/\\\"//g'

#!/bin/bash

set -eo pipefail

IFS='
'

CURRENT=$(aws --region us-west-2 s3api get-bucket-policy --bucket "${1}" | jq --raw-output '.Policy' | jq '.Statement[].Principal.AWS[]')

TEMP=$(for i in ${CURRENT} ; do
  printf "%s\n" "${i},"
done | egrep -v "${2}")

NEW=$(echo "${TEMP}" | sort | uniq | tr -d '\n')

jq -n --arg principals "${NEW}" '.principals = $principals' | sed 's/\\\"//g'

#!/bin/bash

# apply bucket policy generated by append_bucket_policy.sh

set -eo pipefail

# may fail to apply if the origin access identity was just created, wait a few seconds
sleep 10

RESULT=$(aws --region us-west-2 s3api put-bucket-policy --bucket "${1}" --policy "${2}")

jq -n --arg result "${RESULT}" '.result = $result' | sed 's/\\\"//g'


很抱歉,这太复杂了,可能不是100%合适,但它在过去对我很有效,可能会激发你的一些想法。我也欢迎有更好的方法来做这件事

aws_iam_policy_文档数据源的
source_json
参数通过使用语句id(“sid”)值合并策略语句来工作,因此,为了使来自先前JSON的语句出现在结果中,新语句中的
sid
参数必须与源文档中的参数不同

另一个选择是在Terraform语言本身中更手动地进行转换。这需要直接使用原始语句数据结构,因此您有责任确保稳健地处理输入并生成有效的IAM策略数据结构

例如:

locals {
  policy_a = jsondecode(file("${path.module}/policy_a.json"))
  policy_b = jsondecode(file("${path.module}/policy_b.json"))
  policy_c = {
    Version: local.policy_a.Version,
    Statement: concat(
      local.policy_a.Statement,
      local.policy_b.Statement,
    ),
  }
}
然后,您可以使用
jsonecode(local.policy_c)
在模块中的其他地方生成JSON版本的
policy_c


因为这使用的是
concat
,所以结果实际上是两个语句列表连接在一起,因此,您需要自己确保结果是合理的:语句id或任何类似的规范化不会自动重写。

aws_iam_policy_文档数据源的
source\u json
参数使用语句id(“sid”)值合并策略语句,因此,为了使来自先前JSON的语句出现在结果中,新语句中的
sid
参数必须与源文档中的参数不同

另一个选择是在Terraform语言本身中更手动地进行转换。这需要直接使用原始语句数据结构,因此您有责任确保稳健地处理输入并生成有效的IAM策略数据结构

例如:

locals {
  policy_a = jsondecode(file("${path.module}/policy_a.json"))
  policy_b = jsondecode(file("${path.module}/policy_b.json"))
  policy_c = {
    Version: local.policy_a.Version,
    Statement: concat(
      local.policy_a.Statement,
      local.policy_b.Statement,
    ),
  }
}
然后,您可以使用
jsonecode(local.policy_c)
在模块中的其他地方生成JSON版本的
policy_c


因为这是使用
concat
,结果实际上是两个语句列表连接在一起,所以您自己需要确保结果是合理的:不会被语句id或任何类似的规范化自动覆盖。

我不确定您是否可以使用terraform做到这一点。最好是标记您的bucket,并使用Lambda函数来发现bucket,并使用boto3更新策略。我不确定您是否可以使用terraform来做到这一点。最好标记您的bucket并使用Lambda函数来发现bucket,并使用boto3更新策略