provider "aws" {
  region = var.aws_region
}

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

# IAM group for everyone
resource "aws_iam_group" "generic_orchard_group" {
  name = "generic-orchard-${var.environment}-group"
}

resource "aws_iam_group_membership" "generic_orchard_group" {
  name  = "generic-orchard-${var.environment}-group-membership"
  group = aws_iam_group.generic_orchard_group.name
  users = []
}

# IAM group for engineers
resource "aws_iam_group" "generic_orchard_engineering_group" {
  name = "generic-orchard-${var.environment}-engineering-group"
}

resource "aws_iam_group_membership" "generic_orchard_engineering_group" {
  name  = "generic-orchard-${var.environment}-engineering-group-membership"
  group = aws_iam_group.generic_orchard_engineering_group.name
  users = []
}

data "aws_caller_identity" "current" {}

data "aws_iam_policy_document" "orchard_engineering_shared_iam_security_credentials_policy" {
  statement {
    actions = [
      "iam:*AccessKey*",
      "iam:*ServiceSpecificCredential*",
    ]

    resources = [
      "arn:aws:iam::${data.aws_caller_identity.current.account_id}:user/$${aws:username}",
    ]
  }
}

# IAM policy for everyone
data "aws_iam_policy_document" "orchard_everyone_shared_iam_access_policy" {

  statement {
    actions = [
      "iam:ChangePassword",
      "iam:GetUser",
      "iam:ListMFADevices",
      "iam:UpdateLoginProfile",
    ]

    resources = [
      "arn:aws:iam::${data.aws_caller_identity.current.account_id}:user/$${aws:username}",
    ]

  }

  # These actions do not support specific resources and are account-wide
  statement {
    actions = [
      "iam:GetAccountPasswordPolicy",
      "iam:ListVirtualMFADevices",
    ]

    resources = [
      "*",
    ]
  }

  statement {
    sid = "AllowPrimaryMfaRegistration"

    actions = [
      "iam:CreateVirtualMFADevice",
      "iam:EnableMFADevice",
      "iam:FinalizeSmsMfaRegistration",
      "iam:RequestSmsMfaRegistration",
      "iam:ResyncMFADevice",
    ]

    resources = [
      "arn:aws:iam::${data.aws_caller_identity.current.account_id}:mfa/$${aws:username}",
      "arn:aws:iam::${data.aws_caller_identity.current.account_id}:user/$${aws:username}",
    ]

  }

  statement {
    sid = "AllowSecondaryMfaRegistrationOnlyIfMfaAuthenticated"

    actions = [
      "iam:CreateVirtualMFADevice",
      "iam:EnableMFADevice",
      "iam:FinalizeSmsMfaRegistration",
      "iam:RequestSmsMfaRegistration",
      "iam:ResyncMFADevice",
    ]

    resources = [
      "arn:aws:iam::${data.aws_caller_identity.current.account_id}:mfa/$${aws:username}-*",
      "arn:aws:iam::${data.aws_caller_identity.current.account_id}:user/$${aws:username}",
    ]

    condition {
      test     = "Bool"
      variable = "aws:MultiFactorAuthPresent"
      values   = ["true"]
    }

  }

  statement {
    sid = "AllowMfaDeregistrationOnlyIfMfaAuthenticated"

    actions = [
      "iam:DeactivateMFADevice",
      "iam:DeleteVirtualMFADevice",
    ]

    resources = [
      "arn:aws:iam::${data.aws_caller_identity.current.account_id}:mfa/$${aws:username}",
      "arn:aws:iam::${data.aws_caller_identity.current.account_id}:mfa/$${aws:username}-*",
      "arn:aws:iam::${data.aws_caller_identity.current.account_id}:user/$${aws:username}",
    ]

    condition {
      test     = "Bool"
      variable = "aws:MultiFactorAuthPresent"
      values   = ["true"]
    }

  }

  statement {
    sid    = "BlockAnyAccessOtherThanAboveUnlessSignedInWithMFA"
    effect = "Deny"
    not_actions = [
      "iam:*",
    ]

    resources = [
      "*",
    ]

    condition {
      test     = "Bool"
      variable = "aws:MultiFactorAuthPresent"

      values = [
        "false",
      ]
    }

  }

  statement {
    sid = "AllowIAMWithMFA"
    actions = [
      "iam:GetAccessKeyLastUsed",
      "iam:GetLoginProfile",
      "iam:GetUser",
      "iam:GetUserPolicy",
      "iam:ListAccessKeys",
      "iam:ListAttachedUserPolicies",
      "iam:ListGroupPolicies",
      "iam:ListGroupsForUser",
      "iam:ListMFADevices",
      "iam:ListServiceSpecificCredentials",
      "iam:ListSigningCertificates",
      "iam:ListSSHPublicKeys",
      "iam:ListUserPolicies",
    ]

    resources = [
      "arn:aws:iam::${data.aws_caller_identity.current.account_id}:user/$${aws:username}",
    ]

    condition {
      test     = "BoolIfExists"
      variable = "aws:MultiFactorAuthPresent"

      values = [
        "true",
      ]
    }

  }
}

