VERSICH

Steps to create a Terraform Module that creates Kinesis, Firehose and SQS

steps to create a terraform module that creates kinesis, firehose and sqs

Creating a reusable Terraform module for AWS streaming and messaging is a practical way to standardize infrastructure across projects. This guide explains how to design a Terraform module that provisions Kinesis Data Stream, Kinesis Firehose, and SQS, with suggestions for adding diagrams and screenshots to a blog or documentation.

What This Terraform Module Will Do

The goal is to create a single Terraform module that can be called like this:

module "streaming_stack" { 
  source = "./modules/streaming" 
 
  project_name       = "orders" 
  environment        = "prod" 
  kinesis_shard_count = 1 
 
  firehose_destination_s3_bucket_arn = aws_s3_bucket.logs.arn 
 
  sqs_fifo           = false 
  sqs_visibility_timeout = 30 
} 

The module will create:

  • An AWS Kinesis Data Stream for ingesting records.

  • An AWS Kinesis Firehose Delivery Stream that delivers data, for example, to S3.

  • An AWS SQS Queue that can receive messages or connect to downstream consumers.

Module Structure

Create a folder, such as modules/streaming/, with these files:

  • main.tf, resources for Kinesis, Firehose, and SQS

  • variables.tf, inputs with sensible defaults

  • outputs.tf, ARNs and names exported to callers

Defining Module Inputs (variables.tf)

Start by defining the configurable inputs:

variable "project_name" { 
  type        = string 
  description = "Logical project name used for resource naming." 
} 
 
variable "environment" { 
  type        = string 
  description = "Environment name (e.g. dev, staging, prod)." 
} 
 
variable "kinesis_shard_count" { 
  type        = number 
  default     = 1 
  description = "Number of shards for the Kinesis stream." 
} 
 
variable "firehose_destination_s3_bucket_arn" { 
  type        = string 
  description = "ARN of the S3 bucket where Firehose will deliver data." 
} 
 
variable "sqs_fifo" { 
  type        = bool 
  default     = false 
  description = "Whether to create a FIFO SQS queue." 
} 
 
variable "sqs_visibility_timeout" { 
  type        = number 
  default     = 30 
  description = "SQS visibility timeout in seconds." 
} 
 
variable "tags" { 
  type        = map(string) 
  default     = {} 
  description = "Additional tags to apply to all resources." 
} 

Creating the Kinesis Data Stream (main.tf)

Use the AWS provider’s Kinesis resource to define the data stream.

resource "aws_kinesis_stream" "this" { 
  name             = "${var.project_name}-${var.environment}-stream" 
  shard_count      = var.kinesis_shard_count 
  retention_period = 24 
 
  shard_level_metrics = [ 
    "IncomingBytes", 
    "OutgoingBytes", 
  ] 
 
  tags = merge( 
    { 
      Name        = "${var.project_name}-${var.environment}-stream" 
      Environment = var.environment 
    }, 
    var.tags 
  ) 
} 

This creates a durable, scalable entry point for real-time data.

Creating the Firehose Delivery Stream

Next, create a Kinesis Firehose Delivery Stream that reads from the Kinesis Data Stream and delivers data to S3.

You’ll need an IAM role that Firehose can assume:

data "aws_iam_policy_document" "firehose_assume_role" { 
  statement { 
    actions = ["sts:AssumeRole"] 
 
    principals { 
      type        = "Service" 
      identifiers = ["firehose.amazonaws.com"] 
    } 
  } 
} 
 
resource "aws_iam_role" "firehose_role" { 
  name               = "${var.project_name}-${var.environment}-firehose-role" 
  assume_role_policy = data.aws_iam_policy_document.firehose_assume_role.json 
} 

Attach a basic policy, simplified for brevity:

data "aws_iam_policy_document" "firehose_policy" { 
  statement { 
    actions = [ 
      "s3:AbortMultipartUpload", 
      "s3:GetBucketLocation", 
      "s3:GetObject", 
      "s3:ListBucket", 
      "s3:ListBucketMultipartUploads", 
      "s3:PutObject" 
    ] 
    resources = [ 
      var.firehose_destination_s3_bucket_arn, 
      "${var.firehose_destination_s3_bucket_arn}/*" 
    ] 
  } 
 
  statement { 
    actions = [ 
      "kinesis:DescribeStream", 
      "kinesis:GetShardIterator", 
      "kinesis:GetRecords", 
      "kinesis:ListShards" 
    ] 
    resources = [aws_kinesis_stream.this.arn] 
  } 
} 
 
