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          = "abacus"
}

provider "aws" {
  region = var.aws_region

  default_tags {
    tags = merge(
      {
        map-migrated = var.map_migrated_tag
        Name         = "${var.environment}-${var.service_name}"
      },
      module.default_tags.tags
    )
  }
}

# Terraform backends cannot contain interpolations
terraform {
  backend "s3" {
    bucket  = "qa-accounting-terraform-state"
    key     = "qa/slaughterhouse/terraform.tfstate"
    region  = "us-east-1"
    encrypt = "true"
  }
}

data "aws_caller_identity" "current" {}

data "aws_ec2_managed_prefix_list" "vpn_prefix_list" {
  name = "vpn-sme-internal-primary"
}

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

  environment = var.environment
}

# Getting AMI id
data "aws_ami" "debian_12" {
  most_recent = true

  owners = [
    "136693071363",
  ]

  filter {
    name = "virtualization-type"

    values = [
      "hvm",
    ]
  }

  filter {
    name   = "name"
    values = ["debian-12-amd64-*"]
  }

  filter {
    name   = "architecture"
    values = ["x86_64"]
  }
}

data "aws_acm_certificate" "certificate" {
  domain   = "*.${var.domain_name}"
  statuses = ["ISSUED"]
}

data "aws_s3_bucket" "lb_logs_bucket" {
  bucket = "qa-accounting-lb-logs"
}

