These examples demonstrate practical, real-world usage patterns for the iam-role module. Each example is self-contained and ready to run—simply copy the configuration, customize the values for your environment, and apply.

Getting Started

To run any example, follow these steps:

  1. Authenticate with the registry: terraform login registry.patterneddesigns.ca
  2. Initialize the working directory: terraform init
  3. Review the execution plan: terraform plan
  4. Apply the configuration: terraform apply

Usage Examples

Basic Lambda Execution Role

Minimal role for Lambda function execution

module "lambda_role" {
  source  = "registry.patterneddesigns.ca/patterneddesigns/iam-role/aws"
  version = "2.0.0"

  name = "lambda-basic-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = { Service = "lambda.amazonaws.com" }
      Action    = "sts:AssumeRole"
    }]
  })

  managed_policy_arns = [
    "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
  ]
}

output "role_arn" {
  value = module.lambda_role.role_arn
}

Lambda with VPC Access

Role for Lambda functions in a VPC

module "vpc_lambda_role" {
  source  = "registry.patterneddesigns.ca/patterneddesigns/iam-role/aws"
  version = "2.0.0"

  name = "lambda-vpc-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = { Service = "lambda.amazonaws.com" }
      Action    = "sts:AssumeRole"
    }]
  })

  managed_policy_arns = [
    "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
    "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
  ]
}

Lambda with Custom Permissions

Role with inline policies for specific resource access

module "api_role" {
  source  = "registry.patterneddesigns.ca/patterneddesigns/iam-role/aws"
  version = "2.0.0"

  name = "api-handler-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = { Service = "lambda.amazonaws.com" }
      Action    = "sts:AssumeRole"
    }]
  })

  managed_policy_arns = [
    "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
  ]

  inline_policies = {
    dynamodb_access = jsonencode({
      Version = "2012-10-17"
      Statement = [{
        Effect = "Allow"
        Action = [
          "dynamodb:GetItem",
          "dynamodb:PutItem",
          "dynamodb:UpdateItem",
          "dynamodb:DeleteItem",
          "dynamodb:Query"
        ]
        Resource = [
          "arn:aws:dynamodb:us-east-1:123456789012:table/users",
          "arn:aws:dynamodb:us-east-1:123456789012:table/users/index/*"
        ]
      }]
    })

    s3_access = jsonencode({
      Version = "2012-10-17"
      Statement = [{
        Effect   = "Allow"
        Action   = ["s3:GetObject", "s3:PutObject"]
        Resource = "arn:aws:s3:::api-uploads/*"
      }]
    })

    secrets_access = jsonencode({
      Version = "2012-10-17"
      Statement = [{
        Effect   = "Allow"
        Action   = ["secretsmanager:GetSecretValue"]
        Resource = "arn:aws:secretsmanager:us-east-1:123456789012:secret:api/*"
      }]
    })
  }
}

Cross-Account Access Role

Role that can be assumed by users from another AWS account

module "cross_account_role" {
  source  = "registry.patterneddesigns.ca/patterneddesigns/iam-role/aws"
  version = "2.0.0"

  name = "cross-account-readonly"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = { AWS = "arn:aws:iam::987654321098:root" }
      Action    = "sts:AssumeRole"
      Condition = {
        StringEquals = {
          "sts:ExternalId" = "secure-external-id-12345"
        }
        Bool = {
          "aws:MultiFactorAuthPresent" = "true"
        }
      }
    }]
  })

  managed_policy_arns = [
    "arn:aws:iam::aws:policy/ReadOnlyAccess"
  ]

  max_session_duration = 14400  # 4 hours
}

EC2 Instance Role

Role for EC2 instances with SSM access

module "ec2_role" {
  source  = "registry.patterneddesigns.ca/patterneddesigns/iam-role/aws"
  version = "2.0.0"

  name = "ec2-app-server-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = { Service = "ec2.amazonaws.com" }
      Action    = "sts:AssumeRole"
    }]
  })

  managed_policy_arns = [
    "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore",
    "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"
  ]

  inline_policies = {
    s3_config = jsonencode({
      Version = "2012-10-17"
      Statement = [{
        Effect   = "Allow"
        Action   = ["s3:GetObject"]
        Resource = "arn:aws:s3:::config-bucket/app-config/*"
      }]
    })
  }
}

resource "aws_iam_instance_profile" "app" {
  name = "app-server-profile"
  role = module.ec2_role.role_name
}

ECS Task Role

Role for ECS container tasks

module "ecs_task_role" {
  source  = "registry.patterneddesigns.ca/patterneddesigns/iam-role/aws"
  version = "2.0.0"

  name = "ecs-app-task-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = { Service = "ecs-tasks.amazonaws.com" }
      Action    = "sts:AssumeRole"
    }]
  })

  inline_policies = {
    app_permissions = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
          Effect   = "Allow"
          Action   = ["s3:GetObject", "s3:PutObject"]
          Resource = "arn:aws:s3:::app-data/*"
        },
        {
          Effect   = "Allow"
          Action   = ["sqs:SendMessage", "sqs:ReceiveMessage", "sqs:DeleteMessage"]
          Resource = "arn:aws:sqs:us-east-1:123456789012:app-queue"
        }
      ]
    })
  }
}

# Separate execution role for ECS agent
module "ecs_execution_role" {
  source  = "registry.patterneddesigns.ca/patterneddesigns/iam-role/aws"
  version = "2.0.0"

  name = "ecs-execution-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = { Service = "ecs-tasks.amazonaws.com" }
      Action    = "sts:AssumeRole"
    }]
  })

  managed_policy_arns = [
    "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
  ]

  inline_policies = {
    secrets = jsonencode({
      Version = "2012-10-17"
      Statement = [{
        Effect   = "Allow"
        Action   = ["secretsmanager:GetSecretValue"]
        Resource = "arn:aws:secretsmanager:us-east-1:123456789012:secret:ecs/*"
      }]
    })
  }
}

Role with Permissions Boundary

Role constrained by an organizational boundary

# Assume this boundary policy exists
data "aws_iam_policy" "developer_boundary" {
  name = "DeveloperBoundary"
}

module "developer_role" {
  source  = "registry.patterneddesigns.ca/patterneddesigns/iam-role/aws"
  version = "2.0.0"

  name = "developer-deployment-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = { Service = "codebuild.amazonaws.com" }
      Action    = "sts:AssumeRole"
    }]
  })

  managed_policy_arns = [
    "arn:aws:iam::aws:policy/PowerUserAccess"
  ]

  # Limit what this role can do despite having PowerUserAccess
  permissions_boundary = data.aws_iam_policy.developer_boundary.arn
}

Multiple Roles for Different Environments

Using for_each to create roles per environment

locals {
  environments = {
    dev = {
      max_session = 3600
      policies    = ["arn:aws:iam::aws:policy/AdministratorAccess"]
    }
    staging = {
      max_session = 7200
      policies    = ["arn:aws:iam::aws:policy/PowerUserAccess"]
    }
    prod = {
      max_session = 3600
      policies    = ["arn:aws:iam::aws:policy/ReadOnlyAccess"]
    }
  }
}

module "deploy_roles" {
  for_each = local.environments

  source  = "registry.patterneddesigns.ca/patterneddesigns/iam-role/aws"
  version = "2.0.0"

  name = "deploy-${each.key}-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = { Service = "codepipeline.amazonaws.com" }
      Action    = "sts:AssumeRole"
    }]
  })

  managed_policy_arns  = each.value.policies
  max_session_duration = each.value.max_session
}

output "role_arns" {
  value = { for k, v in module.deploy_roles : k => v.role_arn }
}