我有一个简单的 Lambda 函数,当文件上传到 S3 时,它应该调用 Textract。但是,当我从桌面运行 Lambda 函数时,对 Textract 的调用可以正常工作,而当我从 Lambda 环境运行完全相同的代码时,对 Textract 的调用就不起作用。
这是 Lambda 代码:
import os
import boto3
TEXTRACT_CLIENT = boto3.client('textract', region_name=os.environ['REGION'])
def lambda_handler(event, context):
event_source = event['Records'][0]['s3']
textract_ticket = TEXTRACT_CLIENT.start_document_analysis(
DocumentLocation={
'S3Object': {
'Bucket': os.environ['REQUESTS_BUCKET'],
'Name': event_source['object']['key']
}
},
FeatureTypes=["TABLES", "FORMS"],
NotificationChannel={
'RoleArn': os.environ['TEXTRACT_ROLE_ARN'],
'SNSTopicArn': os.environ['SNS_TOPIC_ARN']
},
OutputConfig={
'S3Bucket': os.environ['RESULTS_BUCKET']
}
)
return {
'statusCode': 200,
'JobId': textract_ticket['JobId']
}
代码没有什么特别的。我在 Lambda 环境和本地计算机中对所有环境变量使用完全相同的值。在这两种情况下,我都使用相同的事件,指向相同的 S3 对象:
{
"Records": [
{
"eventVersion": "2.0",
"eventSource": "aws:s3",
"awsRegion": "us-east-1",
"eventTime": "1970-01-01T00:00:00.000Z",
"eventName": "ObjectCreated:Put",
"userIdentity": {
"principalId": "EXAMPLE"
},
"requestParameters": {
"sourceIPAddress": "127.0.0.1"
},
"responseElements": {
"x-amz-request-id": "EXAMPLE123456789",
"x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
},
"s3": {
"s3SchemaVersion": "1.0",
"configurationId": "testConfigRule",
"bucket": {
"name": "my-bucket",
"ownerIdentity": {
"principalId": "EXAMPLE"
},
"arn": "arn:aws:s3:::example-bucket"
},
"object": {
"key": "35264254-7aa6-4f24-815a-f73e1671f151.pdf",
"size": 1024,
"eTag": "0123456789abcdef0123456789abcdef",
"sequencer": "0A1B2C3D4E5F678901"
}
}
}
]
}
奇怪的是,当从我的桌面调用时,所有这些都会成功执行,但是当我从 Lambda 运行时,我得到:
{
"errorMessage": "An error occurred (InvalidS3ObjectException) when calling the StartDocumentAnalysis operation: Unable to get object metadata from S3. Check object key, region and/or access permissions.",
"errorType": "InvalidS3ObjectException",
"stackTrace": [
" File \"/var/task/lambda_function.py\", line 10, in lambda_handler\n textract_ticket = TEXTRACT_CLIENT.start_document_analysis(\n",
" File \"/var/runtime/botocore/client.py\", line 386, in _api_call\n return self._make_api_call(operation_name, kwargs)\n",
" File \"/var/runtime/botocore/client.py\", line 705, in _make_api_call\n raise error_class(parsed_response, operation_name)\n"
]
}
我在这里遗漏了什么吗?我不知道 Lambda 环境中可能出现什么问题。
@Ronan Cunningham 和 @stijndepestel 的直觉都是正确的。
我对角色感到困惑。此示例涉及两个角色:Lambda 角色和 Textract 运行所在的角色。我错误地认为 Textract 角色用于其完整执行(Textract 角色具有完整的 S3 访问权限),但它仅用于发送 SNS 通知。但实际上 textract 在分配给 Lambda 的相同角色下运行,而 Lambda 没有 S3 访问权限。为 Lambda 角色添加 S3 访问权限后,一切按预期运行。
谢谢大家!
提醒其他遇到此错误的人。 OP 是正确的,需要设置的是 Lambda 权限,而不是角色的权限,角色只需要 SNS 权限(不是其他 google 结果错误指出的 SQS)。如果您根本没有设置权限并且只有读取权限,AWS 会给出 2 个不同的错误。
如果 Lambda 缺乏读取权限,它将输出一个错误,提示“检查权限/对象”,如果它具有读取权限,它将输出 500 错误并显示不同的消息。
当
s3:GetObject
设置为 s3:PutObject
时,Lambda 需要 OutputConfig
和 StartDocumentTextDetectionCommand
。
- Effect: Allow
Action:
- s3:GetObject
- s3:PutObject
Resource:
- arn:aws:s3:::<bucket_name>*
texttract 命令需要仅具有
sns:Publish
权限的角色:
- PolicyName: MyPolicyName
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: sns:Publish
Resource: !Ref <MySNSTopic>
只是为了通过稍微扩展答案来节省其他人的时间。