provider "aws" {
  profile = var.profile
  region  = var.region_id

  default_tags {
    tags = {
      application_family = "delphi"
    }
  }
}

provider "aws" {
  alias = "eu-west-1"

  profile = var.profile
  region  = "eu-west-1"

}

locals {
  aws_elb_account_id = module.elb_account_ids.elb_account_ids[var.region_id]
  allowed_roles = [
    module.cross_account_deployment_role.role.name,
    module.cross_account_terraform_role.role.name,
    "admin"
  ]
  account_id = data.aws_caller_identity.current.account_id
}

data "aws_caller_identity" "current" {}

module "elb_account_ids" {
  source = "../../../../modules/elb_account_ids"
}

module "backend" {
  source             = "../../../../modules/backend"
  name_prefix        = var.name_prefix
  common_tags        = var.common_tags
  allowed_roles      = concat(var.allowed_roles, local.allowed_roles)
  allowed_accounts   = keys(var.admin_users)
  env_prefix         = "dev"
  aws_elb_account_id = local.aws_elb_account_id
}

module "access_policies_documents" {
  source             = "../../../../modules/iam/policies/iam_access_policies_documents"
  require_mfa        = false
  application_family = "delphi"
}

// Deployment policies
module "deployment_policies" {
  source      = "../../../../modules/iam/policies/deployment"
  name_prefix = "dev-delphi"
}

module "s3_deployment_policy" {
  source = "../../../../modules/iam/policies/s3/buckets_rw"

  name        = "s3_deploy_policy"
  name_prefix = "dev-delphi"

  bucket_masks = [
    "*-delphi-etl-artifacts",
    "*-delphi-configs",
    "*-delphi-autotests",
  ]
}

locals {
  additional_deployment_policies = concat(
    formatlist("%s-delphi-secrets-deployment-ro", ["dev", "qa", "stage"]),
    ["jenkins-infra-secrets-services-ro"]
  )
}

data "aws_iam_policy" "additional_deployment_policies" {
  for_each = toset(local.additional_deployment_policies)
  name     = each.value
}

//

module "aws_accounts_list" {
  source = "../../../../modules/iam/aws_accounts_list"
}

resource "aws_s3_bucket" "logs" {
  provider = aws.eu-west-1
  bucket   = "security-${local.account_id}-eu-west-1-logs"
  tags     = var.common_tags
}

resource "aws_s3_bucket_acl" "logs" {
  provider = aws.eu-west-1
  bucket   = aws_s3_bucket.logs.id
  acl      = "private"
}

