data "aws_partition" "current" {}

locals {
  # `costwatch policy` plus strays.risks.RISK_ACTIONS; tests/test_onboarding.py keeps them in sync
  read_only_actions = [
    "sts:GetCallerIdentity",
    "ec2:DescribeRegions",
    "ec2:DescribeVolumes",
    "ec2:DescribeSnapshots",
    "ec2:DescribeImages",
    "ec2:DescribeAddresses",
    "ec2:DescribeInstances",
    "ec2:DescribeNatGateways",
    "ec2:DescribeLaunchTemplates",
    "ec2:DescribeLaunchTemplateVersions",
    "autoscaling:DescribeLaunchConfigurations",
    "elasticloadbalancing:DescribeLoadBalancers",
    "elasticloadbalancing:DescribeTargetGroups",
    "elasticloadbalancing:DescribeTargetHealth",
    "elasticloadbalancing:DescribeTags",
    "rds:DescribeDBSnapshots",
    "rds:DescribeDBClusterSnapshots",
    "rds:DescribeDBInstances",
    "rds:DescribeDBInstanceAutomatedBackups",
    "cloudwatch:GetMetricData",
    "logs:DescribeLogGroups",
    "cloudtrail:LookupEvents",
    # Security risk checks
    "iam:GetAccountSummary",
    "iam:GenerateCredentialReport",
    "iam:GetCredentialReport",
    "ec2:DescribeSecurityGroups",
    "ec2:DescribeNetworkInterfaces",
    "ec2:DescribeSnapshotAttribute",
    "rds:DescribeDBSnapshotAttributes",
    "rds:DescribeDBClusterSnapshotAttributes",
    "s3:GetAccountPublicAccessBlock",
    "s3:ListAllMyBuckets",
    "s3:GetBucketLocation",
    "s3:GetBucketPolicyStatus",
    "s3:GetBucketAcl",
    "ec2:GetEbsEncryptionByDefault",
    "cloudtrail:DescribeTrails",
    "cloudtrail:GetTrailStatus",
    "guardduty:ListDetectors",
    "guardduty:GetDetector",
    "rds:DescribeDBClusters",
    "lambda:ListFunctions",
    "eks:ListClusters",
    "eks:DescribeCluster",
    "ec2:DescribeVpcEndpoints",
    "iam:ListRoles",
    "iam:GetRole",
    "iam:ListUsers",
    "iam:ListAttachedUserPolicies",
    "iam:ListGroupsForUser",
    "iam:ListAttachedGroupPolicies",
    "iam:GetAccountPasswordPolicy",
    "lambda:ListFunctionUrlConfigs",
    "elasticloadbalancing:DescribeListeners",
    "acm:ListCertificates",
    "acm:DescribeCertificate",
    "route53domains:ListDomains",
    "budgets:ViewBudget",
    "cloudwatch:DescribeAlarms",
    "s3:GetLifecycleConfiguration",
    "s3:ListBucketMultipartUploads",
    "kms:ListKeys",
    "kms:DescribeKey",
    "secretsmanager:ListSecrets",
    "ecr:DescribeRepositories",
    "ecr:GetLifecyclePolicy",
    "ecr:DescribeImages",
    "ce:GetSavingsPlansPurchaseRecommendation",
    "ce:GetCostAndUsage",
    "ce:ListCostAllocationTags",
    "iam:ListAttachedRolePolicies",
    "iam:GetUser",
    "iam:ListAccessKeys",
    "iam:GetAccessKeyLastUsed",
    "iam:GetLoginProfile",
    "iam:ListMFADevices",
    "iam:ListSSHPublicKeys",
    # Inventory and tagging (strays.tagging)
    "lambda:ListTags",
    "kms:ListResourceTags",
    "ecr:ListTagsForResource",
    "logs:ListTagsForResource",
    "s3:GetBucketTagging",
    "backup:ListBackupVaults",
    "backup:ListBackupPlans",
    "backup:ListTags",
    "iam:ListUserTags",
    "iam:ListRoleTags",
    "iam:ListPolicies",
    "iam:ListPolicyTags",
  ]
}

data "aws_iam_policy_document" "trust" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type = "AWS"
      identifiers = [
        "arn:${data.aws_partition.current.partition}:iam::${var.trusted_account_id}:role/${var.worker_role_name}",
        "arn:${data.aws_partition.current.partition}:iam::${var.trusted_account_id}:role/${var.web_role_name}",
      ]
    }

    condition {
      test     = "StringEquals"
      variable = "sts:ExternalId"
      values   = [var.external_id]
    }
  }
}

resource "aws_iam_role" "audit" {
  name                 = var.role_name
  description          = "Read-only access for a Strays AWS audit (waste and security)"
  assume_role_policy   = data.aws_iam_policy_document.trust.json
  max_session_duration = 3600
  tags                 = var.tags
}

data "aws_iam_policy_document" "read_only" {
  # checkov:skip=CKV_AWS_356:An account-wide audit must read every role, user, bucket and certificate; every action is read-only (enforced by tests)
  statement {
    sid       = "CostwatchReadOnly"
    actions   = local.read_only_actions
    resources = ["*"]
  }
}

resource "aws_iam_role_policy" "read_only" {
  name   = "costwatch-read-only"
  role   = aws_iam_role.audit.id
  policy = data.aws_iam_policy_document.read_only.json
}

data "aws_iam_policy_document" "state" {
  count = var.terraform_state_bucket == null ? 0 : 1

  statement {
    actions   = ["s3:ListBucket"]
    resources = ["arn:${data.aws_partition.current.partition}:s3:::${var.terraform_state_bucket}"]
  }

  statement {
    actions   = ["s3:GetObject"]
    resources = ["arn:${data.aws_partition.current.partition}:s3:::${var.terraform_state_bucket}/*"]
  }

  dynamic "statement" {
    for_each = var.terraform_state_kms_key_arn == null ? [] : [var.terraform_state_kms_key_arn]
    content {
      actions   = ["kms:Decrypt"]
      resources = [statement.value]
    }
  }
}

resource "aws_iam_role_policy" "state" {
  count = var.terraform_state_bucket == null ? 0 : 1

  name   = "terraform-state-read"
  role   = aws_iam_role.audit.id
  policy = data.aws_iam_policy_document.state[0].json
}
