S3 to Lambda to DynamoDB

Upload object data from S3 to DynamoDB via Lambda.

S3AWS LambdaAmazon DynamoDB
import { Aws, Duration, RemovalPolicy, Stack, StackProps, CfnParameter, CfnOutput } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as s3n from 'aws-cdk-lib/aws-s3-notifications'
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as iam from 'aws-cdk-lib/aws-iam'
import { Effect } from 'aws-cdk-lib/aws-iam';
import { BillingMode } from 'aws-cdk-lib/aws-dynamodb';

export class S3LambdaDynamodbCdkStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);
    
    const dataObjectParam = new CfnParameter(this, 'dataObject', {
      type: 'String',
      description : 'Enter the name of the data object (For Example: product, customer, or order)',
      default: this.node.tryGetContext('dataObjectParam') ? this.node.tryGetContext('dataObjectParam') : 'object'
    });

    const bucket = new s3.Bucket(this, 's3-lambda-ddb-cdk', {
      removalPolicy: RemovalPolicy.DESTROY
    });
    const table = new dynamodb.Table(this, 'objects',{
      tableName: dataObjectParam.valueAsString,
      partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
      billingMode: BillingMode.PAY_PER_REQUEST,
      removalPolicy: RemovalPolicy.DESTROY
    });
    const lambdaRole = new iam.Role(this, 'dataloadFnRole', {
      assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com')
    });
    const lambdaRolePolicy = lambdaRole.assumeRolePolicy;
    lambdaRolePolicy?.addStatements(new iam.PolicyStatement({
      principals: [new iam.ServicePrincipal('s3.amazonaws.com')],
      actions: ['sts:AssumeRole']
    }));
    lambdaRole.addManagedPolicy(iam.ManagedPolicy.fromManagedPolicyArn(this, "AWSLambdaBasicExecutionRole", 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'));
    lambdaRole.addManagedPolicy(iam.ManagedPolicy.fromManagedPolicyArn(this, "AmazonS3ReadOnlyAccess", 'arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess'));
    lambdaRole.addManagedPolicy(iam.ManagedPolicy.fromManagedPolicyArn(this, "AWSLambdaInvocation-DynamoDB", 'arn:aws:iam::aws:policy/AWSLambdaInvocation-DynamoDB'));
    lambdaRole.addToPolicy(new iam.PolicyStatement({
      actions: [
        "dynamodb:PutItem",
        "dynamodb:BatchWriteItem"
      ],
      resources: ["*"],
      effect: Effect.ALLOW
    }));
    const lambdaFunction = new lambda.Function(this, 'dataload', {
      runtime: lambda.Runtime.PYTHON_3_7,
      handler: 'data-load.handler',
      code: lambda.Code.fromAsset('code'),
      role: lambdaRole,
      environment: {
        bucket: bucket.bucketName,
        key: dataObjectParam.valueAsString + '.csv',
        table: table.tableName
      },
      timeout: Duration.minutes(5)
    });
    lambdaFunction.grantInvoke(new iam.ServicePrincipal('s3.amazonaws.com').withConditions({
      ArnLike: {
        'aws:SourceArn': bucket.bucketArn,
      },
      StringEquals: {
        'aws:SourceAccount': Aws.ACCOUNT_ID,
      }
    }));
    bucket.addEventNotification(s3.EventType.OBJECT_CREATED, new s3n.LambdaDestination(lambdaFunction), {prefix: dataObjectParam.valueAsString + '.csv'});

    new CfnOutput(this, 'Bucket Name', { value: bucket.bucketName });
  }
}

Download

git clone https://github.com/aws-samples/serverless-patterns
cd serverless-patterns/s3-lambda-dynamodb-cdk

Pattern repository

View on GitHub

Last updated on 26 Dec 2024

Edit this page