Features | Important | Examples | Usage | Inputs | Outputs | Related projects | Authors | License
This Terraform module manages AWS IAM to its full extend.
It is only required to have a single module invocation per AWS account, as this module allows the creation of unlimited resources and you will therefore have an auditable single source of truth for IAM.
- Completely configurable via
terraform.tfvarsonly - Arbitrary number of IAM policies, groups, users and roles
- Policies can be defined via JSON or templatable JSON files
- Policies can be defined via
aws_iam_policy_document(Example here) - Groups, users and roles can be attached to an arbitrary number of custom policies, inline policies and existing policy ARN's
- Users can be added to an arbitrary number of groups
- Users support AWS access/secret key rotation
- Roles support trusted entities
- Arbitrary number of identity providers (SAML and OIDC)
- Account settings: account alias and password policy
When creating an IAM user with an Inactive access key, it is initially created with access key set to Active. You will have to run it a second time in order to deactivate the access key.
This is either an issue with the terraform resource aws_iam_access_key or with the AWS api itself.
This module is very flexible and might look a bit complicated at first glance. To show off a few features which are possible, have a look at the following examples.
📄 Also see each example README.md file for more detailed explanations on each of the covered resources. They serve as a documentation purpose as well.
| Example | Description |
|---|---|
| POLICIES | |
| JSON policies | Define JSON policies with variable templating |
| Policies with custom data sources | Use terraform's aws_iam_policy_document data source to create policies and attach them to defined roles. |
| GROUPS / USERS | |
| Groups | Defines groups |
| Users | Defines users |
| Groups, users and policies | Defines groups, users and policies |
| Access key rotation | Shows how to safely rotate AWS access keys for IAM users |
| ROLES | |
| Roles | Define roles (cross-account assumable) |
| ADVANCED | |
| SAML Login | Login into AWS via SAML identity provider and assume cross-account roles. Also read about best-practices for separating login roles and permission roles. |
You can simply clone this repository and add your terraform.tfvars file into the root of this directory.
terraform.tfvars
# --------------------------------------------------------------------------------
# Account Management
# --------------------------------------------------------------------------------
account_alias = "prod-account"
account_pass_policy = {
manage = true
allow_users_to_change_password = true
hard_expiry = false
max_password_age = 365
minimum_password_length = 8
password_reuse_prevention = 5
require_lowercase_characters = true
require_numbers = true
require_symbols = true
require_uppercase_characters = true
}
# --------------------------------------------------------------------------------
# Account Identity provider
# --------------------------------------------------------------------------------
# Add a SAML provider for login
providers_saml = [
{
name = "AzureAD"
file = "path/to/azure/meta.xml"
},
{
name = "ADFS"
file = "path/to/adfs/meta.xml"
}
]
# --------------------------------------------------------------------------------
# Policies, Groups, Users and Roles
# --------------------------------------------------------------------------------
# List of policies to create
# Policies defined here can be used by name in groups, users and roles list
policies = [
{
name = "ro-billing"
path = "/assume/human/"
desc = "Provides read-only access to billing"
file = "policies/ro-billing.json"
vars = {}
},
]
# List of groups to manage
# Groups defined here can be used in users list
groups = [
{
name = "admin-group"
path = null
policies = []
policy_arns = [
"arn:aws:iam::aws:policy/AdministratorAccess",
]
inline_policies = []
},
]
# List of users to manage
users = [
{
name = "admin"
path = null
groups = ["admin-group"]
access_keys = []
permissions_boundary = null
policies = []
policy_arns = []
inline_policies = []
},
]
# List of roles to manage
roles = [
{
name = "ROLE-ADMIN"
path = ""
desc = ""
trust_policy_file = "trust-policies/admin.json"
permissions_boundary = null
policies = []
policy_arns = [
"arn:aws:iam::aws:policy/AdministratorAccess",
]
inline_policies = []
},
{
name = "ROLE-DEV"
path = ""
desc = ""
trust_policy_file = "trust-policies/dev.json"
permissions_boundary = "arn:aws:iam::aws:policy/PowerUserAccess"
policies = [
"ro-billing",
]
policy_arns = [
"arn:aws:iam::aws:policy/PowerUserAccess",
]
inline_policies = []
},
]
# --------------------------------------------------------------------------------
# Defaults
# --------------------------------------------------------------------------------
policy_path = "/"
policy_desc = "Managed by Terraform"
group_path = "/"
user_path = "/"
role_path = "/"
role_desc = "Managed by Terraform"
role_max_session_duration = 3600
role_force_detach_policies = true
tags = {
env = "prod"
owner = "terraform"
}Create your own module by sourcing this module.
module "iam_roles" {
source = "github.com/cytopia/terraform-aws-iam?ref=v5.0.5"
# --------------------------------------------------------------------------------
# Account Management
# --------------------------------------------------------------------------------
account_alias = "prod-account"
account_pass_policy = {
manage = true
allow_users_to_change_password = true
hard_expiry = false
max_password_age = 365
minimum_password_length = 8
password_reuse_prevention = 5
require_lowercase_characters = true
require_numbers = true
require_symbols = true
require_uppercase_characters = true
}
# --------------------------------------------------------------------------------
# Account Identity provider
# --------------------------------------------------------------------------------
# Add a SAML provider for login
providers_saml = [
{
name = "AzureAD"
file = "path/to/azure/meta.xml"
},
{
name = "ADFS"
file = "path/to/adfs/meta.xml"
}
]
# --------------------------------------------------------------------------------
# Policies, Groups, Users and Roles
# --------------------------------------------------------------------------------
# List of policies to create
# Policies defined here can be used by name in groups, users and roles list
policies = [
{
name = "ro-billing"
path = "/assume/human/"
desc = "Provides read-only access to billing"
file = "policies/ro-billing.json"
vars = {}
},
]
# List of groups to manage
# Groups defined here can be used in users list
groups = [
{
name = "admin-group"
path = null
policies = []
policy_arns = [
"arn:aws:iam::aws:policy/AdministratorAccess",
]
inline_policies = []
},
]
# List of users to manage
users = [
{
name = "admin"
path = null
groups = ["admin-group"]
access_keys = []
permissions_boundary = null
policies = []
policy_arns = []
inline_policies = []
},
]
# List of roles to manage
roles = [
{
name = "ROLE-ADMIN"
path = ""
desc = ""
trust_policy_file = "trust-policies/admin.json"
permissions_boundary = null
policies = []
policy_arns = [
"arn:aws:iam::aws:policy/AdministratorAccess",
]
inline_policies = []
},
{
name = "ROLE-DEV"
path = ""
desc = ""
trust_policy_file = "trust-policies/dev.json"
permissions_boundary = "arn:aws:iam::aws:policy/PowerUserAccess"
policies = [
"ro-billing",
]
policy_arns = [
"arn:aws:iam::aws:policy/PowerUserAccess",
]
inline_policies = []
},
]
# --------------------------------------------------------------------------------
# Defaults
# --------------------------------------------------------------------------------
policy_path = "/"
policy_desc = "Managed by Terraform"
group_path = "/"
user_path = "/"
role_path = "/"
role_desc = "Managed by Terraform"
role_max_session_duration = 3600
role_force_detach_policies = true
tags = {
env = "prod"
owner = "terraform"
}
}Wrap this module into Terragrunt
terraform {
source = "github.com/cytopia/terraform-aws-iam?ref=v5.0.5"
}
inputs = {
# --------------------------------------------------------------------------------
# Account Management
# --------------------------------------------------------------------------------
account_alias = "prod-account"
account_pass_policy = {
manage = true
allow_users_to_change_password = true
hard_expiry = false
max_password_age = 365
minimum_password_length = 8
password_reuse_prevention = 5
require_lowercase_characters = true
require_numbers = true
require_symbols = true
require_uppercase_characters = true
}
# --------------------------------------------------------------------------------
# Account Identity provider
# --------------------------------------------------------------------------------
# Add a SAML providers for login
providers_saml = [
{
name = "AzureAD"
file = "path/to/azure/meta.xml"
},
{
name = "ADFS"
file = "path/to/adfs/meta.xml"
}
]
# --------------------------------------------------------------------------------
# Policies, Groups, Users and Roles
# --------------------------------------------------------------------------------
# List of policies to create
# Policies defined here can be used by name in groups, users and roles list
policies = [
{
name = "ro-billing"
path = "/assume/human/"
desc = "Provides read-only access to billing"
file = "policies/ro-billing.json"
vars = {}
},
]
# List of groups to manage
# Groups defined here can be used in users list
groups = [
{
name = "admin-group"
path = null
policies = []
policy_arns = [
"arn:aws:iam::aws:policy/AdministratorAccess",
]
inline_policies = []
},
]
# List of users to manage
users = [
{
name = "admin"
path = null
groups = ["admin-group"]
access_keys = []
permissions_boundary = null
policies = []
policy_arns = []
inline_policies = []
},
]
# List of roles to manage
roles = [
{
name = "ROLE-ADMIN"
path = ""
desc = ""
trust_policy_file = "trust-policies/admin.json"
permissions_boundary = null
policies = []
policy_arns = [
"arn:aws:iam::aws:policy/AdministratorAccess",
]
inline_policies = []
},
{
name = "ROLE-DEV"
path = ""
desc = ""
trust_policy_file = "trust-policies/dev.json"
permissions_boundary = "arn:aws:iam::aws:policy/PowerUserAccess"
policies = [
"ro-billing",
]
policy_arns = [
"arn:aws:iam::aws:policy/PowerUserAccess",
]
inline_policies = []
},
]
# --------------------------------------------------------------------------------
# Defaults
# --------------------------------------------------------------------------------
policy_path = "/"
policy_desc = "Managed by Terraform"
group_path = "/"
user_path = "/"
role_path = "/"
role_desc = "Managed by Terraform"
role_max_session_duration = 3600
role_force_detach_policies = true
tags = {
env = "prod"
owner = "terraform"
}
}No required input.
The following input variables are optional (have default values):
Description: Assign the account alias for the AWS Account. Unmanaged by default. Resource will be created if the string is non-empty.
Type: string
Default: ""
Description: Manages Password Policy for the AWS Account. Unmanaged by default. Resource will be created if 'manage' is set to true.
Type:
object({
manage = bool # Set to true, to manage the AWS account password policy
allow_users_to_change_password = bool # Allow users to change their own password?
hard_expiry = bool # Users are prevented from setting a new password after their password has expired?
max_password_age = number # Number of days that an user password is valid
minimum_password_length = number # Minimum length to require for user passwords
password_reuse_prevention = number # The number of previous passwords that users are prevented from reusing
require_lowercase_characters = bool # Require lowercase characters for user passwords?
require_numbers = bool # Require numbers for user passwords?
require_symbols = bool # Require symbols for user passwords?
require_uppercase_characters = bool # Require uppercase characters for user passwords?
})Default:
{
"allow_users_to_change_password": null,
"hard_expiry": null,
"manage": false,
"max_password_age": null,
"minimum_password_length": null,
"password_reuse_prevention": null,
"require_lowercase_characters": null,
"require_numbers": null,
"require_symbols": null,
"require_uppercase_characters": null
}Description: A list of dictionaries defining saml providers.
Type:
list(object({
name = string # The name of the provider to create
file = string # Path to XML generated by identity provider that supports SAML 2.0
}))Default: []
Description: A list of dictionaries defining openid connect providers.
Type:
list(object({
url = string # URL of the identity provider. Corresponds to the iss claim
client_id_list = list(string) # List of client IDs (also known as audiences)
thumbprint_list = list(string) # List of server certificate thumbprints.
}))Default: []
Description: A list of dictionaries defining all policies.
Type:
list(object({
name = string # Name of the policy
path = string # Defaults to 'var.policy_path' if variable is set to null
desc = string # Defaults to 'var.policy_desc' if variable is set to null
file = string # Path to json or json.tmpl file of policy
vars = map(string) # Policy template variables {key: val, ...}
}))Default: []
Description: A list of dictionaries defining all groups.
Type:
list(object({
name = string # Name of the group
path = string # Defaults to 'var.group_path' if variable is set to null
policies = list(string) # List of names of policies (must be defined in var.policies)
policy_arns = list(string) # List of existing policy ARN's
inline_policies = list(object({
name = string # Name of the inline policy
file = string # Path to json or json.tmpl file of policy
vars = map(string) # Policy template variables {key = val, ...}
}))
}))Default: []
Description: A list of dictionaries defining all users.
Type:
list(object({
name = string # Name of the user
path = string # Defaults to 'var.user_path' if variable is set to null
groups = list(string) # List of group names to add this user to
access_keys = list(object({
name = string # IaC identifier for first or second IAM access key (not used on AWS)
pgp_key = string # Leave empty for non or provide a b64-enc pubkey or keybase username
status = string # 'Active' or 'Inactive'
}))
permissions_boundary = string # ARN to a policy used as permissions boundary (or null/empty)
policies = list(string) # List of names of policies (must be defined in var.policies)
policy_arns = list(string) # List of existing policy ARN's
inline_policies = list(object({
name = string # Name of the inline policy
file = string # Path to json or json.tmpl file of policy
vars = map(string) # Policy template variables {key = val, ...}
}))
}))Default: []
Description: A list of dictionaries defining all roles.
Type:
list(object({
name = string # Name of the role
path = string # Defaults to 'var.role_path' if variable is set to null
desc = string # Defaults to 'var.role_desc' if variable is set to null
trust_policy_file = string # Path to file of trust/assume policy
permissions_boundary = string # ARN to a policy used as permissions boundary (or null/empty)
policies = list(string) # List of names of policies (must be defined in var.policies)
policy_arns = list(string) # List of existing policy ARN's
inline_policies = list(object({
name = string # Name of the inline policy
file = string # Path to json or json.tmpl file of policy
vars = map(string) # Policy template variables {key = val, ...}
}))
}))Default: []
Description: The default path under which to create the policy if not specified in the policies list. You can use a single path, or nest multiple paths as if they were a folder structure. For example, you could use the nested path /division_abc/subdivision_xyz/product_1234/engineering/ to match your company's organizational structure.
Type: string
Default: "/"
Description: The default description of the policy.
Type: string
Default: "Managed by Terraform"
Description: The path under which to create the group. You can use a single path, or nest multiple paths as if they were a folder structure. For example, you could use the nested path /division_abc/subdivision_xyz/product_1234/engineering/ to match your company's organizational structure.
Type: string
Default: "/"
Description: The path under which to create the user. You can use a single path, or nest multiple paths as if they were a folder structure. For example, you could use the nested path /division_abc/subdivision_xyz/product_1234/engineering/ to match your company's organizational structure.
Type: string
Default: "/"
Description: The path under which to create the role. You can use a single path, or nest multiple paths as if they were a folder structure. For example, you could use the nested path /division_abc/subdivision_xyz/product_1234/engineering/ to match your company's organizational structure.
Type: string
Default: "/"
Description: The description of the role.
Type: string
Default: "Managed by Terraform"
Description: The maximum session duration (in seconds) that you want to set for the specified role. This setting can have a value from 1 hour to 12 hours specified in seconds.
Type: string
Default: "3600"
Description: Specifies to force detaching any policies the role has before destroying it.
Type: bool
Default: true
Description: Key-value mapping of tags for the IAM role or user.
Type: map(any)
Default: {}
| Name | Description |
|---|---|
| account_alias | Created Account alias. |
| account_pass_policy | Created Account password policy. |
| debug_local_group_inline_policies | The transformed group inline policy map |
| debug_local_group_policies | The transformed group policy map |
| debug_local_group_policy_arns | The transformed group policy arns map |
| debug_local_policies | The transformed policy map |
| debug_local_role_inline_policies | The transformed role inline policy map |
| debug_local_role_policies | The transformed role policy map |
| debug_local_role_policy_arns | The transformed role policy arns map |
| debug_local_user_access_keys | The transformed user access key map |
| debug_local_user_inline_policies | The transformed user inline policy map |
| debug_local_user_policies | The transformed user policy map |
| debug_local_user_policy_arns | The transformed user policy arns map |
| debug_var_groups | The defined groups list |
| debug_var_policies | The transformed policy map |
| debug_var_roles | The defined roles list |
| debug_var_users | The defined users list |
| group_inline_policy_attachments | Attached group inline IAM policies |
| group_policy_arn_attachments | Attached group IAM policy arns |
| group_policy_attachments | Attached group customer managed IAM policies |
| groups | Created IAM groups |
| policies | Created customer managed IAM policies |
| providers_oidc | Created OpenID Connect providers. |
| providers_saml | Created SAML providers. |
| role_inline_policy_attachments | Attached role inline IAM policies |
| role_policy_arn_attachments | Attached role IAM policy arns |
| role_policy_attachments | Attached role customer managed IAM policies |
| roles | Created IAM roles |
| user_group_memberships | Assigned user/group memberships |
| user_inline_policy_attachments | Attached user inline IAM policies |
| user_policy_arn_attachments | Attached user IAM policy arns |
| user_policy_attachments | Attached user customer managed IAM policies |
| users | Created IAM users |
| GitHub | Module Registry | Description |
|---|---|---|
| aws-iam | aws-iam | Manages AWS IAM to its full extend |
| aws-iam-roles | aws-iam-roles | Deprecated by aws-iam |
| aws-iam-cross_account | aws-iam-cross-account | Deprecated by aws-iam |
| aws-route53 | aws-route53 | Manages creation of multiple Route53 zones including attachment to new or existing delegation set |
| aws-elb | aws-elb | Manages ELB with optionally a public and/or private Route53 DNS record attached to it |
| aws-rds | aws-rds | Manages RDS resources on AWS |
Module managed by cytopia.
Copyright (c) 2018 cytopia