# =============================================================================
# IAM — ported from basic/aws/cloudformation/iam.yaml and basic/aws/policies/
#
# 4 customer managed policies (documents kept verbatim under ./policies) and
# 8 IRSA roles. Trust policies reference the EKS OIDC provider; the OIDCIssuer
# CloudFormation parameter maps to module.eks.cluster_oidc_issuer_url.
# =============================================================================

locals {
  oidc_issuer = replace(module.eks.cluster_oidc_issuer_url, "https://", "")
}

# =============================================================================
# Customer managed policies
#
# These 4 policy names carry no cluster suffix — they are ACCOUNT-LEVEL SHARED
# resources, reused by every o11y region in the account. Mirroring the old
# basic/iam script (get-policy -> skip creation; the old finalizers never
# delete them), they are ensured out-of-band here: created if missing, never
# updated, never destroyed. This avoids EntityAlreadyExists on accounts that
# already ran the legacy flow (or host a second region), and avoids wiping the
# permissions of sibling regions on destroy.
# =============================================================================

locals {
  shared_policy_names = [
    "aws-cluster-auto-scaler",
    "aws-load-balancer-controller",
    "external-dns",
    "regional-server-iam",
  ]
  shared_policy_arns = {
    for name in local.shared_policy_names :
    name => "arn:aws:iam::${local.o11y_account}:policy/${name}"
  }
}