# Policies for engineering group
module "shared_policies" {
  source = "git@github.com:theorchard/terraform-iam-policies.git//modules/shared?ref=1.18.3"

  environment                                 = var.environment
  break_glass_elevate_permissions_policy_name = "${var.environment}-break-glass-elevate-permissions-access-policy"
}

resource "aws_iam_policy" "shared_engineering_iam_security_credentials_policy" {
  name   = "${var.environment}-orchard-engineeering-shared-iam-security-credentials-policy"
  policy = data.aws_iam_policy_document.orchard_engineering_shared_iam_security_credentials_policy.json
}

resource "aws_iam_group_policy_attachment" "shared_engineering_iam_read_policy_attachment" {
  group      = aws_iam_group.generic_orchard_engineering_group.name
  policy_arn = module.shared_policies.shared_engineering_read_policy_arn
}

resource "aws_iam_group_policy_attachment" "shared_engineering_global_iam_access_policy_attachment" {
  group      = aws_iam_group.generic_orchard_engineering_group.name
  policy_arn = module.shared_policies.shared_engineering_iam_access_policy_arn
}

resource "aws_iam_group_policy_attachment" "shared_engineering_iam_security_credentials_policy_attachment" {
  group      = aws_iam_group.generic_orchard_engineering_group.name
  policy_arn = aws_iam_policy.shared_engineering_iam_security_credentials_policy.arn
}

# Policies for everyone
resource "aws_iam_policy" "shared_everyone_iam_access_policy" {
  name   = "${var.environment}-orchard-everyone-shared-iam-access-policy"
  policy = data.aws_iam_policy_document.orchard_everyone_shared_iam_access_policy.json
}

resource "aws_iam_group_policy_attachment" "shared_everyone_iam_access_policy_attachment" {
  group      = aws_iam_group.generic_orchard_group.name
  policy_arn = aws_iam_policy.shared_everyone_iam_access_policy.arn
}

