lacework / terraform-aws-cloudtrail

Terraform module for configuring an integration with Lacework and AWS for CloudTrail analysis
6 stars 21 forks source link

feat: Lacework CloudTrail should send logs to CloudWatch #135

Open TheShahin opened 1 year ago

TheShahin commented 1 year ago

Feature Request

Describe the Feature Request The CloudTrail created by this Terraform module should support setting up a proper logging integration with CloudWatch.

Is your feature request related to a problem? Please describe The created CloudTrail is non-compliant with CIS Benchmarks and is listed as a Medium severity in Lacework's generated reports for compliance with AWS ISO 27001:2013 and AWS ISO/IEC 27002:2022.

The non-compliance in question is lacework-global-55.

Describe Preferred Solution The module creates resources that by default are compliant with CIS Benchmarks.

Add input variables cloudwatch_logs_encryption_enabled, cloudwatch_logs_encryption_key_arn, and cloudwatch_logs_iam_role_arn, and set them in the aws_cloudtrail resource. If no IAM role ARN is provided then one should be created by the module.

Additional Context I think the changes needed are the following:

variables.tf:

variable "cloudwatch_logs_encryption_enabled" {
  type    = bool
  default = true
}

variable "cloudwatch_logs_encryption_key_arn" {
  type    = string
  default = ""
}

variable "cloudwatch_logs_iam_role_arn" {
  type    = string
  default = ""
}

main.tf:

locals {
  ...
  create_cloudwatch_iam_role = var.cloudwatch_logs_encryption_enabled && var.cloudwatch_logs_iam_role_arn == null

  cloudwatch_key_arn = var.cloudwatch_logs_encryption_enabled ? (length(var.cloudwatch_logs_encryption_key_arn) > 0 ? var.cloudwatch_logs_encryption_key_arn : aws_kms_key.lacework_kms_key[0].arn) : ""

  cloudwatch_logstream_arn = "${aws_cloudwatch_log_group.cloudtrail_log_group.arn}:log-stream:${data.aws_caller_identity.current.account_id}_CloudTrail_${data.aws_region.current.name}*" # Reference: https://docs.aws.amazon.com/awscloudtrail/latest/userguide/send-cloudtrail-events-to-cloudwatch-logs.html
}

data "aws_iam_policy_document" "kms_key_policy" {
  ...

  dynamic "statement" {
    for_each = (var.cloudwatch_logs_encryption_enabled && length(var.cloudwatch_logs_encryption_key_arn) == 0) ? [1] : []
    content {
      sid    = "Allow CloudWatch service to encrypt/decrypt"
      effect = "Allow"

      actions = [
        "kms:Encrypt*",
        "kms:Decrypt*",
        "kms:ReEncrypt*",
        "kms:GenerateDataKey*",
        "kms:Describe*"
      ]

      resources = ["*"]

      principals {
        type = "Service"
        identifiers = [
          "logs.${data.aws_region.current.name}.amazonaws.com",
        ]
      }

      condition {
        test     = "ArnEquals"
        variable = "kms:EncryptionContext:aws:logs:arn"
        values = [
          "arn:aws:logs:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:log-group:${var.cloudtrail_name}",
        ]
      }
    }
  }
}

resource "aws_cloudwatch_log_group" "cloudtrail_log_group" {
  name              = var.cloudtrail_name
  kms_key_id        = local.cloudwatch_key_arn
  retention_in_days = 90
}

data "aws_iam_policy_document" "cloudtrail_assume_role" {
  count = local.create_cloudwatch_iam_role ? 1 : 0

  statement {
    effect = "Allow"

    actions = [
      "sts:AssumeRole",
    ]

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

data "aws_iam_policy_document" "cloudtrail_logging" {
  count = local.create_cloudwatch_iam_role ? 1 : 0

  statement {
    sid    = "AWSCloudTrailCreateLogStream"
    effect = "Allow"

    actions = [
      "logs:CreateLogStream",
    ]

    resources = [
      local.cloudwatch_logstream_resource,
    ]
  }

  statement {
    sid    = "AWSCloudTrailPutLogEvents"
    effect = "Allow"

    actions = [
      "logs:PutLogEvents",
    ]

    resources = [
      local.cloudwatch_logstream_resource,
    ]
  }
}

resource "aws_iam_policy" "cloudtrail_logging" {
  count = local.create_cloudwatch_iam_role ? 1 : 0

  name        = var.cloudtrail_name
  policy      = data.aws_iam_policy_document.cloudtrail_logging[count.index].json
  description = "Allows CloudTrail to create log streams and to put logs in CloudWatch"
}

resource "aws_iam_role" "cloudtrail_logging" {
  count = local.create_cloudwatch_iam_role ? 1 : 0

  name               = var.cloudtrail_name
  assume_role_policy = data.aws_iam_policy_document.cloudtrail_assume_role[count.index].json
}

resource "aws_iam_role_policy_attachment" "cloudtrail_logging" {
  count = local.create_cloudwatch_iam_role ? 1 : 0

  role       = aws_iam_role.cloudtrail_logging[count.index].name
  policy_arn = aws_iam_policy.cloudtrail_logging[count.index].arn
}

resource "aws_cloudtrail" "lacework_cloudtrail" {
  ...
  enable_logging             = true
  cloud_watch_logs_group_arn = "${aws_cloudwatch_log_group.cloudtrail_log_group.arn}:*"
  cloud_watch_logs_role_arn  = local.create_cloudwatch_iam_role ? coalesce(var.cloudwatch_logs_iam_role_arn, aws_iam_role.cloudtrail_logging.arn) : null
  enable_log_file_validation = var.enable_log_file_validation
  ...
}

Please note that this code has not been properly tested. I've simply adjusted Terraform configurations that I've found elsewhere.

Thanks!

TheShahin commented 1 year ago

Any news on this?