Examples
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:
- Authenticate with the registry:
terraform login registry.patterneddesigns.ca - Initialize the working directory:
terraform init - Review the execution plan:
terraform plan - Apply the configuration:
terraform apply
Usage Examples
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
}
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"
]
}
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/*"
}]
})
}
}
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
}
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
}
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 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
}
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 }
}