resource "aws_s3_bucket_policy" "logs" {
  # https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/enable-access-logs.html
  provider = aws.eu-west-1
  bucket   = aws_s3_bucket.logs.id
  policy   = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowSSLRequestsOnly",
      "Effect": "Deny",
      "Principal": {
        "AWS": "*"
      },
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::security-${local.account_id}-eu-west-1-logs/*",
        "arn:aws:s3:::security-${local.account_id}-eu-west-1-logs"
      ],
      "Condition": {
        "Bool": {
          "aws:SecureTransport": "false"
        }
      }
    },
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::${module.elb_account_ids.elb_account_ids["eu-west-1"]}:root"
      },
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::security-${local.account_id}-eu-west-1-logs/elb/*"
    },
    {
      "Sid": "S3ServerAccessLogsPolicy",
      "Effect": "Allow",
      "Principal": {
        "Service": "logging.s3.amazonaws.com"
      },
      "Action": [
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::security-${local.account_id}-eu-west-1-logs/s3/*",
      "Condition": {
        "StringEquals": {
          "aws:SourceAccount": "${local.account_id}"
        }
      }
    },
    {
      "Sid": "AWSLogDeliveryCheck",
      "Effect": "Allow",
      "Principal": {
        "Service": "delivery.logs.amazonaws.com"
      },
      "Action": ["s3:GetBucketAcl", "s3:ListBucket"],
      "Resource": "arn:aws:s3:::security-${local.account_id}-eu-west-1-logs",
      "Condition": {
        "StringEquals": {
          "aws:SourceAccount": "${local.account_id}"
        }
      }
    }
  ]
}
POLICY
}

resource "aws_s3_bucket_server_side_encryption_configuration" "logs" {
  provider = aws.eu-west-1
  bucket   = aws_s3_bucket.logs.id
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

resource "aws_s3_bucket_lifecycle_configuration" "logs" {
  provider = aws.eu-west-1
  bucket   = aws_s3_bucket.logs.id
  rule {
    id     = "${var.name_prefix}-logs"
    status = "Enabled"

    expiration {
      days = 90
    }
  }
}

resource "aws_s3_bucket_public_access_block" "logs" {
  provider = aws.eu-west-1
  bucket   = aws_s3_bucket.logs.id

  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

resource "aws_iam_policy" "self_credentials_management" {
  name        = "self_credentials_management"
  path        = "/"
  description = "Allows an IAM user to manage their own Service Specific Credentials."
  policy      = module.access_policies_documents.self_credentials_management_policy_json
}

resource "aws_iam_policy" "read_only" {
  name        = "read_only"
  path        = "/"
  description = "Provides read-only access to AWS services and resources."
  policy      = module.access_policies_documents.read_only_policy_json
}

resource "aws_iam_policy" "power_users" {
  name        = "power_users"
  path        = "/"
  description = "Provides full access to AWS services and resources, with some restrictions."
  policy      = module.access_policies_documents.power_user_policy_json
}

resource "aws_iam_policy" "qa_users" {
  name        = "qa_users"
  path        = "/"
  description = "Provides read-only access to AWS services and resources with some additional permissions."
  policy      = module.access_policies_documents.qa_user_policy_json
}

resource "aws_iam_group" "admin_group" {
  name = "admins"
}

resource "aws_iam_group_policy_attachment" "admin_group_administrator_access" {
  group      = aws_iam_group.admin_group.name
  policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}

module "admin_users" {
  source    = "../../../../modules/iam/aws_users"
  iam_users = var.admin_users
}

module "cross_account_developer_role" {
  source               = "../../../../modules/iam/roles/cross_account_role"
  name                 = "cross_account_developer"
  common_tags          = var.common_tags
  require_mfa          = true
  max_session_duration = 43200
  principal_list = formatlist("arn:aws:iam::%s:root", [
    module.aws_accounts_list.accounts["gdb-infra-dev"],
    module.aws_accounts_list.accounts["the-orchard-prod"],
  ])
  policies_list = [
    aws_iam_policy.power_users.arn,
    aws_iam_policy.read_only.arn,
  ]
}

module "cross_account_support_role" {
  source               = "../../../../modules/iam/roles/cross_account_role"
  name                 = "cross_account_support"
  common_tags          = var.common_tags
  require_mfa          = true
  max_session_duration = 43200
  principal_list = formatlist("arn:aws:iam::%s:root", [
    module.aws_accounts_list.accounts["gdb-infra-dev"],
    module.aws_accounts_list.accounts["the-orchard-prod"],
  ])
  policies_list = [aws_iam_policy.qa_users.arn]
}

module "cross_account_qa_role" {
  source               = "../../../../modules/iam/roles/cross_account_role"
  name                 = "cross_account_qa"
  common_tags          = var.common_tags
  require_mfa          = true
  max_session_duration = 43200
  principal_list = formatlist("arn:aws:iam::%s:root", [
    module.aws_accounts_list.accounts["gdb-infra-dev"],
    module.aws_accounts_list.accounts["the-orchard-prod"],
  ])
  policies_list = [aws_iam_policy.qa_users.arn]
}

module "cross_account_user_role" {
  source               = "../../../../modules/iam/roles/cross_account_role"
  name                 = "cross_account_user"
  common_tags          = var.common_tags
  require_mfa          = true
  max_session_duration = 43200
  principal_list = formatlist("arn:aws:iam::%s:root", [
    module.aws_accounts_list.accounts["gdb-infra-dev"],
    module.aws_accounts_list.accounts["the-orchard-prod"],
  ])
  policies_list = [aws_iam_policy.read_only.arn]
}

module "cross_account_deployment_role" {
  source      = "../../../../modules/iam/roles/cross_account_role"
  name        = "cross_account_deployment_role"
  common_tags = var.common_tags
  require_mfa = false
  principal_list = [
    format("arn:aws:iam::%s:role/dev-infra-jenkins_ec2_agent_role", module.aws_accounts_list.accounts["gdb-infra-dev"]),
  ]
  policies_list = concat([
    module.deployment_policies.lambda_deployment_policy.arn,
    module.deployment_policies.step_functions_deployment_policy.arn,
    module.deployment_policies.cloudfront_deployment_policy.arn,
    module.deployment_policies.ecs_deployment_policy.arn,
    module.s3_deployment_policy.policy.arn,
  ], [for policy in data.aws_iam_policy.additional_deployment_policies : policy.arn])
}

module "cross_account_autotest_role" {
  source               = "../../../../modules/iam/roles/cross_account_role"
  name                 = "cross_account_autotest_role"
  max_session_duration = 28800
  common_tags          = var.common_tags
  require_mfa          = false
  principal_list = [
    format("arn:aws:iam::%s:role/dev-infra-jenkins_ec2_agent_role", module.aws_accounts_list.accounts["gdb-infra-dev"]),
  ]
}

module "cross_account_terraform_role" {
  source      = "../../../../modules/iam/roles/cross_account_role"
  name        = "cross_account_terraform_role"
  common_tags = var.common_tags
  require_mfa = false
  principal_list = [
    format("arn:aws:iam::%s:role/dev-infra-jenkins_ec2_terraform_agent_role", module.aws_accounts_list.accounts["gdb-infra-dev"]),
    format("arn:aws:iam::%s:role/dev-infra-atlantis_task_role", module.aws_accounts_list.accounts["gdb-infra-dev"]),
  ]
  policies_list = formatlist(
    "arn:aws:iam::%s:policy/%s",
    local.account_id,
    [
      "dev-shared-atlantis-apply-part-one-policy",
      "dev-shared-atlantis-apply-part-two-policy",
      "dev-shared-atlantis-invoke-lambdas-policy",
      "dev-shared-atlantis-kms-delete-policy",
      "dev-shared-atlantis-kms-reencrypt-policy",
      "dev-shared-atlantis-secrets-read-policy",
      "dev-shared-atlantis-terrastate-policy",
      "dev-shared-atlantis-tf-infra-core-apply-policy",
    ]
  )
}

module "datatheoreme_security_audit_role" {
  source      = "../../../../modules/iam/roles/datatheoreme_security_audit"
  externam_id = var.datatheorem_externam_id
  common_tags = var.common_tags
}

# Role for grafana to collect cloudWatch metrics
module "cross_account_monitoring_role" {
  source               = "../../../../modules/iam/roles/cross_account_role"
  name                 = "cross_account_monitoring_role"
  require_mfa          = false
  max_session_duration = 43200
  common_tags          = var.common_tags
  principal_list = [
    "arn:aws:iam::${module.aws_accounts_list.accounts.gdb-infra-dev}:root",
    "arn:aws:iam::${module.aws_accounts_list.accounts.gdb-infra-dev}:role/dev-infra-ecs_task_with_cloudwatch_access_role",
  ]
  policies_list = [
    aws_iam_policy.cloudwatch_read.arn
  ]
}

data "aws_iam_policy_document" "cloudwatch_read_policy" {
  version = "2012-10-17"
  statement {
    sid    = "AllowReadCloudWatch"
    effect = "Allow"
    actions = [
      "cloudwatch:Describe*",
      "cloudwatch:List*",
      "cloudwatch:Get*",
    ]
    resources = [
      "*"
    ]
  }
  statement {
    sid    = "AllowReadingLogsFromCloudWatch"
    effect = "Allow"
    actions = [
      "logs:DescribeLogGroups",
      "logs:GetLogGroupFields",
      "logs:StartQuery",
      "logs:StopQuery",
      "logs:GetQueryResults",
      "logs:GetLogEvents"
    ]
    resources = [
      "*"
    ]
  }
  statement {
    sid     = "AllowReadingResourcesForTags"
    effect  = "Allow"
    actions = ["tag:GetResources"]
    resources = [
      "*"
    ]
  }
  statement {
    sid     = "AllowReadingTagsInstancesRegionsFromEC2"
    effect  = "Allow"
    actions = ["ec2:DescribeTags", "ec2:DescribeInstances", "ec2:DescribeRegions"]
    resources = [
      "*"
    ]
  }
  statement {
    sid     = "AllowReadingTagsServicesRegionsFromECS"
    effect  = "Allow"
    actions = ["ecs:Describe*", "ecs:List", "ecs:Get*"]
    resources = [
      "*"
    ]
  }
}

resource "aws_iam_policy" "cloudwatch_read" {
  name        = "grafana-cloudwatch"
  path        = "/"
  description = "Allows Read access to CloudWatch."

  policy = data.aws_iam_policy_document.cloudwatch_read_policy.json
}

# Table for state locks
resource "aws_dynamodb_table" "dynamodb-terraform-state-lock" {
  name         = "terraform-state-lock-dynamodb"
  hash_key     = "LockID"
  billing_mode = "PAY_PER_REQUEST"

  server_side_encryption {
    enabled     = true
    kms_key_arn = module.backend.tf_kms_key_alias.arn
  }

  attribute {
    name = "LockID"
    type = "S"
  }

  tags = merge(
    var.common_tags,
    { "Name" = "DynamoDB Terraform State Lock Table" },
  )

  lifecycle {
    ignore_changes = [server_side_encryption[0].kms_key_arn]
  }
}

module "ecs_stopped_task_events" {
  source = "../../../../modules/ecs_task_events_logging"
}