resource "aws_iam_role_policy" "firehose_policy" { 
  name   = "${var.project_name}-${var.environment}-firehose-policy" 
  role   = aws_iam_role.firehose_role.id 
  policy = data.aws_iam_policy_document.firehose_policy.json 
} 

Now define the Firehose stream:

resource "aws_kinesis_firehose_delivery_stream" "this" { 
  name        = "${var.project_name}-${var.environment}-firehose" 
  destination = "extended_s3"  # maps to S3 in most docs [web:843] 
 
  kinesis_source_configuration { 
    kinesis_stream_arn = aws_kinesis_stream.this.arn 
    role_arn           = aws_iam_role.firehose_role.arn 
  } 
 
  extended_s3_configuration { 
    role_arn   = aws_iam_role.firehose_role.arn 
    bucket_arn = var.firehose_destination_s3_bucket_arn 
 
    buffering_interval = 60 
    buffering_size     = 5 
 
    compression_format = "GZIP" 
  } 
 
  tags = merge( 
    { 
      Name        = "${var.project_name}-${var.environment}-firehose" 
      Environment = var.environment 
    }, 
    var.tags 
  ) 
} 

Creating the SQS Queue

Now define an SQS queue to buffer downstream processing.

resource "aws_sqs_queue" "this" { 
  name = var.sqs_fifo 
    ? "${var.project_name}-${var.environment}.fifo" 
    : "${var.project_name}-${var.environment}" 
 
  fifo_queue                  = var.sqs_fifo 
  visibility_timeout_seconds  = var.sqs_visibility_timeout 
  message_retention_seconds   = 345600 # 4 days 
 
  tags = merge( 
    { 
      Name        = "${var.project_name}-${var.environment}-queue" 
      Environment = var.environment 
    }, 
    var.tags 
  ) 
} 

For more advanced setups, you might also add:

  • A dead-letter queue

  • An access policy that restricts producers and consumers by IAM or IP

Exporting Outputs (outputs.tf)

Expose useful identifiers to the configuration that calls the module:

output "kinesis_stream_name" { 
  value       = aws_kinesis_stream.this.name 
  description = "Name of the Kinesis data stream." 
} 
 
output "kinesis_stream_arn" { 
  value       = aws_kinesis_stream.this.arn 
  description = "ARN of the Kinesis data stream." 
} 
 
output "firehose_name" { 
  value       = aws_kinesis_firehose_delivery_stream.this.name 
  description = "Name of the Firehose delivery stream." 
} 
 
output "firehose_arn" { 
  value       = aws_kinesis_firehose_delivery_stream.this.arn 
  description = "ARN of the Firehose delivery stream." 
} 
 
output "sqs_queue_url" { 
  value       = aws_sqs_queue.this.id 
  description = "URL of the SQS queue." 
} 
 
output "sqs_queue_arn" { 
  value       = aws_sqs_queue.this.arn 
  description = "ARN of the SQS queue." 
} 

Using the Module in a Root Configuration

In your root main.tf, wire everything together:

provider "aws" { 
  region = "us-east-1" 
} 
 
resource "aws_s3_bucket" "logs" { 
  bucket = "my-streaming-logs-bucket" 
} 
 
module "streaming_stack" { 
  source = "./modules/streaming" 
 
  project_name        = "orders" 
  environment         = "dev" 
  kinesis_shard_count = 1 
 
  firehose_destination_s3_bucket_arn = aws_s3_bucket.logs.arn 
 
  sqs_fifo                = false 
  sqs_visibility_timeout  = 45 
 
  tags = { 
    Owner = "data-platform" 
  } 
} 

Then run:

terraform init 
terraform plan 
terraform apply 

You now have a full streaming stack that can be reused across environments and projects.

Best Practices and Next Steps

Keep these best practices in mind when working with Kinesis, Firehose, and SQS in Terraform:

  • Enable encryption at rest for Kinesis and Firehose using KMS where required.

  • Use modules from the Terraform Registry or GitHub as references for advanced patterns such as dynamic partitioning or multi-destination streams.

  • Add alarms and logging, including CloudWatch metrics and log groups, around your stream and queue to monitor throughput and errors.

From here, you can extend the module to:

  • Add Lambda consumers for SQS

  • Forward Firehose data to destinations such as Redshift, OpenSearch, or Snowflake.

  • Introduce dead-letter queues and stricter queue policies for production-grade reliability.

Tags: