我们使用云形成和地形的组合,其中一些公共资源(例如DynamoDB,S3)是使用terraform创建的,而其他资源(例如APIGateway)是使用无服务器和cloudformation来创建的。所有资源都在同一个AWS账户中
我有一个S3铲斗
resource "aws_s3_bucket" "payment_bucket" {
bucket = "payment-bucket-${var.env_name}"
acl = "private"
tags = merge(
module.tags.base_tags,
{
"Name" = "payment-bucket-${var.env_name}"
}
)
lifecycle {
ignore_changes = [tags]
}
}
这会在我运行tf-apply时在我的AWS账户中创建一个私有存储区payment-bucket-dev
我们在使用无服务器创建的同一AWS账户中有一个APIGateway,其中一个lambda需要访问该存储桶,因此我为lambda函数创建了IAM角色以授予访问存储桶的权限。
makePayment:
name: makePayment-${self:provider.stage}
handler: src/handler/makePayment.default
events:
- http:
path: /payment
method: post
private: true
cors: true
iamRoleStatementsName: ${self:service}-${self:provider.stage}-makePayment-role
iamRoleStatements:
- Effect: Allow
Action:
- s3:PutObject
Resource:
- arn:aws:s3:::#{AWS::Region}:#{AWS::AccountId}:payment-bucket-${self:provider.stage}/capture/batch/*
但是当我运行此lambda make-payment-dev
时,除非我添加了存储桶策略以授予对lambda角色的访问权限,否则它将引发AccessDenied错误
resource "aws_s3_bucket_policy" "payment_service_s3_bucket_policy" {
..
..
}
当s3存储桶以及lambda函数和角色都在同一帐户中时,为什么需要添加S3存储桶策略?我想念什么吗?
此外,如果我使用AWS::S3::Bucket
作为Apigateway所在的云形成堆栈的一部分创建了存储桶(我们正在使用无服务器),则不需要添加存储桶策略,并且一切正常。
答案 0 :(得分:1)
我认为问题很简单,就是S3存储桶ARN不正确。
S3存储桶ARN中没有帐户ID或区域。使用arn:aws:s3:::mybucket/myprefix/*
。
答案 1 :(得分:0)
答案取决于AWS IAM角色正在应用terraform计划,因为AWS s3存储桶罐头ACL规则:“私有”将存储桶访问限制为:所有者获得FULL_CONTROL。没有其他人具有访问权限(默认)。每个文档:https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html
在这一点上,您必须相对明确地指出谁可以访问存储桶。通常,如果我要使用私有ACL,但是希望我的AWS账户中的所有其他角色都可以访问存储桶,则将存储桶策略附加到terraform aws_s3_bucket资源中,以首先允许访问存储桶。然后,我通过另一个内联策略明确授予lambda角色访问所述存储桶的权限。
对于您来说,它看起来像这样:
// Allow access to the bucket
data "aws_iam_policy_document" "bucket_policy" {
statement {
sid = "S3 bucket policy for account access"
actions = [
"s3:ListBucket",
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
]
principals {
type = "AWS"
identifiers = [
"arn:aws:iam::{your_account_id_here}:root",
]
}
resources = [
"arn:aws:s3:::test_bucket_name",
"arn:aws:s3:::test_bucket_name/*",
]
condition {
test = "StringEquals"
variable = "aws:PrincipalArn"
values = ["arn:aws:iam::{your_account_id_here}:role/*"]
}
}
}
resource "aws_s3_bucket" "this" {
bucket = "test_bucket_name"
acl = "private"
policy = data.aws_iam_policy_document.bucket_policy.json
}
// Grant the lambda IAM role permissions to the bucket
data "aws_iam_policy_document" "grant_bucket_access" {
statement {
sid = "AccessToTheAppAuxFilesBucket"
actions = [
"s3:ListBucket",
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
]
resources = [
"arn:aws:s3:::test_bucket_name/*",
"arn:aws:s3:::test_bucket_name"
]
}
}
// Data call to pull the arn of the lambda's IAM Role
data "aws_iam_role" "cloudformation_provisioned_role" {
name = "the_name_of_the_lambdas_iam_role"
}
resource "aws_iam_role_policy" "iam_role_inline_policy" {
name = "s3_bucket_access"
role = data.aws_iam_role.cloudformation_provisioned_role.arn
policy = data.aws_iam_policy_document.grant_bucket_access.json
}
答案 2 :(得分:0)
这是一个开放的错误。 acl 和 force_destroy 不能很好地与 terraform import
一起导入:https://github.com/hashicorp/terraform-provider-aws/issues/6193