provider "aws" {
  region = var.region
}

terraform {
  backend "s3" {
    bucket  = "prod-songwhip-terraform-state"
    key     = "prod/songwhip-content/terraform.tfstate"
    region  = "us-east-1"
    encrypt = "true"
  }
}

data "cloudflare_zone" "cloudflare_domain" {
  name = var.cloudflare_zone
}

module "content_s3_bucket" {
  source = "git@github.com:theorchard/terraform-s3.git//modules/s3_bucket?ref=3.12.1"

  env                   = var.environment
  bucket_name           = var.bucket_name
  custom_logging_bucket = "${var.environment}-songwhip-s3-logs"
  s3_read_only_policy   = true
  application_family    = var.application_family

  apply_server_side_encryption_by_default = {
    se_algorithm = "AES256"
  }

  bucket_policy_overrides = [
    data.aws_iam_policy_document.service_bucket_policy.json
  ]

  // Delete aborted multipart uploads after 7 days
  lifecycle_rules_abort_incomplete_multipart_upload_days = [
    {
      prefix  = "uploads"
      enabled = true
      days    = 7
    }
  ]

  bucket_cors_rule = [
    {
      allowed_headers = ["*"]
      allowed_methods = ["GET", "PUT", "POST", "DELETE", "HEAD"],
      allowed_origins = [
        "https://songwhip.com",
      ]
      expose_headers  = ["ETag"]
      max_age_seconds = 3000
    }
  ]
}

data "aws_route53_zone" "route53_zone" {
  name = "aws-prod.songwhip.com"
}

data "aws_acm_certificate" "certificate" {
  domain = "*.${data.aws_route53_zone.route53_zone.name}"
  types  = ["AMAZON_ISSUED"]
}

data "aws_iam_policy_document" "service_bucket_policy" {
  statement {
    sid = "DenyDestructiveActions"

    effect = "Deny"

    actions = [
      "s3:DeleteBucket",
      "s3:DeleteBucketPolicy",
    ]

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

    principals {
      type        = "*"
      identifiers = ["*"]
    }
  }

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

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

    condition {
      test     = "StringEquals"
      variable = "AWS:SourceArn"
      values = [
        aws_cloudfront_distribution.distribution.arn
      ]
    }

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

data "aws_cloudfront_response_headers_policy" "response_headers_policy" {
  name = "Managed-SimpleCORS"
}

data "aws_cloudfront_cache_policy" "cache_policy" {
  name = "Managed-CachingOptimized"
}

resource "aws_cloudfront_origin_access_control" "origin_access_control" {
  name                              = "${var.environment}-${var.service_name}"
  description                       = "${var.environment}-${var.service_name} Policy"
  origin_access_control_origin_type = "s3"
  signing_behavior                  = "always"
  signing_protocol                  = "sigv4"
}

resource "aws_cloudfront_distribution" "distribution" {
  # checkov:skip=CKV2_AWS_47:Ensure AWS CloudFront attached WAFv2 WebACL is configured with AMR for Log4j Vulnerability
  # checkov:skip=CKV_AWS_310:Ensure CloudFront distributions should have origin failover configured
  # checkov:skip=CKV_AWS_374:Ensure AWS CloudFront web distribution has geo restriction enabled

  enabled             = true
  is_ipv6_enabled     = false
  comment             = "Distribution Songwhip exclusive content"
  price_class         = "PriceClass_All"
  http_version        = "http2"
  aliases             = ["${var.bucket_domain}.aws-prod.songwhip.com"]
  web_acl_id          = module.songwhip_content_waf.waf_blocking_arn_output
  default_root_object = "index.html"

  origin {
    domain_name              = "${module.content_s3_bucket.s3_bucket_name_output}.s3.amazonaws.com"
    origin_id                = "S3-${module.content_s3_bucket.s3_bucket_name_output}"
    origin_access_control_id = aws_cloudfront_origin_access_control.origin_access_control.id
  }

  default_cache_behavior {
    viewer_protocol_policy = "https-only"
    compress               = true
    allowed_methods        = ["GET", "HEAD", "OPTIONS"]
    cached_methods         = ["GET", "HEAD"]

    response_headers_policy_id = data.aws_cloudfront_response_headers_policy.response_headers_policy.id
    cache_policy_id            = data.aws_cloudfront_cache_policy.cache_policy.id
    target_origin_id           = "S3-${module.content_s3_bucket.s3_bucket_name_output}"
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  logging_config {
    include_cookies = false
    bucket          = var.cloudfront_logs_bucket
  }

  viewer_certificate {
    acm_certificate_arn      = data.aws_acm_certificate.certificate.arn
    ssl_support_method       = "sni-only"
    minimum_protocol_version = "TLSv1.2_2021"
  }
}

module "songwhip_content_waf" {
  source            = "git@github.com:theorchard/terraform-aws-waf.git//?ref=2.0.0"
  environment       = var.environment
  service_name      = "${var.service_name}-cloudfront"
  aws_region        = var.region
  acl_scope         = "CLOUDFRONT"
  count_waf_enabled = false
  block_waf_enabled = true

  // Enabling this causes the error: "Error: WAFv2 RuleGroup not found for name: gsirt-ioc-rule-group"
  gsirt_ip_block_rule_group_enabled = false

  excluded_rules = [
    "SizeRestrictions_BODY",
  ]
}

resource "aws_route53_record" "route53_record" {
  name    = var.bucket_domain
  zone_id = data.aws_route53_zone.route53_zone.zone_id
  type    = "CNAME"
  ttl     = "60"
  records = [aws_cloudfront_distribution.distribution.domain_name]
}