data "aws_iam_policy_document" "sme_cloud_compliance_policy_document" {
  # checkov:skip=CKV_AWS_107:Silencing the "Ensure IAM policies does not allow credentials exposure" finding which was triggered on 'ec2:GetPasswordData'.
  # checkov:skip=CKV_AWS_111:Silencing the "Ensure IAM policies does not allow write access without constraints" finding which was triggered on 'states:GetActivityTask'.
  # checkov:skip=CKV_AWS_109:Silencing the "Ensure IAM policies does not allow permissions management / resource exposure without constraints" finding which was triggered on "glue:Get*".


  statement {
    actions = [
      "apigateway:Get*",
      "a4b:Get*",
      "a4b:List*",
      "a4b:Search*",
      "access-analyzer:Get*",
      "access-analyzer:List*",
      "acm-pca:Describe*",
      "acm-pca:Get*",
      "acm-pca:List*",
      "acm:Describe*",
      "acm:Get*",
      "acm:List*",
      "airflow:List*",
      "amplify:Get*",
      "amplify:List*",
      "appconfig:Get*",
      "appconfig:List*",
      "application-autoscaling:Describe*",
      "autoscaling:Describe*",
      "applicationinsights:Describe*",
      "applicationinsights:List*",
      "appmesh:Describe*",
      "appmesh:List*",
      "appstream:Describe*",
      "appstream:List*",
      "appsync:Get*",
      "appsync:List*",
      "athena:Batch*",
      "athena:Get*",
      "athena:List*",
      "auditmanager:Get*",
      "auditmanager:List*",
      "batch:Describe*",
      "batch:List*",
      "budgets:Describe*",
      "budgets:View*",
      "cassandra:Select",
      "ce:Describe*",
      "ce:Get*",
      "ce:List*",
      "cloudfront:DescribeFunction",
      "cloudfront:Get*",
      "cloudfront:List*",
      "cloudhsm:Describe*",
      "cloudhsm:Get*",
      "cloudhsm:List*",
      "cloudsearch:Describe*",
      "cloudsearch:List*",
      "cloudwatch:Describe*",
      "cloudwatch:Get*",
      "cloudwatch:List*",
      "cognito-identity:Describe*",
      "cognito-identity:Get*",
      "cognito-identity:List*",
      "cognito-identity:Lookup*",
      "cognito-idp:AdminGet*",
      "cognito-idp:AdminList*",
      "cognito-idp:Describe*",
      "cognito-idp:Get*",
      "cognito-idp:List*",
      "cognito-sync:Describe*",
      "cognito-sync:Get*",
      "cognito-sync:List*",
      "cognito-sync:QueryRecords",
      "compute-optimizer:Describe*",
      "compute-optimizer:Get*",
      "datapipeline:Describe*",
      "datapipeline:Get*",
      "datapipeline:List*",
      "datapipeline:ValidatePipelineDefinition",
      "datapipeline:QueryObjects",
      "dynamodb:Describe*",
      "dynamodb:List*",
      "ec2:Describe*",
      "ec2:Get*",
      "ecr:Describe*",
      "ecr:ListImages",
      "ecs:Describe*",
      "ecs:List*",
      "eks:Describe*",
      "eks:List*",
      "elasticache:Describe*",
      "elasticache:List*",
      "elasticbeanstalk:Check*",
      "elasticbeanstalk:Describe*",
      "elasticbeanstalk:List*",
      "elasticbeanstalk:RequestEnvironmentInfo",
      "elasticfilesystem:Describe*",
      "elasticloadbalancing:Describe*",
      "elasticmapreduce:ListInstance*",
      "elastictranscoder:List*",
      "elastictranscoder:Read*",
      "es:GetCompatibleElasticsearchVersions",
      "es:GetUpgradeStatus",
      "es:ListElasticsearchInstanceTypeDetails",
      "es:Describe*",
      "es:List*",
      "events:Describe*",
      "events:List*",
      "glue:Get*",
      "glue:List*",
      "guardduty:Get*",
      "guardduty:List*",
      "health:Describe*",
      "iam:Get*",
      "iam:GenerateCredentialReport",
      "iam:List*",
      "inspector:Describe*",
      "inspector:Get*",
      "inspector:List*",
      "inspector:Preview*",
      "kafka:Describe*",
      "kafka:Get*",
      "kafka:List*",
      "kinesis:Get*",
      "kinesis:List*",
      "kinesis:Describe*",
      "kms:Describe*",
      "kms:List*",
      "lambda:Get*",
      "lambda:List*",
      "logs:Describe*",
      "logs:Filter*",
      "logs:Get*",
      "macie2:Describe*",
      "macie2:Get*",
      "macie2:List*",
      "network-firewall:Describe*",
      "network-firewall:List*",
      "organizations:ListAccounts",
      "organizations:ListParents",
      "organizations:DescribeAccount",
      "redshift:DescribeClusters",
      "rds:Describe*",
      "rds:List*",
      "route53:Get*",
      "route53:List*",
      "route53domains:Check*",
      "route53domains:Get*",
      "route53domains:List*",
      "route53domains:View*",
      "route53resolver:Get*",
      "route53resolver:List*",
      "s3:GetAccelerateConfiguration",
      "s3:GetAccessPoint",
      "s3:GetAccessPoint*",
      "s3:GetAccountPublicAccessBlock",
      "s3:GetAnalyticsConfiguration",
      "s3:GetBucket*",
      "s3:GetEncryptionConfiguration",
      "s3:GetIntelligentTieringConfiguration",
      "s3:GetInventoryConfiguration",
      "s3:GetJobTagging",
      "s3:GetLifecycleConfiguration",
      "s3:GetMetricsConfiguration",
      "s3:GetMultiRegionAccess*",
      "s3:GetReplicationConfiguration",
      "s3:GetStorageLens*",
      "s3:List*",
      "secretsmanager:Describe*",
      "secretsmanager:GetResourcePolicy",
      "secretsmanager:List*",
      "securityhub:Describe*",
      "securityhub:Get*",
      "securityhub:List*",
      "serverlessrepo:Get*",
      "serverlessrepo:List*",
      "serverlessrepo:SearchApplications",
      "ses:Describe*",
      "ses:Get*",
      "ses:List*",
      "shield:Describe*",
      "shield:Get*",
      "shield:List*",
      "sns:Get*",
      "sns:ListSubscriptionsByTopic",
      "sns:ListTopics",
      "sqs:Get*",
      "sqs:List*",
      "states:Describe*",
      "states:Get*",
      "states:List*",
      "swf:Describe*",
      "swf:Get*",
      "swf:List*",
      "tag:Get*",
      "waf-regional:Get*",
      "waf-regional:List*",
      "waf:Get*",
      "waf:List*",
      "wafv2:Describe*",
      "wafv2:Get*",
      "wafv2:List*",
      "wafv2:CheckCapacity",
      "xray:BatchGet*",
      "xray:Get*",
      "xray:List*",
    ]

    resources = [
      "*"
    ]

  }
}

resource "aws_iam_policy" "sme_cloud_compliance_policy" {
  name   = "${var.environment}-sme-cloud-compliance-policy-shared"
  policy = data.aws_iam_policy_document.sme_cloud_compliance_policy_document.json
}

# IAM group for engineers
resource "aws_iam_group" "sme_cloud_compliance_group" {
  name = "${var.environment}-sme-cloud-compliance-group"
}

resource "aws_iam_group_policy_attachment" "readonly" {
  group      = aws_iam_group.sme_cloud_compliance_group.name
  policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}

resource "aws_iam_group_membership" "sme_cloud_compliance_group" {
  name  = "${var.environment}-sme-cloud-compliance-group-membership"
  group = aws_iam_group.sme_cloud_compliance_group.name
  users = []
}
