Managing IAM users manually in AWS can quickly become complex, error-prone, and difficult to scale. As teams grow, you need a repeatable, auditable, and secure way to manage users, groups, permissions, and security controls like MFA.
In this blog, we’ll explore how to implement AWS IAM user management using Terraform, driven by a CSV file as the single source of truth.
Why Use Terraform for IAM User Management?
Using Terraform for IAM offers several advantages:
- Centralized and version-controlled user management
- Easy onboarding and offboarding of users
- Consistent security policies across teams
- Reduced manual errors
- Idempotent and auditable changes
Instead of clicking through the AWS Console, we define everything declaratively.
Architecture Overview
This setup includes:
- IAM users created dynamically from a CSV file
- IAM groups for Education, Managers, and Engineers
- Automatic group membership based on user attributes
- Console access with forced password reset
- MFA enforcement across all groups
- Group-based permission management
The CSV file becomes the single source of truth for identity data.
Reading User Data from CSV
We begin by loading user data from a CSV file.
locals {
users = csvdecode(file("users.csv")) // It gives list of maps for the data
}
Terraform converts each row into a map, allowing us to loop over users dynamically. This makes adding or removing users as simple as editing the CSV.
Creating IAM Users Dynamically
IAM users are created using for_each, ensuring scalability and consistency.
resource "aws_iam_user" "users" {
for_each = { for user in local.users : user.first_name => user }
name = lower("${substr(each.value.first_name, 0, 1)}${each.value.last_name}")
path = "/users/"
tags = {
DisplayName = "${each.value.first_name} ${each.value.last_name}"
Department = each.value.department
JobTitle = each.value.job_title
Email = each.value.email
Phone = each.value.phone
}
}
Key points:
- Usernames are generated automatically (
first initial + last name) - Tags store rich metadata for filtering, auditing, and policies
- No hardcoding of users
Enabling Console Access Securely
To allow AWS Console access, we create login profiles.
resource "aws_iam_user_login_profile" "users" {
for_each = aws_iam_user.users
user = each.value.name
password_reset_required = true
lifecycle {
ignore_changes = [
password_reset_required,
password_length
]
}
}
This enforces a password reset on first login, aligning with security best practices.
Creating IAM Groups
Groups are used to manage permissions collectively.
resource "aws_iam_group" "education" {
name = "Education"
path = "/groups/"
}
resource "aws_iam_group" "managers" {
name = "Managers"
path = "/groups/"
}
resource "aws_iam_group" "engineers" {
name = "Engineers"
path = "/groups/"
}
This allows permissions to be managed at the group level instead of per user.
Dynamic Group Membership Assignment
Users are automatically assigned to groups based on their attributes.
Education Group
resource "aws_iam_group_membership" "education_members" {
name = "education-group-membership"
group = aws_iam_group.education.name
users = [
for user in aws_iam_user.users : user.name
if user.tags.Department == "Education"
]
}
Managers Group (based on job title)
resource "aws_iam_group_membership" "managers_members" {
name = "managers-group-membership"
group = aws_iam_group.managers.name
users = [
for user in aws_iam_user.users : user.name
if contains(keys(user.tags), "JobTitle") &&
can(regex("Manager|CEO", user.tags.JobTitle))
]
}
Engineers Group
resource "aws_iam_group_membership" "engineers_members" {
name = "engineers-group-membership"
group = aws_iam_group.engineers.name
users = [
for user in aws_iam_user.users : user.name
if user.tags.Department == "Engineering"
]
}
This approach eliminates manual group assignment and ensures accuracy.
Enforcing MFA for All Users
Terraform cannot create MFA devices, but it can enforce MFA usage through IAM policies.
resource "aws_iam_policy" "require_mfa" {
name = "Require-MFA"
description = "Deny access unless MFA is enabled"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "DenyAllExceptMFA"
Effect = "Deny"
Action = "*"
Resource = "*"
Condition = {
BoolIfExists = {
"aws:MultiFactorAuthPresent" = "false"
}
}
}
]
})
}
This policy denies all AWS actions unless MFA is enabled.
Attaching MFA Policy to Groups
resource "aws_iam_group_policy_attachment" "mfa_enforcement" {
for_each = {
education = aws_iam_group.education.name
managers = aws_iam_group.managers.name
engineers = aws_iam_group.engineers.name
}
group = each.value
policy_arn = aws_iam_policy.require_mfa.arn
}
Once attached, all users in these groups must enable MFA to access AWS.
Attaching Permissions to Groups
Permissions are granted using AWS managed policies.
resource "aws_iam_group_policy_attachment" "education_readonly" {
group = aws_iam_group.education.name
policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}
resource "aws_iam_group_policy_attachment" "managers_admin" {
group = aws_iam_group.managers.name
policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}
resource "aws_iam_group_policy_attachment" "engineers_poweruser" {
group = aws_iam_group.engineers.name
policy_arn = "arn:aws:iam::aws:policy/PowerUserAccess"
}
This ensures:
- Education users have read-only access
- Managers have full administrative access
- Engineers can manage resources but not IAM
AWS Account Verification
data "aws_caller_identity" "current" {}
This is useful for outputs, debugging, and ensuring Terraform is operating in the correct AWS account.
Security and Best Practices
- MFA enforced across all users
- Permissions applied via groups, not users
- Metadata stored as tags for auditing
- CSV-driven user lifecycle management
- Infrastructure fully reproducible and auditable
For production environments, AWS IAM Identity Center (SSO) is recommended instead of IAM users.
Conclusion
This Terraform-based IAM user management solution demonstrates how identity can be treated as code, not configuration. By combining CSV-driven data, dynamic group membership, MFA enforcement, and least-privilege access, you get a scalable and secure IAM architecture suitable for real-world environments.
This approach not only simplifies administration but also aligns closely with modern DevOps and security best practices.
Top comments (0)