resource "null_resource" "shared_iam_policies" {
  triggers = {
    aws_profile = local.o11y_account
    policy_dir  = "${path.module}/policies"
    policy_arns = join(" ", values(local.shared_policy_arns))
  }

  provisioner "local-exec" {
    when        = create
    interpreter = ["bash", "-c"]
    command     = <<-EOT
      set -euo pipefail
      for policy_arn in ${self.triggers.policy_arns}; do
        policy_name=$${policy_arn##*/}
        if aws iam get-policy --profile ${self.triggers.aws_profile} --policy-arn "$policy_arn" > /dev/null 2>&1; then
          echo "Policy $policy_name already exists. Skipping creation."
        else
          echo "Creating policy $policy_name ..."
          aws iam create-policy --profile ${self.triggers.aws_profile} \
            --policy-name "$policy_name" \
            --policy-document "file://${self.triggers.policy_dir}/$policy_name.json"
        fi
      done
    EOT
  }

  # No destroy provisioner on purpose: the policies are shared across regions.
}

# =============================================================================
# IRSA assume-role policy documents
# =============================================================================

# Shared document builder: one statement per service-account subject.
# test: StringEquals or StringLike; with_aud: whether to pin :aud = sts.amazonaws.com
locals {
  # role name suffix -> trust configuration (ported one-by-one from iam.yaml)
  irsa_roles = {
    alb-controller = {
      test     = "StringEquals"
      subjects = ["system:serviceaccount:kube-system:aws-load-balancer-controller"]
      with_aud = false
    }
    external-dns = {
      test     = "StringEquals"
      subjects = ["system:serviceaccount:kube-system:external-dns"]
      with_aud = false
    }
    aws-ca = {
      test     = "StringEquals"
      subjects = ["system:serviceaccount:kube-system:cluster-autoscaler"]
      with_aud = false
    }
    regional-server = {
      test = "StringLike"
      subjects = [
        "system:serviceaccount:observability:*",
        "system:serviceaccount:ops-system:ops-server",
      ]
      with_aud = true
    }
    loki = {
      test     = "StringEquals"
      subjects = ["system:serviceaccount:observability:loki-ha"]
      with_aud = true
    }
    vmbackup = {
      test     = "StringEquals"
      subjects = ["system:serviceaccount:observability:vmcluster-vmcluster"]
      with_aud = true
    }
    alertmanager = {
      test     = "StringEquals"
      subjects = ["system:serviceaccount:self-monitoring:self-monitoring-kube-prome-alertmanager"]
      with_aud = true
    }
    o11y-backup = {
      test     = "StringLike"
      subjects = ["system:serviceaccount:cluster-backup:*"]
      with_aud = true
    }
  }
}

data "aws_iam_policy_document" "irsa" {
  for_each = local.irsa_roles

  statement {
    effect  = "Allow"
    actions = ["sts:AssumeRoleWithWebIdentity"]

    principals {
      type        = "Federated"
      identifiers = [module.eks.oidc_provider_arn]
    }

    condition {
      test     = each.value.test
      variable = "${local.oidc_issuer}:sub"
      values   = each.value.subjects
    }

    dynamic "condition" {
      for_each = each.value.with_aud ? [1] : []
      content {
        test     = each.value.test
        variable = "${local.oidc_issuer}:aud"
        values   = ["sts.amazonaws.com"]
      }
    }
  }
}

# =============================================================================
# IRSA roles
# =============================================================================

resource "aws_iam_role" "alb_controller" {
  name               = "alb-controller-${local.cluster_name}"
  assume_role_policy = data.aws_iam_policy_document.irsa["alb-controller"].json
  tags               = local.common_tags
}

resource "aws_iam_role_policy_attachment" "alb_controller" {
  role       = aws_iam_role.alb_controller.name
  policy_arn = local.shared_policy_arns["aws-load-balancer-controller"]

  depends_on = [null_resource.shared_iam_policies]
}

resource "aws_iam_role" "external_dns" {
  name               = "external-dns-${local.cluster_name}"
  assume_role_policy = data.aws_iam_policy_document.irsa["external-dns"].json
  tags               = local.common_tags
}

resource "aws_iam_role_policy_attachment" "external_dns" {
  role       = aws_iam_role.external_dns.name
  policy_arn = local.shared_policy_arns["external-dns"]

  depends_on = [null_resource.shared_iam_policies]
}

resource "aws_iam_role" "aws_ca" {
  name               = "aws-ca-${local.cluster_name}"
  assume_role_policy = data.aws_iam_policy_document.irsa["aws-ca"].json
  tags               = local.common_tags
}

resource "aws_iam_role" "regional_server" {
  name               = "regional-server-${local.cluster_name}"
  assume_role_policy = data.aws_iam_policy_document.irsa["regional-server"].json
  tags               = local.common_tags
}

resource "aws_iam_role_policy_attachment" "regional_server" {
  role       = aws_iam_role.regional_server.name
  policy_arn = local.shared_policy_arns["regional-server-iam"]

  depends_on = [null_resource.shared_iam_policies]
}

resource "aws_iam_role_policy_attachment" "aws_ca" {
  role       = aws_iam_role.aws_ca.name
  policy_arn = local.shared_policy_arns["aws-cluster-auto-scaler"]

  depends_on = [null_resource.shared_iam_policies]
}

resource "aws_iam_role" "loki" {
  name               = "loki-${local.cluster_name}"
  assume_role_policy = data.aws_iam_policy_document.irsa["loki"].json
  tags               = local.common_tags
}

resource "aws_iam_role_policy_attachment" "loki" {
  role       = aws_iam_role.loki.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonS3FullAccess"
}

resource "aws_iam_role" "vmbackup" {
  name               = "vmbackup-${local.cluster_name}"
  assume_role_policy = data.aws_iam_policy_document.irsa["vmbackup"].json
  tags               = local.common_tags
}

resource "aws_iam_role_policy_attachment" "vmbackup" {
  role       = aws_iam_role.vmbackup.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonS3FullAccess"
}

resource "aws_iam_role" "alertmanager" {
  name               = "alertmanager-${local.cluster_name}"
  assume_role_policy = data.aws_iam_policy_document.irsa["alertmanager"].json
  tags               = local.common_tags
}

resource "aws_iam_role_policy_attachment" "alertmanager" {
  role       = aws_iam_role.alertmanager.name
  policy_arn = "arn:aws:iam::aws:policy/CloudWatchFullAccess"
}

resource "aws_iam_role" "o11y_backup" {
  name               = "o11y-backup-${local.cluster_name}"
  assume_role_policy = data.aws_iam_policy_document.irsa["o11y-backup"].json
  tags               = local.common_tags
}

resource "aws_iam_role_policy" "o11y_backup" {
  name = "o11y-backup-${local.cluster_name}"
  role = aws_iam_role.o11y_backup.id
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect   = "Allow"
        Resource = "*"
        Action = [
          "s3:*",
          "ec2:*",
        ]
      }
    ]
  })
}
