data "aws_iam_policy_document" "guardduty_malware_protection_assume_role" {
  count = var.enable_guardduty_malware_protection ? 1 : 0
  statement {
    sid     = "GuardDutyMalwareProtectionForS3"
    effect  = "Allow"
    actions = [
      "sts:AssumeRole"
    ]
    principals {
      type        = "Service"
      identifiers = [
        "malware-protection-plan.guardduty.amazonaws.com"
      ]
    }
    condition {
      test     = "StringEquals"
      variable = "aws:SourceAccount"
      values   = [
        data.aws_caller_identity.current.account_id
      ]
    }
    condition {
      test     = "ArnLike"
      variable = "aws:SourceArn"
      values   = [
        "arn:aws:guardduty:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:malware-protection-plan/*"
      ]
    }
  }
}

resource "aws_iam_role" "guardduty_malware_protection_for_s3" {
  count = var.enable_guardduty_malware_protection ? 1 : 0
  name  = "GuardDuty-S3-${aws_s3_bucket.bucket.bucket}"
  assume_role_policy = data.aws_iam_policy_document.guardduty_malware_protection_assume_role[0].json
}

resource "aws_guardduty_malware_protection_plan" "protection_plan" {
  count = var.enable_guardduty_malware_protection ? 1 : 0
  role  = aws_iam_role.guardduty_malware_protection_for_s3[0].arn
  protected_resource {
    s3_bucket {
      bucket_name = aws_s3_bucket.bucket.bucket
    }
  }

  actions {
    tagging {
      status = "ENABLED"
    }
  }

  tags = local.tags
}

data "aws_iam_policy_document" "guardduty_malware_protection_for_s3_policy_document" {
  statement {
    sid     = "AllowManagedRuleToSendS3EventsToGuardDuty"
    effect  = "Allow"
    actions = [
      "events:PutRule"
    ]
    resources = [
      "arn:aws:events:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:rule/DO-NOT-DELETE-AmazonGuardDutyMalwareProtectionS3*"
    ]
    condition {
      test     = "StringEquals"
      variable = "events:ManagedBy"
      values   = ["malware-protection-plan.guardduty.amazonaws.com"]
    }
    condition {
      test     = "ForAllValues:StringEquals"
      variable = "events:source"
      values   = ["aws.s3"]
    }
    condition {
      test     = "ForAllValues:StringEquals"
      variable = "events:detail-type"
      values   = ["Object Created", "AWS API Call via CloudTrail"]
    }
    condition {
      test     = "Null"
      variable = "events:source"
      values   = ["false"]
    }
    condition {
      test     = "Null"
      variable = "events:detail-type"
      values   = ["false"]
    }
  }

  statement {
    sid     = "AllowUpdateTargetAndDeleteManagedRule"
    effect  = "Allow"
    actions = [
      "events:DeleteRule",
      "events:PutTargets",
      "events:RemoveTargets"
    ]
    resources = [
      "arn:aws:events:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:rule/DO-NOT-DELETE-AmazonGuardDutyMalwareProtectionS3*"
    ]
    condition {
      test     = "StringEquals"
      variable = "events:ManagedBy"
      values   = ["malware-protection-plan.guardduty.amazonaws.com"]
    }
  }

  statement {
    sid     = "AllowGuardDutyToMonitorEventBridgeManagedRule"
    effect  = "Allow"
    actions = [
      "events:DescribeRule",
      "events:ListTargetsByRule"
    ]
    resources = [
      "arn:aws:events:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:rule/DO-NOT-DELETE-AmazonGuardDutyMalwareProtectionS3*"
    ]
  }

  statement {
    sid     = "AllowEnableS3EventBridgeEvents"
    effect  = "Allow"
    actions = [
      "s3:PutBucketNotification",
      "s3:GetBucketNotification"
    ]
    resources = [
      "arn:aws:s3:::${aws_s3_bucket.bucket.bucket}"
    ]
    condition {
      test     = "StringEquals"
      variable = "aws:ResourceAccount"
      values   = ["${data.aws_caller_identity.current.account_id}"]
    }
  }

  statement {
    sid     = "AllowPostScanTag"
    effect  = "Allow"
    actions = [
      "s3:GetObjectTagging",
      "s3:GetObjectVersionTagging",
      "s3:PutObjectTagging",
      "s3:PutObjectVersionTagging"
    ]
    resources = [
      "arn:aws:s3:::${aws_s3_bucket.bucket.bucket}/*"
    ]
    condition {
      test     = "StringEquals"
      variable = "aws:ResourceAccount"
      values   = ["${data.aws_caller_identity.current.account_id}"]
    }
  }

  statement {
    sid     = "AllowPutValidationObject"
    effect  = "Allow"
    actions = [
      "s3:PutObject"
    ]
    resources = [
      "arn:aws:s3:::${aws_s3_bucket.bucket.bucket}/malware-protection-resource-validation-object"
    ]
    condition {
      test     = "StringEquals"
      variable = "aws:ResourceAccount"
      values   = ["${data.aws_caller_identity.current.account_id}"]
    }
  }

  statement {
    sid     = "AllowCheckBucketOwnership"
    effect  = "Allow"
    actions = [
      "s3:ListBucket"
    ]
    resources = [
      "arn:aws:s3:::${aws_s3_bucket.bucket.bucket}"
    ]
    condition {
      test     = "StringEquals"
      variable = "aws:ResourceAccount"
      values   = ["${data.aws_caller_identity.current.account_id}"]
    }
  }

  statement {
    sid     = "AllowMalwareScan"
    effect  = "Allow"
    actions = [
      "s3:GetObject",
      "s3:GetObjectVersion"
    ]
    resources = [
      "arn:aws:s3:::${aws_s3_bucket.bucket.bucket}/*"
    ]
    condition {
      test     = "StringEquals"
      variable = "aws:ResourceAccount"
      values   = ["${data.aws_caller_identity.current.account_id}"]
    }
  }
}

