module "default_tags" {
  source             = "git@github.com:theorchard/terraform-default-tags.git//?ref=2.0.0"
  environment        = var.environment
  application_family = var.application_family
  team_name          = var.team_name
  service_name       = var.service_name
}

provider "aws" {
  region = var.aws_region

  default_tags {
    tags = module.default_tags.tags
  }
}

data "aws_caller_identity" "current" {}

# Terraform backends cannot contain interpolations
terraform {
  backend "s3" {
    bucket  = "orcd-terraform-state"
    key     = "prod/terraform-aws-waf-logging/terraform.tfstate"
    region  = "us-east-1"
    encrypt = "true"
  }
}

resource "aws_kinesis_firehose_delivery_stream" "extended_s3_stream" {
  # checkov:skip=CKV_AWS_241:Log stream encryption will be tested and implemented as part of the WIZ-670 ticket.

  name        = "aws-waf-logs-tf-orcd-prod-stream"
  destination = "extended_s3"
  server_side_encryption {
    enabled = true
  }
  extended_s3_configuration {
    role_arn   = aws_iam_role.firehose_role.arn
    bucket_arn = module.bucket.s3_bucket_arn_output
  }
  tags = {
    Name        = "aws-waf-logs-tf-orcd-prod-stream"
    terraformed = "true"
  }
}

data "aws_iam_policy_document" "bucket_policy" {
  statement {
    sid = "AWSLogDeliveryWrite"

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

    actions = [
      "s3:PutObject",
    ]

    resources = [
      "${module.bucket.s3_bucket_arn_output}/*"
    ]

    condition {
      test     = "StringEquals"
      variable = "s3:x-amz-acl"

      values = ["bucket-owner-full-control"]
    }

    condition {
      test     = "StringEquals"
      variable = "aws:SourceAccount"

      values = [data.aws_caller_identity.current.account_id]
    }

    condition {
      test     = "ArnLike"
      variable = "aws:SourceArn"

      values = ["arn:aws:logs:${var.aws_region}:${data.aws_caller_identity.current.account_id}:*"]
    }
  }

  statement {
    sid = "AWSLogDeliveryAclCheck"

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

    actions = [
      "s3:GetBucketAcl",
    ]

    resources = [
      module.bucket.s3_bucket_arn_output,
    ]

    condition {
      test     = "StringEquals"
      variable = "aws:SourceAccount"

      values = [data.aws_caller_identity.current.account_id]
    }

    condition {
      test     = "ArnLike"
      variable = "aws:SourceArn"

      values = ["arn:aws:logs:${var.aws_region}:${data.aws_caller_identity.current.account_id}:*"]
    }
  }
}

module "bucket" {
  source                = "git@github.com:theorchard/terraform-s3.git//modules/s3_bucket?ref=3.12.1"
  env                   = "aws-waf-logs"
  bucket_name           = "prod-tf-orcd-bucket"
  custom_logging_bucket = "prod-orcd-s3-logs"
  application_family    = var.application_family

  apply_server_side_encryption_by_default = {
    sse_algorithm = "AES256"
  }

  bucket_policy_overrides = [
    data.aws_iam_policy_document.bucket_policy.json,
  ]

  lifecycle_rules_options_noncurrent_version_expiration = [
    {
      prefix  = "" # Using "" will lifecyle the whole bucket.
      enabled = true
      days    = 30
    },
  ]

  lifecycle_rules_options_current_version_expiration = [
    {
      prefix  = "" # Using "" will lifecyle the whole bucket.
      enabled = true
      days    = 60
    },

  ]

  lifecycle_rules_abort_incomplete_multipart_upload_days = [
    {
      prefix  = "" # Using "" will lifecyle the whole bucket.
      enabled = true
      days    = 3
    },
  ]
}

resource "aws_iam_role" "firehose_role" {
  name = "${var.environment}-${var.service_name}-firehose-role"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "firehose.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

data "aws_iam_policy_document" "firehose_s3_iam_policy_document" {
  statement {
    actions = [
      "s3:AbortMultipartUpload",
      "s3:GetBucketLocation",
      "s3:GetObject",
      "s3:ListBucket",
      "s3:ListBucketMultipartUploads",
      "s3:PutObject"
    ]

    resources = [
      "${module.bucket.s3_bucket_arn_output}/*"
    ]
  }

  statement {
    actions = [
      "s3:ListBucket",
    ]

    resources = [
      "${module.bucket.s3_bucket_arn_output}/*"
    ]
  }

  statement {
    actions = [
      "s3:GetBucketLocation",
      "s3:ListAllMyBuckets"
    ]

    resources = [
      "*"
    ]
  }
}

resource "aws_iam_policy" "firehose_s3_iam_policy" {
  name        = "S3-${var.environment}-firehose-policy"
  description = "Firehose iam policy to write on s3 bucket"
  policy      = data.aws_iam_policy_document.firehose_s3_iam_policy_document.json
}

resource "aws_iam_role_policy_attachment" "firehose_role_s3_iam_policy_attachment" {
  policy_arn = aws_iam_policy.firehose_s3_iam_policy.arn
  role       = aws_iam_role.firehose_role.name
}

data "aws_iam_policy_document" "kms_data_policy" {
  # checkov:skip=CKV_AWS_109:It is a KMS key policy, so it applies only to a specific key. This policy allows GSIRT to access the key using IAM policies for decrypting AWS WAF logs. GSIRT uses `<env>-gsirt-waf-logs-access-policy` while any other access is forbidden by `<env>-orchard-shared-iam-deny-policy`.
  # checkov:skip=CKV_AWS_111:The same as above.

  version = "2012-10-17"
  statement {
    sid    = "Enable IAM User Permissions"
    effect = "Allow"
    principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::437795906767:root"]
    }
    actions   = ["kms:*"]
    resources = ["*"]
  }
  statement {
    sid    = "Allow sns and s3 to use kms key"
    effect = "Allow"
    principals {
      type        = "Service"
      identifiers = ["s3.amazonaws.com", "sns.amazonaws.com"]
    }
    actions   = ["kms:GenerateDataKey", "kms:Decrypt"]
    resources = ["arn:aws:kms:us-east-1:437795906767:key/129b659e-38e8-41d7-ad74-81826b45376d"]
  }
}

