为什么在terraform中创建的S3存储桶需要存储桶策略来授予对lambda的访问权限

时间:2020-05-06 19:55:49

标签: amazon-web-services amazon-s3 aws-lambda terraform aws-api-gateway

我们使用云形成和地形的组合,其中一些公共资源(例如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所在的云形成堆栈的一部分创建了存储桶(我们正在使用无服务器),则不需要添加存储桶策略,并且一切正常。

3 个答案:

答案 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