AWS CDK配置问题:Lambda无DynamoDB PutItem权限
解决Lambda写入DynamoDB的AccessDeniedException问题
问题描述
尝试构建一个可向DynamoDB写入数据的Lambda函数,该函数通过API Gateway访问并由Cognito用户池保护,但每次写入数据时都会抛出AccessDeniedException,提示Lambda角色无dynamodb:PutItem权限。曾尝试通过iam.PolicyStatement添加权限但未成功。
错误信息
An error occurred (AccessDeniedException) when calling the PutItem operation: User: arn:aws:sts::{account-id}:assumed-role/SoccerTipGameInfrastructu-fastApiLambdaServiceRole-121EKY67BICBU/SoccerTipGameInfrastructureS-fastApiLambda1F147E7F-Zvo7rWg8oFGY is not authorized to perform: dynamodb:PutItem on resource: arn:aws:dynamodb:eu-central-1:{account-id}:table/teams because no identity-based policy allows the dynamodb:PutItem action
现有CDK代码
import * as cdk from 'aws-cdk-lib'; import { Construct } from 'constructs'; import * as lambda from 'aws-cdk-lib/aws-lambda'; import * as apiGateway from 'aws-cdk-lib/aws-apigateway'; import * as ddb from 'aws-cdk-lib/aws-dynamodb'; import * as cog from 'aws-cdk-lib/aws-cognito' import { BillingMode } from 'aws-cdk-lib/aws-dynamodb'; import { table } from 'console'; import * as cognito from 'aws-cdk-lib/aws-cognito'; import * as iam from 'aws-cdk-lib/aws-iam' export class AppInfrastructureStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // Cognito Userpool const userPool = new cognito.UserPool(this, 'userpool', { // not relevant }); userPool.addDomain('CognitoDomain', { // not relevant }); const clientReadAttributes = new cognito.ClientAttributes() .withStandardAttributes({ // not relevant }) .withCustomAttributes(...['isAdmin']); const clientWriteAttributes = new cognito.ClientAttributes() .withStandardAttributes({ // not relevant }) .withCustomAttributes(...[]); const userPoolClient = new cognito.UserPoolClient(this, 'userpool-client', { // not relevant }); // DB Table const teamsTable = new ddb.Table(this, "teams", { partitionKey: {name: "team_id", type: ddb.AttributeType.STRING}, billingMode: ddb.BillingMode.PAY_PER_REQUEST, }); // Base Layer with fastapi installed const fastApiBaseLayer = new lambda.LayerVersion(this, "fastApiBaseLayer", { code: lambda.Code.fromAsset("lambda_base_layer/layer.zip"), compatibleRuntimes: [lambda.Runtime.PYTHON_3_9], }); // Lambda function const fastApiLambda = new lambda.Function(this, "fastApiLambda", { runtime: lambda.Runtime.PYTHON_3_9, code: lambda.Code.fromAsset("../app"), handler: "main.handler", layers: [fastApiBaseLayer], environment: { TEAMS_TABLE_NAME: "teams", COGNITO_PUBLIC_KEY: // not relevant } }); const authorizer = new apiGateway.CognitoUserPoolsAuthorizer(this, 'userPoolAuth', { cognitoUserPools: [userPool] }) // Api Gateway const fastApiApiGateway = new apiGateway.RestApi(this, "fastApiApiGateway", { restApiName: "fastApiApiGateway", defaultMethodOptions: { authorizationType: apiGateway.AuthorizationType.COGNITO, authorizer } }); // Lambda to ApiGateway const lambdaApiIntegration = new apiGateway.LambdaIntegration(fastApiLambda); fastApiApiGateway.root.addProxy({ defaultIntegration: lambdaApiIntegration }); teamsTable.grantReadWriteData(fastApiLambda); } }
解决方案
1. 修正Lambda环境变量中的表名
代码中硬编码了TEAMS_TABLE_NAME: "teams",但CDK默认会给生成的表添加栈前缀(比如SoccerTipGameInfrastructure-teams-xxxx),导致Lambda尝试访问的表和CDK创建并授权的表不是同一个。将环境变量改为使用CDK生成的实际表名:
environment: { TEAMS_TABLE_NAME: teamsTable.tableName, // 替换硬编码的"teams" COGNITO_PUBLIC_KEY: // 你的密钥内容 }
2. 明确权限声明(可选)
如果上述修改后仍有问题,可以替换teamsTable.grantReadWriteData(fastApiLambda);为更明确的权限声明,确保权限覆盖所需操作:
fastApiLambda.addToRolePolicy(new iam.PolicyStatement({ actions: [ 'dynamodb:PutItem', 'dynamodb:GetItem', 'dynamodb:Scan', 'dynamodb:UpdateItem', 'dynamodb:DeleteItem' ], resources: [teamsTable.tableArn], }));
3. 重新部署并验证
运行cdk deploy重新部署栈,然后在AWS控制台检查Lambda的执行角色:
- 找到目标Lambda函数,进入"配置"->"权限"
- 查看执行角色的权限策略,确认存在允许
dynamodb:PutItem操作且资源为目标DynamoDB表ARN的策略
内容的提问来源于stack exchange,提问作者thomaswiiswitch
相关产品推荐
相关产品推荐