resource "aws_kms_key" "aws_waf_logging_kms_key" {
  description = "${var.environment}-${var.service_name}-kms-key"
  policy      = data.aws_iam_policy_document.kms_data_policy.json

  enable_key_rotation = true

  tags = {
    environment  = var.environment
    service_name = var.service_name
    terraformed  = "true"
  }
}

resource "aws_kms_alias" "aws_waf_logging_kms_key_alias" {
  name          = "alias/${var.environment}-aws-waf-logging-data-key"
  target_key_id = aws_kms_key.aws_waf_logging_kms_key.key_id
}

# Create sqs with dlq for WAF logging
module "aws_waf_sqs" {
  source = "git@github.com:theorchard/terraform-sqs.git?ref=2.5.0"

  environment                          = var.environment
  queue_name                           = "orcd-waf-logs"
  sqs_kms_master_key_id                = aws_kms_alias.aws_waf_logging_kms_key_alias.name
  sqs_delay_seconds                    = 10
  sqs_max_message_size                 = 2048
  sqs_message_retention_seconds        = 86400
  sqs_receive_wait_time_seconds        = 10
  sqs_deadletter_enabled               = true
  deadletter_max_receive_count         = 200
  deadletter_delay_seconds             = 10
  deadletter_max_message_size          = 2048
  deadletter_message_retention_seconds = 86400
  deadletter_receive_wait_time_seconds = 10
  application_family                   = var.application_family
}

resource "aws_sqs_queue_policy" "aws_waf_logging_access_policy" {
  queue_url = module.aws_waf_sqs.queue_url

  policy = <<POLICY
{
  "Version": "2012-10-17",
  "Id": "arn:aws:sqs:${var.aws_region}:${data.aws_caller_identity.current.account_id}:undefined/SQSDefaultPolicy",
  "Statement": [
    {
      "Sid": "topic-subscription-arn:${aws_sns_topic.topic.arn}",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": "SQS:SendMessage",
      "Resource": "${module.aws_waf_sqs.queue_arn}",
      "Condition": {
        "ArnLike": {
          "aws:SourceArn": "${aws_sns_topic.topic.arn}"
        }
      }
    }
  ]
}
POLICY
}

resource "aws_sns_topic" "topic" {
  name                          = "prod-orcd-waf-logs"
  kms_master_key_id             = aws_kms_key.aws_waf_logging_kms_key.key_id
  sqs_failure_feedback_role_arn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/SNSFailureFeedback"
  sqs_success_feedback_role_arn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/SNSSuccessFeedback"
  delivery_policy               = ""
  policy                        = <<POLICY
{
    "Version":"2012-10-17",
    "Statement":[{
        "Effect": "Allow",
        "Principal": { "Service": "s3.amazonaws.com" },
        "Action": "SNS:Publish",
        "Resource": "arn:aws:sns:*:*:prod-orcd-waf-logs",
        "Condition":{
            "ArnLike":{"aws:SourceArn":"${module.bucket.s3_bucket_arn_output}"}
        }
    }]
}
POLICY
}

# Subscribe sns topic to sqs endpoint
resource "aws_sns_topic_subscription" "aws_waf_sqs_target" {
  topic_arn              = aws_sns_topic.topic.arn
  protocol               = "sqs"
  endpoint               = module.aws_waf_sqs.queue_arn
  endpoint_auto_confirms = true
}

resource "aws_s3_bucket_notification" "bucket_notification" {
  bucket = module.bucket.s3_bucket_name_output

  topic {
    topic_arn = aws_sns_topic.topic.arn
    events    = ["s3:ObjectCreated:*"]
  }
}

resource "aws_lambda_permission" "allow_execution_from_sns" {
  statement_id  = "AllowExecutionFromSNS"
  action        = "lambda:InvokeFunction"
  function_name = "arn:aws:lambda:us-east-1:${data.aws_caller_identity.current.account_id}:function:DatadogLambdaFunction"
  principal     = "sns.amazonaws.com"
  source_arn    = aws_sns_topic.topic.arn
}

# Subscribe sns topic to Datadog lambda
resource "aws_sns_topic_subscription" "datadog_lambda_target" {
  topic_arn              = aws_sns_topic.topic.arn
  protocol               = "lambda"
  endpoint               = "arn:aws:lambda:us-east-1:${data.aws_caller_identity.current.account_id}:function:DatadogLambdaFunction"
  endpoint_auto_confirms = true
}
