You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Node.js的Lambda读取S3中CSV时遇Access Denied问题求助

问题排查:S3触发Lambda读取CSV时出现Access Denied错误

业务场景:CSV文件上传至AWS S3后,通过CloudTrail与EventBridge触发Lambda函数,Lambda需读取CSV并转换为JSON格式,但调用Lambda时返回Access Denied错误,无法读取S3中的文件。

相关代码与配置

App.js

const bucket= 'patterns-s3-eventbridge-src-bucket-new';//event['detail'].requestParameters.bucketName,
const objectkey= 'test.csv'
const params = { Bucket: bucket, Key: objectkey };
const results = [];

exports.handler = function (event, ctx, callback) {
    try {
        const file = s3.getObject(params).createReadStream();

        file
            .pipe(csv())
            .on('data', function (data) {
                results.push(data); // --> here
            })
            .on('end', () => {
                console.log(results);
                callback(null, results);
            });
    } catch (err) {
        console.log(err);
        callback(Error(err));
    }

};

CloudFormation模板 temp.yaml

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Description: S3-to-EventBridge Integration 1 - Simple Invoke

Parameters:
  SourceBucketName:
    Type: String
    Default: patterns-s3-eventbridge-src-bucket-new

  LoggingBucketName:
    Type: String
    Default: patterns-s3-eventbridge-ct-logs-new

Resources:
  # S3 Bucket - A source bucket and a logging bucket
  SourceBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref SourceBucketName

  LoggingBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref LoggingBucketName

  # Bucket policy enables CloudTrail to write to the logging bucket
  BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref LoggingBucket
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Sid: AWSCloudTrailAclCheck
            Effect: Allow
            Principal:
              Service: cloudtrail.amazonaws.com
            Action: s3:GetBucketAcl
            Resource: !GetAtt LoggingBucket.Arn
          - Sid: AWSCloudTrailWrite
            Effect: Allow
            Principal:
              Service: cloudtrail.amazonaws.com
            Action: s3:PutObject
            Resource: !Sub ${LoggingBucket.Arn}/AWSLogs/${AWS::AccountId}/*
            Condition:
              StringEquals:
                s3:x-amz-acl: bucket-owner-full-control

  # The CloudTrail trail - uses the LoggingBucketName as the trail name
  myTrail:
    Type: AWS::CloudTrail::Trail
    DependsOn: BucketPolicy
    Properties:
      TrailName: !Ref LoggingBucketName
      S3BucketName: !Ref LoggingBucket
      IsLogging: true
      IsMultiRegionTrail: false
      EventSelectors:
        - IncludeManagementEvents: false
          DataResources:
            - Type: AWS::S3::Object
              Values:
                - !Sub ${SourceBucket.Arn}/
      IncludeGlobalServiceEvents: false

  ### This section configures the consuming Lambda function ###

  # Lambda function
  EventConsumerFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: eventConsumer/
      Handler: app.handler
      Runtime: nodejs14.x

  # EventBridge rule - invokes EventConsumerFunction 
  EventRule:
    Type: AWS::Events::Rule
    Properties:
      Description: EventRule
      State: ENABLED
      EventPattern:
        source:
          - aws.s3
        detail:
          eventName:
            - PutObject
          requestParameters:
            bucketName:
              - !Ref SourceBucket
      Targets:
        - Arn: !GetAtt EventConsumerFunction.Arn
          Id: EventConsumerFunctionTarget

  PermissionForEventsToInvokeLambda:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref EventConsumerFunction
      Action: lambda:InvokeFunction
      Principal: events.amazonaws.com
      SourceArn: !GetAtt EventRule.Arn

错误日志

2022-11-20T11:10:04.221Z    3393a03e-c793-42a1-b4f2-eaee4365e6a8    ERROR   Uncaught Exception  
{
    "errorType": "AccessDenied",
    "errorMessage": "Access Denied",
    "code": "AccessDenied",
    "message": "Access Denied",
    "region": null,
    "time": "2022-11-20T11:10:04.220Z",
    "requestId": "G9BZX6PSC8XZ5NVC",
    "extendedRequestId": "Wpet8ECVvRWEJu25NV8DYM7kYlKgGFCxhuCwg9tojnTd24LfFtBCzSdO953f3HBwmBWaVEDk4WQ=",
    "statusCode": 403,
    "retryable": false,
    "retryDelay": 72.92149207351702,
    "stack": [
        "AccessDenied: Access Denied",
        "    at Request.extractError (/var/task/node_modules/aws-sdk/lib/services/s3.js:711:35)",
        "    at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:106:20)",
        "    at Request.emit (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:78:10)",
        "    at Request.emit (/var/task/node_modules/aws-sdk/lib/request.js:686:14)",
        "    at Request.transition (/var/task/node_modules/aws-sdk/lib/request.js:22:10)",
        "    at AcceptorStateMachine.runTo (/var/task/node_modules/aws-sdk/lib/state_machine.js:14:12)",
        "    at /var/task/node_modules/aws-sdk/lib/state_machine.js:26:10)",
        "    at Request.<anonymous> (/var/task/node_modules/aws-sdk/lib/request.js:38:9)",
        "    at Request.<anonymous> (/var/task/node_modules/aws-sdk/lib/request.js:688:12)",
        "    at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:116:18)"
    ]
}

问题分析与修复方案

核心原因

Lambda函数的执行角色缺少读取目标S3桶对象的IAM权限,Lambda默认没有S3访问权限,这是触发403错误的直接原因。

修复步骤

  1. 给Lambda添加S3读取权限
    在CloudFormation模板的EventConsumerFunction资源中,添加Policies配置,授予读取SourceBucket的权限:
EventConsumerFunction:
  Type: AWS::Serverless::Function
  Properties:
    CodeUri: eventConsumer/
    Handler: app.handler
    Runtime: nodejs14.x
    # 添加以下权限配置
    Policies:
      - S3ReadPolicy:
          BucketName: !Ref SourceBucketName

或者使用更精细化的自定义权限:

Policies:
  - Statement:
      - Effect: Allow
        Action: s3:GetObject
        Resource: !Sub ${SourceBucket.Arn}/*
  1. 优化App.js的硬编码问题
    当前代码中桶名和对象键是固定值,建议从EventBridge传递的事件中动态获取,避免后续资源变更时出错:
const AWS = require('aws-sdk');
const s3 = new AWS.S3();
const csv = require('csv-parser'); // 确保已安装该依赖
const results = [];

exports.handler = function (event, ctx, callback) {
    try {
        // 从EventBridge事件中动态获取桶名和对象键
        const bucket = event.detail.requestParameters.bucketName;
        const objectkey = event.detail.requestParameters.key;
        const params = { Bucket: bucket, Key: objectkey };

        const file = s3.getObject(params).createReadStream();

        file
            .pipe(csv())
            .on('data', function (data) {
                results.push(data);
            })
            .on('end', () => {
                console.log(results);
                callback(null, results);
            });
    } catch (err) {
        console.log(err);
        callback(Error(err));
    }
};

注意:需确保Lambda代码已安装aws-sdk和csv-parser依赖,部署时可包含node_modules或通过Lambda层添加依赖。

  1. 附加排查点
  • 检查SourceBucket是否存在自定义桶策略,若有需确保允许Lambda执行角色的s3:GetObject操作;
  • 确认CloudTrail已正常生成日志到LoggingBucket,可查看桶内是否有AWSLogs目录;
  • 验证EventBridge规则的事件匹配逻辑,当前配置已正确匹配目标桶的PutObject事件,无需修改。

内容的提问来源于stack exchange,提问作者Van

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 07:20:29