# AttestAtlas read-only cross-account access role — Terraform / OpenTofu module. # # Creates an IAM role in your AWS account that AttestAtlas's worker assumes # (via sts:AssumeRole) to collect inventory + posture evidence. No long-lived # credentials leave your account. The trust policy requires a unique # External ID generated server-side by AttestAtlas to prevent confused-deputy # attacks. # # Version: v1 # Permissions: AWS-managed ReadOnlyAccess (v1 baseline; future v2 will swap # to a narrower SecurityAudit + specific Get/List actions policy). # # Usage: # module "attestatlas_readonly" { # source = "./modules/attestatlas-readonly" # or git/HTTPS source # external_id = "" # attestatlas_account_id = "" # } # # output "attestatlas_role_arn" { # value = module.attestatlas_readonly.role_arn # } terraform { required_version = ">= 1.5.0" # Compatible with Terraform 1.5+ and OpenTofu 1.6+ required_providers { aws = { source = "hashicorp/aws" version = ">= 5.0" } } } variable "external_id" { description = "Per-integration external ID generated by AttestAtlas. Do not change." type = string sensitive = true validation { condition = can(regex("^[A-Za-z0-9_\\-]{16,64}$", var.external_id)) error_message = "External ID must be 16-64 chars, alphanumeric + underscore + hyphen." } } variable "attestatlas_account_id" { description = "AttestAtlas's AWS account ID (issued during onboarding)." type = string validation { condition = can(regex("^\\d{12}$", var.attestatlas_account_id)) error_message = "Must be a 12-digit AWS account ID." } } variable "role_name" { description = "Name for the IAM role this module creates." type = string default = "AttestAtlasReadOnly" } resource "aws_iam_role" "attestatlas_readonly" { name = var.role_name description = "Read-only role assumed by AttestAtlas's worker for inventory + posture evidence." max_session_duration = 3600 assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Principal = { AWS = "arn:aws:iam::${var.attestatlas_account_id}:root" } Action = "sts:AssumeRole" Condition = { StringEquals = { "sts:ExternalId" = var.external_id } } } ] }) tags = { ManagedBy = "AttestAtlas" Purpose = "read-only-inventory-and-posture" Version = "v1" } } resource "aws_iam_role_policy_attachment" "readonly" { role = aws_iam_role.attestatlas_readonly.name policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess" } output "role_arn" { description = "Paste this ARN back into the AttestAtlas onboarding wizard." value = aws_iam_role.attestatlas_readonly.arn } output "external_id" { description = "The external ID this role trusts (for your records)." value = var.external_id sensitive = true }