# IAM policy document for ec2 instance's role
data "aws_iam_policy_document" "instance-assume-role-policy" {
  statement {
    actions = ["sts:AssumeRole"]

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

resource "aws_iam_role" "slaughterhouse_role" {
  name               = "${var.environment}-${var.service_name}-service-role"
  assume_role_policy = data.aws_iam_policy_document.instance-assume-role-policy.json
}

resource "aws_iam_instance_profile" "slaughterhouse_instance_profile" {
  name = "${var.environment}-${var.service_name}-instance-profile"
  role = aws_iam_role.slaughterhouse_role.name
}

resource "aws_security_group" "slaughterhouse_instance_sg" {
  name        = "${var.environment}-${var.service_name}-instance-sg"
  description = "Instance security group for ${var.environment}-${var.service_name}"
  vpc_id      = module.vpc_info.vpc_id
}

resource "aws_security_group_rule" "slaughterhouse_instance_ingress_sg_rule" {
  type              = "ingress"
  from_port         = 22
  to_port           = 22
  protocol          = "tcp"
  cidr_blocks       = var.ssh_cidr_blocks
  security_group_id = aws_security_group.slaughterhouse_instance_sg.id
}

resource "aws_security_group_rule" "allow_prefix_lists_ssh" {
  type              = "ingress"
  from_port         = 22
  to_port           = 22
  protocol          = "tcp"
  prefix_list_ids   = [
    data.aws_ec2_managed_prefix_list.vpn_prefix_list.id,
  ]
  security_group_id = aws_security_group.slaughterhouse_instance_sg.id
}

resource "aws_security_group_rule" "slaughterhouse_instance_sftp_nlb_sg_rule" {
  type                     = "ingress"
  from_port                = 22
  to_port                  = 22
  protocol                 = "tcp"
  source_security_group_id = aws_security_group.slaughterhouse_nlb_sg.id
  security_group_id        = aws_security_group.slaughterhouse_instance_sg.id
}

resource "aws_security_group_rule" "slaughterhouse_nlb_sftp_ingress_sg_rule" {
  type              = "ingress"
  from_port         = 22
  to_port           = 22
  protocol          = "tcp"
  cidr_blocks       = var.sftp_cidr_blocks
  security_group_id = aws_security_group.slaughterhouse_nlb_sg.id
}

resource "aws_security_group_rule" "slaughterhouse_instance_egress_sg_rule" {
  type              = "egress"
  from_port         = 0
  to_port           = 65535
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.slaughterhouse_instance_sg.id
}

resource "aws_security_group_rule" "slaughterhouse_instance_igress_lb_sg_rule" {
  type                     = "ingress"
  from_port                = 80
  to_port                  = 80
  protocol                 = "tcp"
  security_group_id        = aws_security_group.slaughterhouse_instance_sg.id
  source_security_group_id = aws_security_group.slaughterhouse_lb_sg.id
}

resource "aws_instance" "slaughterhouse_instance" {
  # checkov:skip=CKV_AWS_79:deemed not safe to enable, will be silenced globally
  ami                                  = data.aws_ami.debian_12.id
  instance_type                        = "t3.medium"
  key_name                             = var.aws_key_name
  monitoring                           = true
  subnet_id                            = module.vpc_info.default_private_subnet_ids[0]
  vpc_security_group_ids               = [aws_security_group.slaughterhouse_instance_sg.id]
  associate_public_ip_address          = false
  iam_instance_profile                 = aws_iam_instance_profile.slaughterhouse_instance_profile.name
  instance_initiated_shutdown_behavior = "stop"
  ebs_optimized                        = true
  disable_api_termination              = true
  user_data                            = module.slaughterhouse_bootstrap.user_data_output

  root_block_device {
    volume_type           = "gp3"
    volume_size           = 100
    delete_on_termination = false
    encrypted             = true
  }

  volume_tags = module.default_tags.tags

  lifecycle {
    ignore_changes = [
      ami,
      subnet_id,
      user_data,
    ]
  }
}

# Slaughterhouse load balancer security group
resource "aws_security_group" "slaughterhouse_lb_sg" {
  name        = "${var.environment}-${var.service_name}-lb-sg"
  description = "Security group for the ${var.environment}-${var.service_name} load balancer"
  vpc_id      =  module.vpc_info.vpc_id
}

# Slaughterhouse load balancer security group rules
resource "aws_security_group_rule" "slaughterhouse_nlb_sg_ingress_cidr_blocks_sg_rule" {
  description       = "Allow traffic to bacon slaughterhouse app"
  type              = "ingress"
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  cidr_blocks       = var.https_cidr_blocks
  security_group_id = aws_security_group.slaughterhouse_nlb_sg.id
}

resource "aws_security_group_rule" "slaughterhouse_nlb_sg_ingress_vpn_prefix_list_sg_rule" {
  description       = "Allow traffic to bacon slaughterhouse app"
  type              = "ingress"
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  prefix_list_ids   = [
    data.aws_ec2_managed_prefix_list.vpn_prefix_list.id,
  ]
  security_group_id = aws_security_group.slaughterhouse_nlb_sg.id
}

resource "aws_security_group_rule" "slaughterhouse_nlb_sg_ingress_sg_rule" {
  description              = "Allow traffic from the NLB to the ALB"
  type                     = "ingress"
  from_port                = 443
  to_port                  = 443
  protocol                 = "tcp"
  source_security_group_id = aws_security_group.slaughterhouse_nlb_sg.id
  security_group_id        = aws_security_group.slaughterhouse_lb_sg.id
}

resource "aws_security_group_rule" "slaughterhouse_lb_sg_egress_sg_rule" {
  type                     = "egress"
  from_port                = 80
  to_port                  = 80
  protocol                 = "tcp"
  source_security_group_id = aws_security_group.slaughterhouse_instance_sg.id
  security_group_id        = aws_security_group.slaughterhouse_lb_sg.id
}

# Slaughterhouse load balancer
resource "aws_lb" "slaughterhouse_lb" {
  name                       = "${var.environment}-${var.service_name}-lb"
  internal                   = true
  load_balancer_type         = "application"
  enable_deletion_protection = true
  security_groups            = [aws_security_group.slaughterhouse_lb_sg.id]
  subnets                    = slice(module.vpc_info.default_private_subnet_ids, 0, 2)

  access_logs {
    enabled = true
    bucket  = data.aws_s3_bucket.lb_logs_bucket.id
    prefix  = "${data.aws_caller_identity.current.account_id}/${var.environment}-${var.service_name}-lb"
  }

  lifecycle {
    ignore_changes = [
      subnets,
    ]
  }
}

# Only server HTTPS
resource "aws_lb_listener" "slaughterhouse_alb_listener" {
  load_balancer_arn = aws_lb.slaughterhouse_lb.arn
  port              = "443"
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-TLS13-1-3-2021-06"
  certificate_arn   = data.aws_acm_certificate.certificate.arn

  default_action {
    target_group_arn = aws_lb_target_group.slaughterhouse_target_group.arn
    type             = "forward"
  }
}

# Create the target group consisting of a single slaunghterhouse instance.
resource "aws_lb_target_group" "slaughterhouse_target_group" {
  name        = aws_lb.slaughterhouse_lb.name
  port        = 80
  protocol    = "HTTP"
  vpc_id      =  module.vpc_info.vpc_id
  target_type = "instance"

  health_check {
    enabled             = true
    healthy_threshold   = 3
    interval            = 10
    matcher             = "200-299,301"
    path                = "/healthchk.html"
    port                = "traffic-port"
    protocol            = "HTTP"
    timeout             = 5
    unhealthy_threshold = 5
  }
}

resource "aws_lb_target_group_attachment" "slaughterhouse_target_group_attachment" {
  target_group_arn = aws_lb_target_group.slaughterhouse_target_group.arn
  target_id        = aws_instance.slaughterhouse_instance.id
  port             = 80
}

# Slaughterhouse network load balancer security group
resource "aws_security_group" "slaughterhouse_nlb_sg" {
  name        = "${var.environment}-${var.service_name}-nlb-sg"
  description = "Security group for the ${var.environment}-${var.service_name} network load balancer"
  vpc_id      =  module.vpc_info.vpc_id
}

resource "aws_security_group_rule" "slaughterhouse_nlb_to_instance_sftp_egress_rule" {
  type                     = "egress"
  from_port                = 22
  to_port                  = 22
  protocol                 = "tcp"
  source_security_group_id = aws_security_group.slaughterhouse_instance_sg.id
  security_group_id        = aws_security_group.slaughterhouse_nlb_sg.id
}

resource "aws_security_group_rule" "slaughterhouse_nlb_to_alb_https_egress_rule" {
  description              = "Allow traffic from the NLB to the ALB"
  type                     = "egress"
  from_port                = 443
  to_port                  = 443
  protocol                 = "tcp"
  source_security_group_id = aws_security_group.slaughterhouse_lb_sg.id
  security_group_id        = aws_security_group.slaughterhouse_nlb_sg.id
}

# Network load balancer for slaughterhouse. This will be used for multiple target groups to route traffic to sftp and web app.
resource "aws_lb" "slaughterhouse_nlb" {
  name                             = "${var.environment}-${var.service_name}-nlb"
  internal                         = true
  load_balancer_type               = "network"
  idle_timeout                     = "10"
  enable_deletion_protection       = true
  enable_cross_zone_load_balancing = true
  security_groups                  = [aws_security_group.slaughterhouse_nlb_sg.id]

  subnets = slice(module.vpc_info.default_private_subnet_ids, 0, 2)

  access_logs {
    enabled = true
    bucket  = data.aws_s3_bucket.lb_logs_bucket.id
    prefix  = "${data.aws_caller_identity.current.account_id}/${var.environment}-${var.service_name}-nlb"
  }
}

# NLB target group for SFTP access
resource "aws_lb_target_group" "slaughterhouse_sftp_nlb_target_group" {
  name        = "${aws_lb.slaughterhouse_nlb.name}-sftp"
  port        = 22
  protocol    = "TCP"
  target_type = "instance"
  vpc_id      = module.vpc_info.vpc_id

  health_check {
    port                = "traffic-port"
    protocol            = "TCP"
    healthy_threshold   = "3"
    unhealthy_threshold = "3"
    interval            = "10"
  }
  deregistration_delay = "300"

  depends_on = [
    aws_lb.slaughterhouse_nlb
  ]
}

resource "aws_lb_listener" "slaughterhouse_sftp_ssh_tcp" {
  load_balancer_arn = aws_lb.slaughterhouse_nlb.id
  port              = "22"
  protocol          = "TCP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.slaughterhouse_sftp_nlb_target_group.id
  }
}

# Add the instance to the NLB target group
resource "aws_lb_target_group_attachment" "slaughterhouse_sftp_nlb_target_group_attachment" {
  target_group_arn = aws_lb_target_group.slaughterhouse_sftp_nlb_target_group.arn
  target_id        = aws_instance.slaughterhouse_instance.id
  port             = 22
}

# NLB target group for slaughterhouse web app access
resource "aws_lb_target_group" "slaughterhouse_webapp_nlb_target_group" {
  name        = "${aws_lb.slaughterhouse_nlb.name}-webapp"
  port        = 443
  protocol    = "TCP"
  target_type = "alb"
  vpc_id      = module.vpc_info.vpc_id

  health_check {
    port                = "traffic-port"
    matcher             = "200-299,301"
    protocol            = "HTTPS"
    healthy_threshold   = "3"
    unhealthy_threshold = "3"
    interval            = "10"
  }
  deregistration_delay = "300"

  depends_on = [
    aws_lb.slaughterhouse_nlb
  ]
}

# NLB listener for slaughterhouse web app access
resource "aws_lb_listener" "slaughterhouse_sftp_nlb_webapp_listner" {
  load_balancer_arn = aws_lb.slaughterhouse_nlb.id
  port              = "443"
  protocol          = "TCP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.slaughterhouse_webapp_nlb_target_group.id
  }
}

# Add the ALB to the NLB target group
resource "aws_lb_target_group_attachment" "slaughterhouse_webapp_nlb_target_group_attachment" {
  target_group_arn = aws_lb_target_group.slaughterhouse_webapp_nlb_target_group.arn
  target_id        = aws_lb.slaughterhouse_lb.id
  port             = 443
}

module "slaughterhouse_bootstrap" {
  source = "git@github.com:theorchard/terraform-chef-bootstrap.git?ref=3.1.2"

  chef_role         = "${var.environment}_apache_slaughterhouse_server"
  aws_instance_name = "${var.environment}-${var.service_name}"
  aws_iam_role_id   = aws_iam_role.slaughterhouse_role.id
}
