terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
}
}
variable "role_name" {
description = "Name for the IAM role"
type = string
default = "TierZeroAccess"
}
variable "external_id" {
description = "External ID from TierZero setup wizard"
type = string
}
# IAM Role with Trust Policy
resource "aws_iam_role" "tierzero" {
name = var.role_name
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::851725519002:role/tierzero-managed"
}
Action = "sts:AssumeRole"
Condition = {
StringEquals = {
"sts:ExternalId" = var.external_id
}
}
}
]
})
tags = {
ManagedBy = "Terraform"
Purpose = "TierZero cross-account access"
}
}
# EKS MCP Read-Only (managed policy — no inline equivalent)
resource "aws_iam_role_policy_attachment" "eks_mcp_readonly" {
role = aws_iam_role.tierzero.name
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSMCPReadOnlyAccess"
}
# Compute & Networking Read-Only
# Covers: EC2, Lambda, ECS, ELB, Auto Scaling, VPC, CloudFormation, Step Functions
resource "aws_iam_role_policy" "compute_networking_readonly" {
name = "compute-networking-readonly"
role = aws_iam_role.tierzero.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "EC2ReadOnly"
Effect = "Allow"
Action = [
"ec2:Describe*",
"ec2:Get*",
"ec2:List*",
"ec2:Search*",
]
Resource = "*"
},
{
Sid = "LambdaReadOnly"
Effect = "Allow"
Action = [
"lambda:Get*",
"lambda:List*",
]
Resource = "*"
},
{
Sid = "ECSReadOnly"
Effect = "Allow"
Action = [
"ecs:Describe*",
"ecs:List*",
]
Resource = "*"
},
{
Sid = "ELBReadOnly"
Effect = "Allow"
Action = [
"elasticloadbalancing:Describe*",
"elasticloadbalancing:Get*",
]
Resource = "*"
},
{
Sid = "AutoScalingReadOnly"
Effect = "Allow"
Action = [
"autoscaling:Describe*",
"application-autoscaling:DescribeScalableTargets",
"application-autoscaling:DescribeScalingActivities",
"application-autoscaling:DescribeScalingPolicies",
]
Resource = "*"
},
{
Sid = "CloudFormationReadOnly"
Effect = "Allow"
Action = [
"cloudformation:DescribeStacks",
"cloudformation:ListStacks",
"cloudformation:ListStackResources",
]
Resource = "*"
},
]
})
}
# Storage & Database Read-Only
# Covers: S3, RDS, DynamoDB, DAX, EBS, EFS, ElastiCache, Data Pipeline, Kinesis
resource "aws_iam_role_policy" "storage_database_readonly" {
name = "storage-database-readonly"
role = aws_iam_role.tierzero.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "S3MetadataOnly"
Effect = "Allow"
Action = [
"s3:ListAllMyBuckets",
"s3:ListBucket",
"s3:ListBucketVersions",
"s3:ListBucketMultipartUploads",
"s3:ListMultipartUploadParts",
"s3:Describe*",
"s3:GetBucket*",
"s3:GetAccessPoint*",
"s3:GetMultiRegionAccessPoint*",
"s3:GetStorageLens*",
"s3:GetEncryptionConfiguration",
"s3:GetLifecycleConfiguration",
"s3:GetReplicationConfiguration",
"s3:GetAccelerateConfiguration",
"s3:GetAnalyticsConfiguration",
"s3:GetIntelligentTieringConfiguration",
"s3:GetInventoryConfiguration",
"s3:GetMetricsConfiguration",
"s3:GetObjectTagging",
"s3:GetObjectVersionTagging",
"s3:GetObjectAcl",
"s3:GetObjectVersionAcl",
"s3:GetObjectRetention",
"s3:GetObjectLegalHold",
"s3:GetObjectAttributes",
"s3:GetObjectVersionAttributes",
]
Resource = "*"
},
{
Sid = "RDSReadOnly"
Effect = "Allow"
Action = [
"rds:Describe*",
"rds:ListTagsForResource",
]
Resource = "*"
},
{
Sid = "DynamoDBMetadataOnly"
Effect = "Allow"
Action = [
"dynamodb:Describe*",
"dynamodb:List*",
"dynamodb:GetAbacStatus",
"dynamodb:GetResourcePolicy",
]
Resource = "*"
},
{
Sid = "EBSReadOnly"
Effect = "Allow"
Action = [
"ec2:DescribeVolumes",
"ec2:DescribeVolumeStatus",
"ec2:DescribeVolumeAttribute",
"ec2:DescribeSnapshots",
"ec2:DescribeSnapshotAttribute",
"ec2:DescribeSnapshotTierStatus",
"ec2:ListSnapshotsInRecycleBin",
"ebs:ListSnapshotBlocks",
"ebs:ListChangedBlocks",
]
Resource = "*"
},
{
Sid = "EFSReadOnly"
Effect = "Allow"
Action = [
"elasticfilesystem:Describe*",
"elasticfilesystem:ListTagsForResource",
]
Resource = "*"
},
{
Sid = "ElastiCacheReadOnly"
Effect = "Allow"
Action = [
"elasticache:Describe*",
"elasticache:List*",
]
Resource = "*"
},
{
Sid = "KinesisReadOnly"
Effect = "Allow"
Action = [
"kinesis:ListStreams",
"kinesis:DescribeStream",
"kinesis:DescribeStreamSummary",
]
Resource = "*"
},
{
Sid = "DynamoDBContributorInsights"
Effect = "Allow"
Action = [
"cloudwatch:GetInsightRuleReport",
]
Resource = "arn:aws:cloudwatch:*:*:insight-rule/DynamoDBContributorInsights*"
},
]
})
}
# Monitoring & Observability Read-Only
# Covers: CloudWatch, Logs, Synthetics, RUM, Application Signals,
# Observability Admin, CloudTrail
resource "aws_iam_role_policy" "monitoring_observability_readonly" {
name = "monitoring-observability-readonly"
role = aws_iam_role.tierzero.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "CloudWatchReadOnly"
Effect = "Allow"
Action = [
"cloudwatch:BatchGet*",
"cloudwatch:Describe*",
"cloudwatch:GenerateQuery",
"cloudwatch:Get*",
"cloudwatch:List*",
]
Resource = "*"
},
{
Sid = "LogsReadOnly"
Effect = "Allow"
Action = [
"logs:Describe*",
"logs:Get*",
"logs:List*",
"logs:StartQuery",
"logs:StopQuery",
"logs:TestMetricFilter",
"logs:FilterLogEvents",
"logs:StartLiveTail",
"logs:StopLiveTail",
]
Resource = "*"
},
{
Sid = "ApplicationSignalsReadOnly"
Effect = "Allow"
Action = [
"application-signals:BatchGet*",
"application-signals:Get*",
"application-signals:List*",
]
Resource = "*"
},
{
Sid = "SyntheticsReadOnly"
Effect = "Allow"
Action = [
"synthetics:Describe*",
"synthetics:Get*",
"synthetics:List*",
]
Resource = "*"
},
{
Sid = "RUMReadOnly"
Effect = "Allow"
Action = [
"rum:BatchGet*",
"rum:Get*",
"rum:List*",
]
Resource = "*"
},
{
Sid = "ObservabilityAdminReadOnly"
Effect = "Allow"
Action = [
"observabilityadmin:Get*",
"observabilityadmin:List*",
"observabilityadmin:Test*",
"observabilityadmin:Validate*",
]
Resource = "*"
},
{
Sid = "CloudTrailReadOnly"
Effect = "Allow"
Action = [
"cloudtrail:ListChannels",
]
Resource = "*"
},
{
Sid = "CloudTrailAppSignalsScoped"
Effect = "Allow"
Action = [
"cloudtrail:GetChannel",
]
Resource = "arn:aws:cloudtrail:*:*:channel/aws-service-channel/application-signals/*"
},
{
Sid = "ServiceQuotasScoped"
Effect = "Allow"
Action = [
"servicequotas:GetServiceQuota",
]
Resource = [
"arn:aws:servicequotas:*:*:s3/*",
"arn:aws:servicequotas:*:*:dynamodb/*",
"arn:aws:servicequotas:*:*:kinesis/*",
"arn:aws:servicequotas:*:*:sns/*",
"arn:aws:servicequotas:*:*:bedrock/*",
"arn:aws:servicequotas:*:*:lambda/*",
"arn:aws:servicequotas:*:*:fargate/*",
"arn:aws:servicequotas:*:*:elasticloadbalancing/*",
"arn:aws:servicequotas:*:*:ec2/*",
]
},
]
})
}
# Billing & Cost Read-Only
resource "aws_iam_role_policy" "billing_cost_readonly" {
name = "billing-cost-readonly"
role = aws_iam_role.tierzero.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "CostAnalysis"
Effect = "Allow"
Action = [
"ce:Describe*",
"ce:Get*",
"ce:List*",
"cur:Describe*",
"cur:Get*",
"budgets:Describe*",
"budgets:View*",
]
Resource = "*"
},
]
})
}
# Security, DNS, Messaging & CDN Read-Only
# Covers: IAM, STS, KMS, ACM, WAF, SQS, Route53, CloudFront
resource "aws_iam_role_policy" "security_dns_messaging_readonly" {
name = "security-dns-messaging-readonly"
role = aws_iam_role.tierzero.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "IAMReadOnly"
Effect = "Allow"
Action = [
"iam:GenerateCredentialReport",
"iam:GenerateServiceLastAccessedDetails",
"iam:Get*",
"iam:List*",
"iam:SimulateCustomPolicy",
"iam:SimulatePrincipalPolicy",
]
Resource = "*"
},
{
Sid = "STSReadOnly"
Effect = "Allow"
Action = [
"sts:GetCallerIdentity",
]
Resource = "*"
},
{
Sid = "KMSReadOnly"
Effect = "Allow"
Action = [
"kms:DescribeKey",
"kms:ListAliases",
]
Resource = "*"
},
{
Sid = "ACMReadOnly"
Effect = "Allow"
Action = [
"acm:DescribeCertificate",
"acm:ListCertificates",
]
Resource = "*"
},
{
Sid = "WAFReadOnly"
Effect = "Allow"
Action = [
"waf:ListWebACLs",
"waf:GetWebACL",
"wafv2:ListWebACLs",
"wafv2:GetWebACL",
]
Resource = "*"
},
{
Sid = "SQSReadOnly"
Effect = "Allow"
Action = [
"sqs:GetQueueAttributes",
"sqs:GetQueueUrl",
"sqs:ListDeadLetterSourceQueues",
"sqs:ListQueues",
"sqs:ListMessageMoveTasks",
"sqs:ListQueueTags",
]
Resource = "*"
},
{
Sid = "Route53ReadOnly"
Effect = "Allow"
Action = [
"route53:Get*",
"route53:List*",
"route53:TestDNSAnswer",
]
Resource = "*"
},
{
Sid = "CloudFrontReadOnly"
Effect = "Allow"
Action = [
"cloudfront:Describe*",
"cloudfront:Get*",
"cloudfront:List*",
"cloudfront-keyvaluestore:Describe*",
"cloudfront-keyvaluestore:Get*",
"cloudfront-keyvaluestore:List*",
]
Resource = "*"
},
{
Sid = "ResourceGroupsAndTags"
Effect = "Allow"
Action = [
"resource-groups:ListGroups",
"resource-groups:ListGroupResources",
"resource-groups:GetGroup",
"resource-groups:GetGroupQuery",
"tag:GetResources",
]
Resource = "*"
},
]
})
}
output "role_arn" {
description = "ARN of the TierZero IAM role — provide this to TierZero"
value = aws_iam_role.tierzero.arn
}