terraform { required_version = ">= 1.3" required_providers { aws = { source = "hashicorp/aws" version = ">= 5.0" } } } variable "trusted_principal_arn" { type = string description = <<-EOT ARN of the IAM user or role in the FinOps Dash account that will assume this role (e.g. arn:aws:iam::111122223333:role/finops-dash-app). EOT default = "arn:aws:sts::413467635781:assumed-role/finops-pro-app/botocore-session-1785611394" validation { condition = can(regex("^arn:aws:iam::\\d{12}:(role|user)/.+$", var.trusted_principal_arn)) error_message = "Must be a valid IAM role or user ARN." } } variable "role_name" { type = string description = "Name of the IAM role to create in this account." default = "FinOpsDashReadOnlyRole" } data "aws_iam_policy_document" "assume_role" { statement { effect = "Allow" actions = ["sts:AssumeRole"] principals { type = "AWS" identifiers = [var.trusted_principal_arn] } } } data "aws_iam_policy_document" "read_only" { statement { sid = "CloudwatchReadOnly" effect = "Allow" actions = [ "cloudwatch:GetMetricStatistics", ] resources = ["*"] } statement { sid = "DynamodbReadOnly" effect = "Allow" actions = [ "dynamodb:DescribeTable", "dynamodb:ListTables", "dynamodb:ListTagsOfResource", ] resources = ["*"] } statement { sid = "Ec2ReadOnly" effect = "Allow" actions = [ "ec2:DescribeAddresses", "ec2:DescribeInstances", "ec2:DescribeInternetGateways", "ec2:DescribeNatGateways", "ec2:DescribeReservedInstances", "ec2:DescribeSecurityGroups", "ec2:DescribeSnapshots", "ec2:DescribeSubnets", "ec2:DescribeVolumes", "ec2:DescribeVpcEndpoints", "ec2:DescribeVpcs", ] resources = ["*"] } statement { sid = "ElasticacheReadOnly" effect = "Allow" actions = [ "elasticache:DescribeCacheClusters", "elasticache:DescribeReplicationGroups", "elasticache:DescribeReservedCacheNodes", "elasticache:ListTagsForResource", ] resources = ["*"] } statement { sid = "ElasticfilesystemReadOnly" effect = "Allow" actions = [ "elasticfilesystem:DescribeFileSystems", "elasticfilesystem:DescribeLifecycleConfiguration", "elasticfilesystem:DescribeTags", ] resources = ["*"] } statement { sid = "ElasticloadbalancingReadOnly" effect = "Allow" actions = [ "elasticloadbalancing:DescribeLoadBalancers", "elasticloadbalancing:DescribeTags", "elasticloadbalancing:DescribeTargetGroups", ] resources = ["*"] } statement { sid = "EsReadOnly" effect = "Allow" actions = [ "es:DescribeDomains", "es:DescribeReservedInstances", "es:ListDomainNames", "es:ListTags", ] resources = ["*"] } statement { sid = "KmsReadOnly" effect = "Allow" actions = [ "kms:DescribeKey", "kms:GetKeyRotationStatus", "kms:ListAliases", "kms:ListKeys", "kms:ListResourceTags", ] resources = ["*"] } statement { sid = "LambdaReadOnly" effect = "Allow" actions = [ "lambda:GetFunctionConfiguration", "lambda:ListFunctions", "lambda:ListTags", ] resources = ["*"] } statement { sid = "LogsReadOnly" effect = "Allow" actions = [ "logs:DescribeLogGroups", "logs:ListTagsForResource", "logs:ListTagsLogGroup", ] resources = ["*"] } statement { sid = "RdsReadOnly" effect = "Allow" actions = [ "rds:DescribeDBClusters", "rds:DescribeDBInstances", "rds:DescribeReservedDBInstances", "rds:ListTagsForResource", ] resources = ["*"] } statement { sid = "Route53ReadOnly" effect = "Allow" actions = [ "route53:ListHostedZones", "route53:ListResourceRecordSets", "route53:ListTagsForResource", ] resources = ["*"] } statement { sid = "S3ReadOnly" effect = "Allow" actions = [ "s3:GetBucketLocation", "s3:GetBucketTagging", "s3:GetObject", "s3:ListAllMyBuckets", "s3:ListBucket", ] resources = ["*"] } statement { sid = "SavingsplansReadOnly" effect = "Allow" actions = [ "savingsplans:DescribeSavingsPlans", ] resources = ["*"] } statement { sid = "SecretsmanagerReadOnly" effect = "Allow" actions = [ "secretsmanager:ListSecrets", ] resources = ["*"] } statement { sid = "SnsReadOnly" effect = "Allow" actions = [ "sns:GetTopicAttributes", "sns:ListTagsForResource", "sns:ListTopics", ] resources = ["*"] } statement { sid = "SqsReadOnly" effect = "Allow" actions = [ "sqs:GetQueueAttributes", "sqs:ListQueueTags", "sqs:ListQueues", ] resources = ["*"] } } resource "aws_iam_role" "finops_dash" { name = var.role_name description = "Role assumed by FinOps Dash to read this account's inventory and costs." assume_role_policy = data.aws_iam_policy_document.assume_role.json max_session_duration = 3600 } resource "aws_iam_role_policy" "finops_dash_read_only" { name = "FinOpsDashReadOnlyPolicy" role = aws_iam_role.finops_dash.id policy = data.aws_iam_policy_document.read_only.json } output "role_arn" { description = "ARN of the role to paste into the \"Assume Role ARN\" field in FinOps Dash." value = aws_iam_role.finops_dash.arn } output "role_name" { description = "Name of the created role." value = aws_iam_role.finops_dash.name }