使用Lambda、API Gateway和IAM Policy无法从DynamoDB返回正确值
问题分析与修复方案
核心问题诊断
你的502错误大概率是IAM权限策略配置错误+Lambda代码中ProjectionExpression处理不当共同导致的,具体原因如下:
- IAM策略中
ForAllValues:StringEquals用于单个分区键值的dynamodb:LeadingKeys是错误的,导致所有者身份的请求无法匹配权限规则 - 当
isOwner为true时,设置空字符串的ProjectionExpression会引发DynamoDB请求格式错误 - 若
IDP_REGEX正则无法正确提取Cognito的sub值,会导致isOwner判断错误,触发权限问题
修复步骤
1. 修正IAM权限策略
将Sid1中的ForAllValues:StringEquals改为StringEquals(LeadingKeys是单个值,无需多值匹配前缀):
{ "Version": "2012-10-17", "Statement": [ { "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:aws:logs:xxxxxxx/aws/lambda/test-production:log-stream:*", "Effect": "Allow" }, { "Sid": "1", "Effect": "Allow", "Action": [ "dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:UpdateItem", "dynamodb:DeleteItem" ], "Resource": "arn:aws:dynamodb:xxxxxxxxxxxxxxxxxxx/xxxxxxx", "Condition": { "StringEquals": { "dynamodb:LeadingKeys": "${cognito-identity.amazonaws.com:sub}" } } }, { "Sid": "2", "Effect": "Allow", "Action": [ "dynamodb:GetItem", "dynamodb:BatchGetItem", "dynamodb:Query" ], "Resource": "arn:aws:dynamodb:xxxxxxxxxxxxxxx/xxxxx", "Condition": { "ForAllValues:StringEquals": { "dynamodb:Attributes": [ "id", "firstName", "lastName" ] }, "StringEqualsIfExists": { "dynamodb:Select": "SPECIFIC_ATTRIBUTES" } } } ] }
2. 修正Lambda代码
- 移除空字符串的
ProjectionExpression,非所有者时才指定属性列表 - 修正Cognito用户ID提取逻辑,确保正则能正确匹配
sub值:
// 标准Cognito sub提取正则 const IDP_REGEX = /CognitoSignIn:(.*)$/; app.get("/user/:id", async function (req, res) { const partitionKey = req.params.id; let userId = null; const authProvider = req.apiGateway.event.requestContext.identity.cognitoAuthenticationProvider; if (authProvider) { const matchResult = authProvider.match(IDP_REGEX); userId = matchResult ? matchResult[1] : null; } const isOwner = userId === partitionKey; // 仅非所有者时添加属性限制 const getItemParams = { TableName: tableName, Key: { id: partitionKey }, ...(!isOwner && { ProjectionExpression: "id, firstName, lastName" }) }; try { const data = await ddbDocClient.send(new GetCommand(getItemParams)); if (!data.Item) { res.statusCode = 404; return res.json({ error: "Item not found", url: req.url }); } res.json({ success: "get call succeed!", url: req.url, data: data.Item }); } catch (error) { console.error("GetItem error:", error); res.statusCode = error.name === "AccessDeniedException" ? 403 : 500; res.json({ error: error.message, errorType: error.name, url: req.url }); } });
3. 辅助排查动作
- 查看Lambda的CloudWatch日志,确认具体错误类型(如
AccessDeniedException) - 验证Cognito用户的
sub值与DynamoDB中id字段的一致性(注意大小写、特殊字符) - 确认API Gateway已正确配置Cognito授权,
requestContext.identity能正常获取cognitoAuthenticationProvider
内容的提问来源于stack exchange,提问作者user16257618
相关产品推荐
相关产品推荐

