当我的 Lambda 有权访问 S3 存储桶时,为什么我的 GetObjectRequest return 出现 403 Access Denied 错误?

Why does my GetObjectRequest return a 403 Access Denied error when my Lambda has access to the S3 bucket?

我有一个向 S3 存储桶发出 GetObject 请求的 Lambda 函数。

但是,我收到以下错误:

AccessDenied: Access Denied
    at deserializeAws_restXmlGetObjectCommandError (/node_modules/@aws-sdk/client-s3/dist-cjs/protocols/Aws_restXml.js:6284:41)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
    at /node_modules/@aws-sdk/middleware-serde/dist-cjs/deserializerMiddleware.js:6:20
    at /node_modules/@aws-sdk/middleware-signing/dist-cjs/middleware.js:11:20
    at StandardRetryStrategy.retry (/node_modules/@aws-sdk/middleware-retry/dist-cjs/StandardRetryStrategy.js:51:46)
    at /node_modules/@aws-sdk/middleware-logger/dist-cjs/loggerMiddleware.js:6:22
    at GetS3Data (/src/input.ts:21:26)
    at Main (/src/main.ts:8:34)
    at Runtime.run [as handler] (/handler.ts:6:9) {
  Code: 'AccessDenied',
  RequestId: '3K61PMQGW4825D3W',
  HostId: '5PpmWpu2I4WZPx37Y0pRfDAcdCmjX8fchuE+HLpUzy7uqoJirtb9Os0g96kWfluM/ctkn/mEC5o=',
  '$fault': 'client',
  '$metadata': {
    httpStatusCode: 403,
    requestId: undefined,
    extendedRequestId: '5PpmWpu2I4WZPx37Y0pRfDAcdCmjX8fchuE+HLpUzy7uqoJirtb9Os0g96kWfluM/ctkn/mEC5o=',
    cfId: undefined,
    attempts: 1,
    totalRetryDelay: 0
  }
}

我已授予访问 Lambda 函数的权限以发出此请求。

有什么问题?

serverless.ts

import type { AWS } from "@serverless/typescript";

const serverlessConfiguration: AWS = {
    service: "affiliations",
    frameworkVersion: "2",
    custom: {
        esbuild: {
            bundle: true,
            minify: false,
            sourcemap: true,
            exclude: ["aws-sdk"],
            target: "node14",
            define: { "require.resolve": undefined },
            platform: "node",
        },
    },
    plugins: ["serverless-esbuild"],
    provider: {
        name: "aws",
        region: "us-east-2",
        runtime: "nodejs14.x",
        apiGateway: {
            minimumCompressionSize: 1024,
            shouldStartNameWithService: true,
        },
        environment: {
            AWS_NODEJS_CONNECTION_REUSE_ENABLED: "1",
            NODE_OPTIONS: "--enable-source-maps --stack-trace-limit=1000",
        },
        lambdaHashingVersion: "20201221",
        vpc: {
            securityGroupIds: ["<redacted>"],
            subnetIds: ["redacted>"],
        },
        iam: {
            role: {
                statements: [
                    {
                        Effect: "Allow",
                        Action: ["s3:GetObject"],
                        Resource: "<redacted>",
                    },
                ],
            },
        },
    },
    useDotenv: true,
    // import the function via paths
    functions: {
        run: {
            handler: "handler.run",
            timeout: 300,
            events: [
                {
                    sns: {
                        arn: "<redacted>",
                    },
                },
            ],
        },
    },
};

module.exports = serverlessConfiguration;

s3.ts

export const GetS3Data = async (payload: GetObjectRequest) => {
    try {
        const response = await S3Service.getObject(payload);

        const result = await new Promise((resolve, reject) => {
            const data = [];
            response.Body.on("data", (chunk) => data.push(chunk));
            response.Body.on("err", reject);
            response.Body.once("end", () => resolve(data.join("")));
        });

        return [result, null];
    } catch (err) {
        Logger.error({
            method: "GetS3Data",
            error: err.stack,
        });

        return [null, err];
    }
};

package.json

"@aws-sdk/client-s3": "^3.36.0",

您的 403 Access Denied 错误掩盖了 404 Not Found 错误,因为您的代码和无服务器配置看起来非常好并且应该按预期工作,前提是您已正确指定资源。


如果您没有正确的 s3:ListBucket 权限,如果指定键的对象不存在,S3 端点将不会 return 404 Not Found 错误。

GetObjectAPI reference 强调了这种细微差别:

If you have the s3:ListBucket permission on the bucket, Amazon S3 will return an HTTP status code 404 ("no such key") error.

If you don’t have the s3:ListBucket permission, Amazon S3 will return an HTTP status code 403 ("access denied") error.

这是为了防止攻击者枚举 public 个存储桶并了解存储桶中实际存在的对象。

在这种情况下,缺少 404 不允许泄露有关对象是否存在的信息(就像登录页面上的 Invalid Credentials 消息而不是 Invalid Password 表示存在具有所提供用户名的用户)。


向 Lambda 提供执行 s3:ListBucket 操作的权限以揭露 404 错误 and/or 最后仔细检查您的 GetObjectRequest 以确保正确指定密钥 存在的对象:

iam: {
    role: {
        statements: [
            {
                Effect: "Allow",
                Action: ["s3:GetObject", "s3:ListBucket"],
                Resource: "<redacted>",
            },
        ],
    },
}

忘记在资源末尾添加/*

Resource: "<redacted>/*",