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

provider "aws" {
  region = var.aws_region

  default_tags {
    tags = module.default_tags.tags
  }
}

locals {
  # EKS cannot change the control plane AZ set after cluster creation.
  # Keep the cluster pinned to the original private subnets used at creation.
  eks_cluster_subnet_ids = [
    "subnet-44c19a21",
    "subnet-0285b8fc992cfc35a",
    "subnet-b649dfef",
  ]
}

module "vpc_info" {
  source = "git@github.com:theorchard/terraform-vpc-info.git?ref=3.1.0"

  environment = var.environment
}

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "21.15.1"

  #checkov:skip=CKV_AWS_38:EKS public endpoint is disabled; Checkov flags the module default public CIDRs even when endpoint_public_access is false.
  #checkov:skip=CKV_AWS_58:EKS secrets encryption is configured below; this is a false positive on the upstream module's dynamic block.
  #checkov:skip=CKV_AWS_339:EKS 1.35 is AWS-supported; the Checkov rule allowlist is outdated in the current CI version.
  #checkov:skip=CKV_AWS_111:This IPv4 cluster does not create the optional IPv6 CNI policy; Checkov is scanning an unused upstream module document.

  name               = var.cluster_name
  kubernetes_version = var.cluster_version
  enabled_log_types  = ["api", "audit", "authenticator", "controllerManager", "scheduler"]

  cloudwatch_log_group_retention_in_days = 365

  encryption_config = {
    resources = ["secrets"]
  }

  kms_key_administrators = [
    "arn:aws:iam::103233932089:role/admin",
    "arn:aws:iam::103233932089:role/cross-account-atlantis-role",
  ]

  upgrade_policy = {
    support_type = "STANDARD"
  }

  vpc_id                   = module.vpc_info.vpc_id
  subnet_ids               = local.eks_cluster_subnet_ids
  control_plane_subnet_ids = local.eks_cluster_subnet_ids

  endpoint_public_access  = false
  endpoint_private_access = true

  security_group_tags = {
    "eiso-exception" = "aws.08.30"
  }

  node_security_group_tags = {
    "eiso-exception" = "aws.08.30"
  }

  security_group_additional_rules = {
    ingress_vpn_sme = {
      description     = "Ingress from VPN SME"
      protocol        = "tcp"
      from_port       = 443
      to_port         = 443
      type            = "ingress"
      prefix_list_ids = ["pl-03681d02cb997bcb2"]
    }
    ingress_vpn_ny = {
      description     = "Ingress from VPN NY"
      protocol        = "tcp"
      from_port       = 443
      to_port         = 443
      type            = "ingress"
      prefix_list_ids = ["pl-01fb88cf631af4011"]
    }
  }

  compute_config = {
    enabled    = true
    node_pools = ["general-purpose", "system"]
  }


  enable_irsa = true

  enable_cluster_creator_admin_permissions = false

  access_entries = {
    admin_role = {
      principal_arn = "arn:aws:iam::103233932089:role/admin"

      policy_associations = {
        admin = {
          policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
          access_scope = {
            type = "cluster"
          }
        }
      }
    }
  }

  tags = local.combined_resource_tags
}

module "lb_controller_irsa" {
  source  = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts"
  version = "~> 6.4.0"

  #checkov:skip=CKV_AWS_109:Checkov is scanning broad optional policy documents inside the shared upstream IRSA module, not custom policy statements in this configuration.
  #checkov:skip=CKV_AWS_111:Checkov is scanning broad optional policy documents inside the shared upstream IRSA module, not custom policy statements in this configuration.

  name                                   = "stripo-eks-dev-lb-controller"
  attach_load_balancer_controller_policy = true

  oidc_providers = {
    ex = {
      provider_arn               = module.eks.oidc_provider_arn
      namespace_service_accounts = ["kube-system:aws-load-balancer-controller"]
    }
  }
}

data "aws_caller_identity" "current" {}

data "aws_ec2_managed_prefix_list" "dev_private_subnets" {
  filter {
    name   = "prefix-list-name"
    values = ["dev-orcd-private-subnet-prefix-list"]
  }
}

data "aws_ec2_managed_prefix_list" "shared_dev_box_private_subnets" {
  filter {
    name   = "prefix-list-name"
    values = ["shared-orcd-dev-box-private-subnet-prefix-list"]
  }
}

data "aws_ec2_managed_prefix_list" "vpn_ny_users" {
  filter {
    name   = "prefix-list-name"
    values = ["vpn-ny-users"]
  }
}

