如何正确设置 IAM 执行角色和存储桶策略以使 lambda 写入 public 读取 S3 存储桶?

How to properly setup an IAM execution role and a bucket policy for getting lambda writing to a public read S3 bucket?

对于上下文,我正在使用无服务器框架,所以发生了一些事情:

我得到以下 iamRoleStatements 部分:

- Effect: "Allow"
  Action:
    - "s3:ListBucket"
  Resource:
    - Fn::Join:
        - ""
        - - "arn:aws:s3:::"
          - Ref: StaticSiteBucket
- Effect: "Allow"
  Action:
    - "s3:GetObject"
    - "s3:PutObject"
    - "s3:DeleteObject"
    - "s3:GetObjectVersionTagging"
    - "s3:PutObjectVersionTagging"
  Resource:
    - Fn::Join:
        - ""
        - - "arn:aws:s3:::"
          - Ref: StaticSiteBucket
          - "/*"

我实际上可以确认它为生成的角色生成了以下策略:

        {
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::bucket-name-here"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject",
                "s3:GetObjectVersionTagging",
                "s3:PutObjectVersionTagging"
            ],
            "Resource": [
                "arn:aws:s3:::bucket-name-here/*"
            ],
            "Effect": "Allow"
        }

有了这个,我 运行 lambda 函数在那个桶上执行 putObject。得到一个'Access denied error',所以我想如果桶本身需要允许写入怎么办,所以我在桶策略中包含了一个写语句:

StaticSiteBucket:
  Type: AWS::S3::Bucket
  Properties:
    AccessControl: PublicRead
    BucketName: ${self:service}-static-site-${self:provider.stage}
    WebsiteConfiguration:
      IndexDocument: index.html
StaticSiteBucketPolicy:
  Type: AWS::S3::BucketPolicy
  Properties:
    Bucket:
      Ref: StaticSiteBucket
    PolicyDocument:
      Statement:
        - Sid: PublicReadGetObject
          Effect: Allow
          Principal: "*"
          Action:
          - s3:GetObject
          Resource:
            Fn::Join: [
              "", [
                "arn:aws:s3:::",
                {
                  "Ref": "StaticSiteBucket"
                },
                "/*"
              ]
            ]
        - Sid: AllowLambdaRoleWrite
          Effect: Allow
          Action:
            - "s3:GetObject"
            - "s3:PutObject"
            - "s3:DeleteObject"
            - "s3:GetObjectVersionTagging"
            - "s3:PutObjectVersionTagging"
          Principal:
            AWS:
              - Fn::GetAtt: [ IamRoleLambdaExecution, Arn ]
          Resource:
            Fn::Join:
              - ""
              - - "arn:aws:s3:::"
                - Ref: StaticSiteBucket
                - "/*"

在 S3 存储桶中生成以下策略:

{
    "Version": "2008-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::bucket-name-here/*"
        },
        {
            "Sid": "AllowLambdaRoleWrite",
            "Effect": "Allow",
            "Principal": {
                "AWS": "<role-arn>"
            },
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject",
                "s3:GetObjectVersionTagging",
                "s3:PutObjectVersionTagging"
            ],
            "Resource": "arn:aws:s3:::bucket-name-here/*"
        }
    ]
}

所以,我试过几句话:

我错过了什么?

需要考虑的一些想法:

  1. 策略中不需要委托人 (lambda.amazonaws.com)。委托人已经出现在无服务器创建的角色中(至少在默认情况下是这样)。很可能现在它可以工作了,因为你给了它所有的权限。
  2. 您可能需要 ListBucket。不是因为它是严格需要的,而是因为它可能掩盖了另一个问题。看到这个 excellent response。事实上,当你把没有星号的桶的名称放在资源部分时,可能是因为这个。
  3. 文件小吗?对于大文件,您可能会触发多部分,这也需要其他放置权限。
  4. 您是否要标记或放置额外的 ACL 权限或所有者?这也需要额外的权限。

因此,就我而言,我缺少的是:

  • 我必须包括 getObjectTaggingputObjectTagging 操作。

对于有类似问题的人。阅读下面的内容!

从课程中吸取教训(我花了一天半的时间坚持这一点)并意识到 Whosebug 是经验和知识的宝库。

我要指出:

  • 确定您的代码正在执行哪些 API 操作,然后转到文档并进行检查。一些操作act on buckets while other on objects
  • 在我的例子中,我可以在存储桶上删除任何额外的策略声明,换句话说,
  • 执行角色是获得权力的角色。
  • 我无法做到这一点,但如果有更明确的错误日志的方法,至少在 aws-sdk 节点的库中,将节省大量时间。 Stacktrace 还不够。欢迎提出建议。

这是我的 StaticSiteBucket 资源声明现在的样子:

- Effect: "Allow"
  Action:
    - "s3:ListBucket"
  Resource:
    - Fn::Join:
        - ""
        - - "arn:aws:s3:::"
          - Ref: StaticSiteBucket
- Effect: "Allow"
  Action:
    - "s3:GetObject"
    - "s3:PutObject"
    - "s3:DeleteObject"
    - "s3:GetObjectTagging"
    - "s3:PutObjectTagging"
  Resource:
    - Fn::Join:
        - ""
        - - "arn:aws:s3:::"
          - Ref: StaticSiteBucket
          - "/*"