resource "aws_iam_policy" "guardduty_malware_protection_for_s3_policy" {
  count       = var.enable_guardduty_malware_protection ? 1 : 0
  name        = "GuardDuty-S3-Policy-${aws_s3_bucket.bucket.bucket}"
  description = "Policy for GuardDuty Malware Protection for S3 bucket ${aws_s3_bucket.bucket.bucket}."
  policy      = data.aws_iam_policy_document.guardduty_malware_protection_for_s3_policy_document.json
}

resource "aws_iam_role_policy_attachment" "guardduty_malware_protection_for_s3" {
  count      = var.enable_guardduty_malware_protection ? 1 : 0
  role       = aws_iam_role.guardduty_malware_protection_for_s3[0].name
  policy_arn = aws_iam_policy.guardduty_malware_protection_for_s3_policy[0].arn
}

resource "aws_cloudwatch_event_rule" "guardduty_malware" {
  count       = var.enable_guardduty_malware_protection ? 1 : 0
  name        = "guardduty-malware-${aws_s3_bucket.bucket.bucket}"
  description = "Capture GuardDuty Malware Protection findings for a ${aws_s3_bucket.bucket.bucket} bucket"
  event_pattern = jsonencode({
    source        = ["aws.guardduty"],
    "detail-type" = ["GuardDuty Finding"],
    detail = {
      type = [{ prefix = "Object:S3/MaliciousFile" }],
      resource = {
        s3BucketDetails = {
          name = [aws_s3_bucket.bucket.bucket]
        }
      }
    }
  })
}

resource "aws_cloudwatch_event_target" "guardduty_to_lambda" {
  count     = var.enable_guardduty_malware_protection ? 1 : 0
  rule      = aws_cloudwatch_event_rule.guardduty_malware[0].name
  target_id = "SendToDatadog"
  arn       = "arn:aws:lambda:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:function:DatadogLambdaFunction"
}