data "aws_ec2_managed_prefix_list" "fansifter_qa_private_subnets" {
  filter {
    name   = "prefix-list-name"
    values = ["qa-fansifter-private-subnet-prefix-list"]
  }
}

resource "aws_security_group" "lb_sg" {
  name        = "${var.cluster_name}-lb-sg"
  description = "Security group for the Application Load Balancer"
  vpc_id      = module.vpc_info.vpc_id

  ingress {
    from_port       = 80
    to_port         = 80
    protocol        = "tcp"
    prefix_list_ids = ["pl-03681d02cb997bcb2", "pl-01fb88cf631af4011"]
    description     = "Allow HTTP from VPN"
  }

  ingress {
    from_port       = 443
    to_port         = 443
    protocol        = "tcp"
    prefix_list_ids = ["pl-03681d02cb997bcb2", "pl-01fb88cf631af4011"]
    description     = "Allow HTTPS from VPN"
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = merge(
    local.combined_resource_tags,
    {
      "eiso-exception" = "aws.08.30"
    }
  )
}

resource "aws_security_group" "stripo_ingress_lb_sg" {
  name        = "${var.cluster_name}-stripo-ingress-lb-sg"
  description = "Security group for the Stripo V2 Application Load Balancer"
  vpc_id      = module.vpc_info.vpc_id

  ingress {
    from_port = 80
    to_port   = 80
    protocol  = "tcp"
    prefix_list_ids = [
      data.aws_ec2_managed_prefix_list.dev_private_subnets.id,
      data.aws_ec2_managed_prefix_list.shared_dev_box_private_subnets.id,
      data.aws_ec2_managed_prefix_list.vpn_ny_users.id,
      data.aws_ec2_managed_prefix_list.fansifter_qa_private_subnets.id,
    ]
    description = "Allow HTTP from dev, dev-box, fansifter-qa, and VPN NY users"
  }

  ingress {
    from_port = 443
    to_port   = 443
    protocol  = "tcp"
    prefix_list_ids = [
      data.aws_ec2_managed_prefix_list.dev_private_subnets.id,
      data.aws_ec2_managed_prefix_list.shared_dev_box_private_subnets.id,
      data.aws_ec2_managed_prefix_list.vpn_ny_users.id,
      data.aws_ec2_managed_prefix_list.fansifter_qa_private_subnets.id,
    ]
    description = "Allow HTTPS from dev, dev-box, fansifter-qa, and VPN NY users"
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = merge(
    local.combined_resource_tags,
    {
      "Name"           = "${var.cluster_name}-stripo-ingress-lb-sg"
      "eiso-exception" = "aws.08.30"
    }
  )
}

resource "aws_security_group_rule" "cluster_allow_stripo_ingress_lb" {
  type                     = "ingress"
  from_port                = 0
  to_port                  = 65535
  protocol                 = "tcp"
  security_group_id        = module.eks.node_security_group_id
  source_security_group_id = aws_security_group.stripo_ingress_lb_sg.id
  description              = "Allow traffic from the Stripo V2 ALB to EKS nodes"
}

resource "aws_security_group_rule" "cluster_allow_lb" {
  type                     = "ingress"
  from_port                = 0
  to_port                  = 65535
  protocol                 = "tcp"
  security_group_id        = module.eks.node_security_group_id
  source_security_group_id = aws_security_group.lb_sg.id
  description              = "Allow traffic from ALB to EKS nodes"
}

resource "aws_ec2_tag" "primary_cluster_sg_exception" {
  resource_id = module.eks.cluster_primary_security_group_id
  key         = "eiso-exception"
  value       = "aws.08.30,aws.08.36"
}

data "aws_lb" "argocd" {
  tags = {
    "elbv2.k8s.aws/cluster" = var.cluster_name
    "ingress.k8s.aws/stack" = "argocd/argocd-server"
  }
}

data "aws_lb" "stripo_v2" {
  tags = {
    "elbv2.k8s.aws/cluster" = var.cluster_name
    "ingress.k8s.aws/stack" = "stripo-v2"
  }
}

data "aws_route53_zone" "dev" {
  name         = "dev.theorchard.io."
  private_zone = false
}

data "aws_acm_certificate" "certificate" {
  domain      = "*.dev.theorchard.io"
  statuses    = ["ISSUED"]
  most_recent = true
}

resource "aws_route53_record" "argocd" {
  zone_id = data.aws_route53_zone.dev.zone_id
  name    = "argocd-stripo.dev.theorchard.io"
  type    = "A"

  alias {
    name                   = data.aws_lb.argocd.dns_name
    zone_id                = data.aws_lb.argocd.zone_id
    evaluate_target_health = true
  }
}

resource "aws_route53_record" "stripo_v2_api_gateway" {
  zone_id = data.aws_route53_zone.dev.zone_id
  name    = "dev-stripo-v2-api-gateway.dev.theorchard.io"
  type    = "A"

  alias {
    name                   = data.aws_lb.stripo_v2.dns_name
    zone_id                = data.aws_lb.stripo_v2.zone_id
    evaluate_target_health = true
  }
}

resource "aws_route53_record" "stripo_v2_assets" {
  zone_id = data.aws_route53_zone.dev.zone_id
  name    = "dev-stripo-v2-assets.dev.theorchard.io"
  type    = "CNAME"
  ttl     = "60"
  records = [aws_cloudfront_distribution.editor_assets.domain_name]
}

resource "aws_route53_record" "stripo_v2_coediting" {
  zone_id = data.aws_route53_zone.dev.zone_id
  name    = "dev-stripo-v2-coediting.dev.theorchard.io"
  type    = "A"

  alias {
    name                   = data.aws_lb.stripo_v2.dns_name
    zone_id                = data.aws_lb.stripo_v2.zone_id
    evaluate_target_health = true
  }
}

module "external_secrets_irsa" {
  source  = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts"
  version = "~> 6.4.0"

  #checkov:skip=CKV_AWS_109:Checkov is reporting optional upstream policy documents from the shared IRSA module rather than this scoped External Secrets policy.
  #checkov:skip=CKV_AWS_111:Checkov is reporting optional upstream policy documents from the shared IRSA module rather than this scoped External Secrets policy.

  name                                = "stripo-eks-dev-external-secrets"
  use_name_prefix                     = false
  attach_external_secrets_policy      = true
  external_secrets_ssm_parameter_arns = ["arn:aws:ssm:${var.aws_region}:103233932089:parameter/${var.environment}/${var.service_name}*"]
  external_secrets_secrets_manager_arns = [
    "arn:aws:secretsmanager:${var.aws_region}:103233932089:secret:${var.environment}/${var.service_name}*",
    "arn:aws:secretsmanager:${var.aws_region}:103233932089:secret:${var.environment}/datadog*",
  ]

  oidc_providers = {
    ex = {
      provider_arn               = module.eks.oidc_provider_arn
      namespace_service_accounts = ["external-secrets:external-secrets"]
    }
  }
}

module "documents_service_irsa" {
  source  = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts"
  version = "~> 6.4.0"

  #checkov:skip=CKV_AWS_109:Checkov is scanning optional upstream policy documents inside the shared IRSA module; this role only attaches the custom documents-service S3 policy.
  #checkov:skip=CKV_AWS_111:Checkov is scanning optional upstream policy documents inside the shared IRSA module; this role only attaches the custom documents-service S3 policy.

  name            = "${var.cluster_name}-documents-service"
  use_name_prefix = false

  policies = {
    s3_access = aws_iam_policy.documents_service_s3.arn
  }

  oidc_providers = {
    ex = {
      provider_arn               = module.eks.oidc_provider_arn
      namespace_service_accounts = ["stripo:stripo-plugin-documents-service"]
    }
  }
}

resource "aws_iam_policy" "documents_service_s3" {
  name        = "${var.environment}-${var.service_name}-documents-service-s3"
  description = "S3 and KMS access for stripo-plugin-documents-service"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "s3:GetObject",
          "s3:GetObject*",
          "s3:PutObject",
          "s3:PutObject*",
          "s3:DeleteObject",
          "s3:DeleteObject*",
        ]
        Resource = "${module.s3_bucket.s3_bucket_arn_output}/*"
      },
      {
        Effect = "Allow"
        Action = [
          "s3:GetBucketLocation",
          "s3:ListBucket",
        ]
        Resource = module.s3_bucket.s3_bucket_arn_output
      },
      {
        Effect = "Allow"
        Action = [
          "kms:Decrypt",
          "kms:Encrypt",
          "kms:GenerateDataKey*",
        ]
        Resource = module.s3_bucket.s3_kms_encryption_key_arn_output
      },
    ]
  })

  tags = local.combined_resource_tags
}


