AWS IAM & Identity Center User Management with Terraform

Mini Project 3 – Day 16 of My Terraform Journey 🚀
As I move deeper into Terraform, I’ve started focusing on real-world operational problems, not just resource creation.
Today’s learning was a big step toward enterprise-grade AWS management.
I built a complete IAM + AWS Identity Center (SSO) user management system using Terraform, fully driven by data and automation.
This mini project taught me how organizations actually manage users, access, and permissions at scale.
Project Goal
The goal of this mini project was simple but powerful:
Manage IAM users, groups, and permissions using Terraform
Create users dynamically from a CSV-based data source
Assign users to IAM groups based on departments
Replicate the same setup using AWS Identity Center (SSO)
Provide single sign-on (SSO) access using Permission Sets
Everything is automated.
No manual clicks. No console chaos.
Architecture Overview
IAM (Classic AWS IAM)
IAM Users
IAM Groups (Education, Corporate, Accounting)
Group-based permissions
Console access with forced password reset
AWS Identity Center (SSO)
Identity Store Users
Identity Store Groups
Permission Sets
Account Assignments
Step 1: Creating IAM Users Dynamically
Instead of hardcoding users, I used a local variable (CSV-backed) and created IAM users dynamically.
🔹 What I learned
for_eachis extremely powerfulNaming conventions can be enforced programmatically
Tags help drive logic (department-based access)
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 = {
department = each.value.department
}
}
Step 2: Enabling Console Access Securely
Each IAM user gets:
Console login
Forced password reset on first login
resource "aws_iam_user_login_profile" "example" {
for_each = aws_iam_user.users
user = each.value.name
password_reset_required = true
lifecycle {
ignore_changes = [
password_length,
password_reset_required,
]
}
}
👉 This avoids password drift issues during re-applies.
Step 3: Creating IAM Groups
I created department-based IAM groups:
resource "aws_iam_group" "education" {
name = "Education"
}
resource "aws_iam_group" "corporate" {
name = "Corporate"
}
resource "aws_iam_group" "accounting" {
name = "Accounting"
}
Step 4: Smart Group Membership (No Manual Mapping)
Here’s where Terraform shines ✨
Users are automatically added to groups based on tags.
resource "aws_iam_group_membership" "Education" {
name = "Adding education"
users = [
for user in aws_iam_user.users : user.name
if user.tags.department == "Education"
]
group = aws_iam_group.education.name
}
Step 5: Attaching Policies to Groups
Instead of attaching policies to users, I followed best practices:
resource "aws_iam_group_policy_attachment" "Education-ReadOnly" {
group = aws_iam_group.education.name
policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess"
}
Step 6: Moving to AWS Identity Center (SSO)
This was the most exciting part of the project.
I used Terraform to:
Discover the Identity Store
Create SSO users
Create groups
Assign permission sets
Enable AWS account access
Step 7: Creating Identity Center Users
Only Education department users were synced to SSO:
resource "aws_identitystore_user" "example" {
identity_store_id = tolist(data.aws_ssoadmin_instances.example.identity_store_ids)[0]
for_each = {
for user in local.users :
lower("${substr(user.first_name, 0, 1)}${user.last_name}") => user
if user.department == "Education"
}
display_name = "${each.value.first_name} ${each.value.last_name}"
user_name = each.key
name {
given_name = each.value.first_name
family_name = each.value.last_name
}
emails {
value = "${each.value.first_name}.${each.value.last_name}@example.com"
}
}
Step 8: Identity Store Groups & Memberships
resource "aws_identitystore_group" "education_group" {
identity_store_id = tolist(data.aws_ssoadmin_instances.example.identity_store_ids)[0]
display_name = "Education Group"
}
resource "aws_identitystore_group_membership" "name" {
for_each = aws_identitystore_user.example
identity_store_id = tolist(data.aws_ssoadmin_instances.example.identity_store_ids)[0]
group_id = aws_identitystore_group.education_group.group_id
member_id = each.value.user_id
}
Step 9: Permission Sets (SSO Access Control)
Instead of IAM policies, SSO uses Permission Sets.
resource "aws_ssoadmin_permission_set" "permission_set" {
name = "Education-Permission-Set"
instance_arn = tolist(data.aws_ssoadmin_instances.example.arns)[0]
session_duration = "PT1H"
}
Attach managed policy:
resource "aws_ssoadmin_managed_policy_attachment" "permission_set_attachment" {
instance_arn = tolist(data.aws_ssoadmin_instances.example.arns)[0]
permission_set_arn = aws_ssoadmin_permission_set.permission_set.arn
managed_policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}
Step 10: Assigning Access to AWS Account
resource "aws_ssoadmin_account_assignment" "attaching_permission_to_group" {
instance_arn = tolist(data.aws_ssoadmin_instances.example.arns)[0]
permission_set_arn = aws_ssoadmin_permission_set.permission_set.arn
principal_id = aws_identitystore_group.education_group.group_id
principal_type = "GROUP"
target_id = data.aws_caller_identity.current.account_id
target_type = "AWS_ACCOUNT"
}
Now users can log in using SSO and access AWS securely.
What I Learned from This Mini Project
How real companies manage users at scale
IAM vs Identity Center differences
Data-driven infrastructure
Terraform loops & conditions in real scenarios
Secure, repeatable access management
📺 Video That Helped Me Understand this concept:
If you’re learning Terraform and AWS access management — this project will change how you think about IAM.




