This template sets up a CloudWatch Metric Stream that filters and sends specific AWS/EC2 and AWS/EBS metrics to an Amazon Kinesis Firehose delivery stream, which then stores the data in an S3 bucket.

Terraform Template

data "aws_iam_policy_document" "firehose_assume_role" {

  statement {
    actions = ["sts:AssumeRole"]
    effect = "Allow"

    principals {
      identifiers = ["firehose.amazonaws.com"]
      type = "Service"
    }
  }
}

data "aws_iam_policy_document" "firehose_to_s3" {

  statement {
    actions = ["s3:AbortMultipartUpload", "s3:GetBucketLocation", "s3:GetObject", "s3:ListBucket", "s3:ListBucketMultipartUploads", "s3:PutObject"]
    effect = "Allow"
    resources = [aws_s3_bucket.bucket.arn, "${aws_s3_bucket.bucket.arn}/*"]
  }
}

data "aws_iam_policy_document" "metric_stream_to_firehose" {

  statement {
    actions = ["firehose:PutRecord", "firehose:PutRecordBatch"]
    effect = "Allow"
    resources = [aws_kinesis_firehose_delivery_stream.s3_stream.arn]
  }
}

data "aws_iam_policy_document" "streams_assume_role" {

  statement {
    actions = ["sts:AssumeRole"]
    effect = "Allow"

    principals {
      identifiers = ["streams.metrics.cloudwatch.amazonaws.com"]
      type = "Service"
    }
  }
}

resource "aws_cloudwatch_metric_stream" "main" {
  firehose_arn = aws_kinesis_firehose_delivery_stream.s3_stream.arn
  include_filter = ["CPUUtilization", "NetworkOut", "AWS/EC2", "AWS/EBS"]
  name = "my-metric-stream"
  output_format = "json"
  role_arn = aws_iam_role.metric_stream_to_firehose.arn
}

resource "aws_iam_role" "firehose_to_s3" {
  assume_role_policy = data.aws_iam_policy_document.firehose_assume_role.json
}

resource "aws_iam_role" "metric_stream_to_firehose" {
  assume_role_policy = data.aws_iam_policy_document.streams_assume_role.json
  name = "metric_stream_to_firehose_role"
}

resource "aws_iam_role_policy" "firehose_to_s3" {
  name = "default"
  policy = data.aws_iam_policy_document.firehose_to_s3.json
  role = aws_iam_role.firehose_to_s3.id
}

resource "aws_iam_role_policy" "metric_stream_to_firehose" {
  name = "default"
  policy = data.aws_iam_policy_document.metric_stream_to_firehose.json
  role = aws_iam_role.metric_stream_to_firehose.id
}

resource "aws_kinesis_firehose_delivery_stream" "s3_stream" {
}

resource "aws_s3_bucket" "bucket" {
  bucket = "metric-stream-test-bucket"
}

resource "aws_s3_bucket_acl" "bucket_acl" {
  acl = "private"
  bucket = aws_s3_bucket.bucket.id
}