DEV Community

Cover image for AWS Terraform IAM User Management
Adarsh Gupta
Adarsh Gupta

Posted on

AWS Terraform IAM User Management

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
}
Enter fullscreen mode Exit fullscreen mode

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
  }
}
Enter fullscreen mode Exit fullscreen mode

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
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

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/"
}
Enter fullscreen mode Exit fullscreen mode

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"
  ]
}
Enter fullscreen mode Exit fullscreen mode

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))
  ]
}
Enter fullscreen mode Exit fullscreen mode

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"
  ]
}
Enter fullscreen mode Exit fullscreen mode

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"
          }
        }
      }
    ]
  })
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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" {}
Enter fullscreen mode Exit fullscreen mode

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.


Embedded Video Tutorial

@piyushsachdeva


Top comments (0)