TheArchitect

Streaming Analytics

AWS architecture template · SAA-C03: Kinesis Data Stream → Lambda → S3 archive + DynamoDB + CloudWatch

Streaming Analytics is a free AWS architecture template built with CloudWatch, DynamoDB, IAM, Kinesis, Lambda and S3. Open it in TheArchitect to edit the diagram, estimate monthly cost, and export the CloudFormation or Terraform that deploys it.

KinesisStream ConsumerConsumer RoleArchive BucketEvents TableIterator Lag A…
Streaming Analytics architecture diagram

AWS services in this template

  • CloudWatch
  • DynamoDB
  • IAM
  • Kinesis
  • Lambda
  • S3

Deployment notes

Deploy-ready

  • Deploys a Kinesis stream, Lambda consumer with inline code, S3 archive bucket, DynamoDB table, and iterator-lag alarm.

Generated CloudFormation — 7 resources

Logical IDResource type
KinesiskinesisAWS::Kinesis::Stream
StreamConsumerlambdaAWS::Lambda::Function
ConsumerRoleiamAWS::IAM::Role
ArchiveBuckets3AWS::S3::Bucket
EventsTabledynamodbAWS::DynamoDB::Table
IteratorLagAlarmcloudwatchAWS::CloudWatch::Alarm
StreamConsumerlambdaArchiveBuckets3PermissionAWS::Lambda::Permission
View the full CloudFormation template
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "Generated by TheArchitect — https://www.thecloudarchitect.dev",
  "Metadata": {
    "TheArchitect": {
      "Edges": [
        {
          "From": "Kinesiskinesis",
          "To": "StreamConsumerlambda",
          "Label": "records"
        },
        {
          "From": "ConsumerRoleiam",
          "To": "StreamConsumerlambda",
          "Label": "role"
        },
        {
          "From": "StreamConsumerlambda",
          "To": "ArchiveBuckets3",
          "Label": "archive"
        },
        {
          "From": "StreamConsumerlambda",
          "To": "EventsTabledynamodb",
          "Label": "write"
        },
        {
          "From": "StreamConsumerlambda",
          "To": "IteratorLagAlarmcloudwatch",
          "Label": "metrics"
        }
      ]
    }
  },
  "Resources": {
    "Kinesiskinesis": {
      "Type": "AWS::Kinesis::Stream",
      "Properties": {
        "Name": "saa-events-stream",
        "StreamModeDetails": {
          "StreamMode": "PROVISIONED"
        },
        "ShardCount": 2,
        "RetentionPeriodHours": 24
      }
    },
    "StreamConsumerlambda": {
      "Type": "AWS::Lambda::Function",
      "DependsOn": [
        "ConsumerRoleiam"
      ],
      "Properties": {
        "FunctionName": "saa-stream-consumer",
        "Runtime": "nodejs20.x",
        "Handler": "index.handler",
        "MemorySize": 512,
        "Architectures": [
          "arm64"
        ],
        "Timeout": 30,
        "Description": "Consumes Kinesis records and fans out to S3 and DynamoDB.",
        "Environment": {
          "Variables": {
            "APP_ENV": "demo",
            "LOG_LEVEL": "info"
          }
        },
        "TracingConfig": {
          "Mode": "Active"
        },
        "Code": {
          "ZipFile": "exports.handler = async (event) => ({ processed: Array.isArray(event.Records) ? event.Records.length : 1 });"
        },
        "Role": {
          "Fn::GetAtt": [
            "ConsumerRoleiam",
            "Arn"
          ]
        }
      }
    },
    "ConsumerRoleiam": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "RoleName": "saa-stream-consumer-role",
        "Description": "Execution role for the Kinesis consumer Lambda.",
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": "lambda.amazonaws.com"
              },
              "Action": "sts:AssumeRole"
            }
          ]
        },
        "ManagedPolicyArns": [
          "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
        ]
      }
    },
    "ArchiveBuckets3": {
      "Type": "AWS::S3::Bucket",
      "Properties": {
        "BucketName": "saa-stream-archive",
        "VersioningConfiguration": {
          "Status": "Enabled"
        },
        "OwnershipControls": {
          "Rules": [
            {
              "ObjectOwnership": "BucketOwnerEnforced"
            }
          ]
        },
        "BucketEncryption": {
          "ServerSideEncryptionConfiguration": [
            {
              "ServerSideEncryptionByDefault": {
                "SSEAlgorithm": "AES256"
              }
            }
          ]
        },
        "PublicAccessBlockConfiguration": {
          "BlockPublicAcls": true,
          "BlockPublicPolicy": true,
          "IgnorePublicAcls": true,
          "RestrictPublicBuckets": true
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": "saa-stream-archive"
          }
        ],
        "NotificationConfiguration": {
          "LambdaConfigurations": [
            {
              "Event": "s3:ObjectCreated:*",
              "Function": {
                "Fn::GetAtt": [
                  "StreamConsumerlambda",
                  "Arn"
                ]
              }
            }
          ]
        }
      },
      "DependsOn": [
        "StreamConsumerlambdaArchiveBuckets3Permission"
      ]
    },
    "EventsTabledynamodb": {
      "Type": "AWS::DynamoDB::Table",
      "Properties": {
        "TableName": "saa-stream-events",
        "BillingMode": "PAY_PER_REQUEST",
        "AttributeDefinitions": [
          {
            "AttributeName": "streamId",
            "AttributeType": "S"
          },
          {
            "AttributeName": "ts",
            "AttributeType": "N"
          }
        ],
        "KeySchema": [
          {
            "AttributeName": "streamId",
            "KeyType": "HASH"
          },
          {
            "AttributeName": "ts",
            "KeyType": "RANGE"
          }
        ],
        "PointInTimeRecoverySpecification": {
          "PointInTimeRecoveryEnabled": true
        },
        "SSESpecification": {
          "SSEEnabled": true
        }
      }
    },
    "IteratorLagAlarmcloudwatch": {
      "Type": "AWS::CloudWatch::Alarm",
      "Properties": {
        "AlarmName": "saa-stream-iterator-lag",
        "AlarmDescription": "Alert on Kinesis iterator age above 60 seconds.",
        "Namespace": "AWS/Kinesis",
        "MetricName": "GetRecords.IteratorAgeMilliseconds",
        "Statistic": "Maximum",
        "Period": 60,
        "EvaluationPeriods": 2,
        "Threshold": 60000,
        "ComparisonOperator": "GreaterThanOrEqualToThreshold",
        "TreatMissingData": "notBreaching"
      }
    },
    "StreamConsumerlambdaArchiveBuckets3Permission": {
      "Type": "AWS::Lambda::Permission",
      "DependsOn": [
        "StreamConsumerlambda"
      ],
      "Properties": {
        "Action": "lambda:InvokeFunction",
        "FunctionName": {
          "Ref": "StreamConsumerlambda"
        },
        "Principal": "s3.amazonaws.com",
        "SourceAccount": {
          "Ref": "AWS::AccountId"
        },
        "SourceArn": {
          "Fn::Sub": "arn:${AWS::Partition}:s3:::saa-stream-archive"
        }
      }
    }
  }
}

Generated by TheArchitect from the diagram above. Review values such as names, CIDR ranges and instance sizes before deploying to your account.

Related templates