Lambda S3 getObject(从Ajax调用触发)抛出403拒绝

时间:2019-10-31 05:41:26

标签: node.js amazon-s3 aws-lambda

我有一个lambda函数,该函数从一个存储桶中获取图像,调整其大小并将其放入另一个存储桶中。 lambda函数设置为在创建源存储桶时触发。相当标准的教程级内容。

当我使用aws Web UI将图像放入源存储桶时,一切都会按预期进行。

但是,当我从Web应用程序中使用xhr将图像放入同一存储桶时,出现以下错误(从s3.getObject调用抛出):

AccessDenied: Access Denied
at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/services/s3.js:585:35

经过广泛搜索,大多数人都说403错误通常归结为lambda函数的角色/策略权限。但是,当我拖曳日志时,我看到的xhr上传和aws Web UI上传之间的唯一区别是eventName和userIdentity。

对于Web UI上传,它是Put和PrincipalId:

eventName: 'ObjectCreated:Put',
userIdentity: { principalId: 'AWS:AIDAJ2VMZPNX5NJD2VBLM' }

但是在xhr上称为Post and Anonymous:

eventName: 'ObjectCreated:Post',
userIdentity: { principalId: 'Anonymous' }

我的Lambda角色附加了两个策略:

AWSLambdaExecute

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:*"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::*"
        }
    ]
}

AWSLambdaBasicExecutionRole

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        }
    ]
}

我的S3存储桶具有以下策略:

源存储桶:

{
    "Version": "2012-10-17",
    "Id": "Lambda access bucket policy",
    "Statement": [
        {
            "Sid": "All on objects in bucket lambda",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::source-bucket-name/*"
        },
        {
            "Sid": "All on bucket by lambda",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::source-bucket-name"
        }
    ]
}

目标存储桶:

{
    "Version": "2012-10-17",
    "Id": "Lambda access bucket policy",
    "Statement": [
        {
            "Sid": "All on objects in bucket lambda",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::destination-bucket-name/*"
        },
        {
            "Sid": "All on bucket by lambda",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::destination-bucket-name"
        }
    ]
}

我是否需要以某种方式将主体ID传递(或分配)给我的xhr调用才能使其正常工作?还是我需要向我的函数添加权限/策略/角色以使其在没有附加触发器的主体ID的情况下触发该函数?

编辑: 这是将POST文件发送到源存储桶的JS代码:

function uploadFileAttachment(attachment, form) {

  var formButtons = document.querySelectorAll("form.form--trix button.btn");

  formButtons.forEach((button) => {
    button.setAttribute("disabled", "disabled");
  });

  uploadFile(attachment.file, setProgress, setAttributes)

  function setProgress(progress) {
    attachment.setUploadProgress(progress)
  }

  function setAttributes(attributes) {

    attachment.setAttributes(attributes)

    formButtons.forEach((button) => {
      button.removeAttribute("disabled");
    });

  }
}

function uploadFile(file, progressCallback, successCallback) {

  var key = createStorageKey(file)
  var formData = createFormData(key, file)
  var xhr = new XMLHttpRequest()

  xhr.open("POST", global.s3url, true)

  xhr.upload.addEventListener("progress", function(event) {
    var progress = event.loaded / event.total * 100
    progressCallback(progress)
  })

  xhr.addEventListener("load", function(event) {
    if (xhr.status == 204) {
      var attributes = {
        url: global.s3url + key,
        href: global.s3url + key + "?content-disposition=attachment"
      }
      successCallback(attributes)
    }
  })

  xhr.send(formData);
}

function createStorageKey(file) {
  var date = new Date()
  var day = date.toISOString().slice(0,10)
  var name = date.getTime() + "-" + file.name
  return [ "trix", day, name ].join("/")
}

function createFormData(key, file) {
  var data = new FormData()
  data.append("key", key)
  data.append("Content-Type", file.type)
  data.append("file", file)
  return data
}

0 个答案:

没有答案