【问题标题】:Why does S3 bucket created in terraform needs bucket policy to grant access to lambda为什么在 terraform 中创建的 S3 存储桶需要存储桶策略来授予对 lambda 的访问权限
【发布时间】:2020-08-21 22:42:36
【问题描述】:

我们结合使用云形成和 terraform,其中一些常见资源(如 DynamoDB、S3)是使用 terraform 创建的,而其他资源(如 APIGateway)则使用无服务器和 cloudformation 创建。所有资源都在同一个 AWS 账户中

我在 terraform 中有一个 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 时,它会引发 AccessDenied 错误,除非我添加存储桶策略来授予对 lambda 角色的访问权限

resource "aws_s3_bucket_policy" "payment_service_s3_bucket_policy" { 
..
..
}

当 s3 存储桶和 lambda 函数和角色在同一个账户时,为什么我需要添加 S3 存储桶策略?我错过了什么吗?

另外,如果我使用 AWS::S3::Bucket 创建存储桶作为 Apigateway 所在的云形成堆栈的一部分(我们使用的是无服务器),我不需要添加存储桶策略并且一切正常。

【问题讨论】:

  • S3 存储桶 ARN 中没有账户 ID 或区域。使用arn:aws:s3:::mybucket/myprefix/*
  • 谢谢!这解决了问题。

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


【解决方案1】:

我认为问题仅仅是 S3 存储桶 ARN 不正确。

S3 存储桶 ARN 中没有账户 ID 或区域。使用arn:aws:s3:::mybucket/myprefix/*

【讨论】:

    【解决方案2】:

    答案取决于应用 terraform 计划的 AWS IAM 角色,因为 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
    }
    

    【讨论】:

      【解决方案3】:

      这是一个开放的错误。 acl 和 force_destroy 不能很好地使用 terraform import 导入:https://github.com/hashicorp/terraform-provider-aws/issues/6193

      【讨论】:

        猜你喜欢
        • 2022-01-17
        • 2012-12-16
        • 2022-11-03
        • 1970-01-01
        • 2016-09-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多