iam-role
- Create IAM roles with customizable trust policies
module "iam_role" {
source = "registry.patterneddesigns.ca/patterneddesigns/iam-role/aws"
version = "0.1.0"
# Required inputs
name = "..."
}Overview
The iam-role module creates AWS IAM roles with:
- Customizable trust policies for service principals
- Managed policy attachments for standard permissions
- Inline policies for custom permissions
- Configurable session duration
- Optional permissions boundaries for security guardrails
Category: Security Provider: AWS Latest Version: 2.0.0
Quick Start
module "lambda_role" {
source = "registry.patterneddesigns.ca/patterneddesigns/iam-role/aws"
version = "2.0.0"
name = "lambda-execution-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"
]
}
Key Features
Service-Linked Roles
Create roles for AWS services:
# Lambda execution role
module "lambda_role" {
source = "registry.patterneddesigns.ca/patterneddesigns/iam-role/aws"
version = "2.0.0"
name = "lambda-api-handler"
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"
]
}
Cross-Account Access
Allow principals from other accounts:
module "cross_account_role" {
source = "registry.patterneddesigns.ca/patterneddesigns/iam-role/aws"
version = "2.0.0"
name = "cross-account-admin"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { AWS = "arn:aws:iam::123456789012:root" }
Action = "sts:AssumeRole"
Condition = {
StringEquals = { "sts:ExternalId" = "shared-secret" }
}
}]
})
managed_policy_arns = [
"arn:aws:iam::aws:policy/AdministratorAccess"
]
}
Custom Inline Policies
Attach custom permissions directly:
module "s3_processor_role" {
source = "registry.patterneddesigns.ca/patterneddesigns/iam-role/aws"
version = "2.0.0"
name = "s3-processor"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "lambda.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
inline_policies = {
s3_access = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = ["s3:GetObject", "s3:PutObject"]
Resource = "arn:aws:s3:::my-bucket/*"
}]
})
}
}
Documentation
Registry
Inputs
The name of the IAM role. Must be unique within your AWS account. **Naming conventions:** - Use lowercase with hyphens: `my-service-role` - Include purpose: `lambda-processor-role`, `ecs-task-role` - Include environment for clarity: `prod-api-gateway-role` **Constraints:** - Maximum 64 characters - Alphanumeric characters, plus `+=,.@-_` - Cannot begin with `aws-`
Human-readable description of the role's purpose. A good description helps with: - Auditing and compliance reviews - Understanding role purpose months later - Identifying roles for cleanup **Example descriptions:** - "Allows Lambda functions to process S3 events and write to DynamoDB" - "ECS task execution role for production API containers" - "Cross-account access for CI/CD pipeline deployment"
Path for the IAM role. Use paths to organize roles hierarchically. **Path patterns:** - `/service-roles/` - AWS service-linked roles - `/application/{app-name}/` - Application-specific roles - `/environment/{env}/` - Environment-based organization - `/team/{team-name}/` - Team ownership **Benefits of using paths:** - Organize roles by application, team, or environment - Apply IAM policies that scope to path prefixes - Easier auditing and role discovery **Example:** `/production/api/` would allow policies like: ```json { "Effect": "Allow", "Action": "iam:PassRole", "Resource": "arn:aws:iam::*:role/production/api/*" } ```
Set of managed policy ARNs to attach to the role. **AWS managed policies** (recommended for common use cases): - `arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole` - `arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy` - `arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess` - `arn:aws:iam::aws:policy/CloudWatchLogsFullAccess` **Customer managed policies** (for custom permissions): - `arn:aws:iam::123456789012:policy/MyCustomPolicy` **Best practices:** - Prefer managed policies over inline for reusability - Use AWS managed policies when they fit your needs - Create customer managed policies for organization-specific permissions - Maximum 10 managed policies per role (AWS limit)
ARN of the policy to use as a permissions boundary. **What is a permissions boundary?** A permissions boundary sets the maximum permissions a role can have, regardless of what policies are attached. The effective permissions are the intersection of the identity-based policies and the boundary. **Use cases:** - Delegate role creation to developers while limiting maximum permissions - Enforce organization-wide security controls - Prevent privilege escalation in multi-tenant environments **Example boundary policy:** A boundary that prevents IAM modifications: ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "*", "Resource": "*" }, { "Effect": "Deny", "Action": [ "iam:CreateRole", "iam:DeleteRole", "iam:AttachRolePolicy", "iam:PutRolePolicy" ], "Resource": "*" } ] } ``` **Best practices:** - Apply boundaries to all roles created by delegated administrators - Include the boundary in the boundary policy itself to prevent removal - Test thoroughly - boundaries can cause unexpected permission denials
Maximum session duration in seconds for role assumption. **Range:** 3600 (1 hour) to 43200 (12 hours) **Default:** 3600 (1 hour) **When to increase:** - Long-running CI/CD pipelines - Cross-account access requiring extended sessions - Interactive console sessions for debugging **Security consideration:** Use the shortest duration that meets your needs. Shorter sessions reduce the window of exposure if credentials are compromised. **Common durations:** - 1 hour (3600): Default, suitable for most automated tasks - 4 hours (14400): Long CI/CD pipelines - 8 hours (28800): Workday console sessions - 12 hours (43200): Maximum, rarely needed
Whether to force detach policies before destroying the role. **Default:** false When set to `true`, Terraform will automatically detach all managed and inline policies before attempting to delete the role. **When to enable:** - Development environments where roles are frequently recreated - Automated cleanup processes - When policies might be attached outside of Terraform **Caution:** In production, keeping this `false` ensures you're aware of all policies attached to a role before deletion.
Whether to create an EC2 instance profile for this role. **What is an instance profile?** An instance profile is a container for an IAM role that allows EC2 instances to assume the role. EC2 instances cannot directly use IAM roles - they must use instance profiles. **When to enable:** - The role will be used by EC2 instances - The role will be used by ECS container instances (not Fargate) - You need to pass credentials to applications running on EC2 **When NOT needed:** - Lambda functions (use role ARN directly) - ECS Fargate tasks (use task role ARN) - Cross-account access (use role ARN with AssumeRole)
Name of the instance profile. Defaults to the role name if not specified. Only used when `create_instance_profile = true`. **When to customize:** - You need a different name for the instance profile than the role - Migrating from an existing instance profile with a specific name - Organization naming conventions differ for profiles vs roles
Map of tags to apply to all resources created by this module. **Required tags (recommended):** - `Environment`: prod, staging, dev - `Owner`: Team or individual responsible **Optional tags:** - `CostCenter`: For cost allocation - `Service`: Application or service name - `Compliance`: Regulatory requirements (PCI, HIPAA, etc.) **Example:** ```hcl tags = { Environment = "production" Owner = "platform-team" Service = "payment-api" CostCenter = "engineering" } ``` **Note:** The module automatically adds: - `ManagedBy = "terraform"` - `Module = "patterneddesigns/iam-role/aws"`
Outputs
Name of the IAM role. Use the name (not ARN) when: - Attaching policies via aws_iam_role_policy_attachment - Referencing in aws_iam_instance_profile - Using with AWS CLI commands Use the ARN instead when: - Configuring cross-account access - Setting up service-linked resources
Stable and unique string identifying the role. This ID remains constant even if the role is recreated with the same name. Use for: - CloudWatch log group policies scoped to specific roles - S3 bucket policies with aws:userId condition - Audit trails requiring stable identifiers
Unique identifier assigned by AWS (format: AROA...). This is the principal ID used in: - CloudTrail logs for role assumption events - S3 access logs identifying the caller - Resource policies using aws:userId conditions Unlike role_id, this is the AWS-assigned identifier that appears in audit logs and can be used to trace actions back to this role.
Timestamp when the role was created (ISO 8601 format). Useful for: - Auditing role age - Identifying stale roles for cleanup - Compliance reporting
ARN of the instance profile (if created). Only populated when create_instance_profile = true. Use this ARN when: - Launching EC2 instances with aws_instance.iam_instance_profile - Configuring Auto Scaling launch templates - Setting up ECS container instances
Name of the instance profile (if created). Only populated when create_instance_profile = true. Use the name when referencing in: - AWS CLI commands (aws ec2 associate-iam-instance-profile) - CloudFormation templates - Launch configurations
Unique identifier for the instance profile (if created). Only populated when create_instance_profile = true. Format: AIPA... (similar to role unique_id but for profiles)
Verification & Attestation
map[algorithm:sha256 scope:module source files]