Enterprise IAM Governance on AWS

Enforce hard security boundaries with SCPs, OUs, and IAM Identity Center.

Introduction

30 Second Summary

When a company has dozens of AWS accounts, someone needs to decide who can access what and where the hard boundaries live. Without governance, a single misconfigured role can expose production data or rack up costs in regions nobody approved.

In this project, you will build a complete enterprise IAM governance stack on AWS. You will create an Organization with Organizational Units, enforce security boundaries with Service Control Policies, configure federated access through IAM Identity Center, and manage IAM roles entirely through Terraform code.

What You'll Build

By the end, you can sign into the AWS access portal as a federated user, attempt an action in a blocked region and watch it get denied, and run terraform apply to create IAM roles without ever touching the console.

By the end of this project, you'll have:

  • A working AWS Organization with a Production and Development OU hierarchy, where SCPs physically block unapproved regions and root user actions.
  • A fully configured IAM Identity Center with groups and permission sets that give you federated access to accounts with scoped, temporary credentials.
  • A Terraform project that manages IAM roles as code, demonstrating the "no console clicks for IAM" pattern used in production environments.
  • Secret Mission: Codify the entire governance stack (Organizations, SCPs, Identity Center) as Terraform for a full infrastructure-as-code interview answer.

Are there any prerequisites?

You need an AWS account with administrator access, the AWS CLI installed and configured, and Terraform installed. Step 1 will verify all of these are working before you start building.

Before We Start

Before we dive in, let's lock in what you're about to build and why this governance pattern matters for enterprise AWS environments.

Set Up Your AWS Organization

Before you can enforce governance boundaries, you need the organizational structure that makes those boundaries possible. A single AWS account has no concept of Service Control Policies or centralized access control.

In this step, you will create an AWS Organization with all features enabled and turn on Service Control Policies. This unlocks the policy engine that enforces hard security boundaries in later steps.

In this step, get ready to:
  • Verify your AWS CLI and Terraform are working.
  • Create an AWS Organization with all features enabled.
  • Enable Service Control Policies on the organization.
Verify your tools are working

Your AWS CLI and Terraform need to be functional before you touch the console. A quick check now saves debugging later.

  • Open a terminal by pressing Cmd+Space (macOS) or the Windows key (Windows), typing Terminal, and pressing Enter.
  • Confirm your AWS CLI is authenticated by running this command:
aws sts get-caller-identity

You should see JSON output containing your Account ID and Arn. This confirms your CLI can talk to AWS.

Seeing an error instead of JSON output?

If you see a credentials error, your AWS CLI is not configured. Run aws configure and enter your access key ID, secret access key, and default region (us-east-1).

If the command is not found, the AWS CLI is not installed. Follow the official AWS CLI installation guide for your operating system.

Help me troubleshoot my AWS CLI authentication

  • Confirm Terraform is installed by running:
terraform --version

You should see a version number in the output. Any recent version works for this project.

Command not found?

If terraform is not recognized, it is not installed or not on your PATH. Follow the official Terraform installation guide for your operating system.

Help me install Terraform

Create the AWS Organization

Now you will create the Organization itself. This turns your current AWS account into the management account, which is the central control point for all governance.

  • Open the AWS Organizations console by navigating to this URL in your browser:
https://console.aws.amazon.com/organizations/v2
  • Choose Create an organization.
  • The default feature set is All Features. Leave this selected and confirm creation.
  • Your account is now the management account of the new Organization.

What just happened?

Creating an Organization with All Features enabled gives you access to SCPs, tag policies, and other governance tools. Your current account becomes the management account, which is the only account that can manage the Organization's structure and policies.

If you are prompted to verify your email, check your inbox for a verification link from AWS and click it before continuing.

  • Confirm your Organization exists by running this in your terminal:
aws organizations describe-organization

You should see JSON output with "FeatureSet": "ALL" in the response. This confirms your Organization is live with all features enabled.

Seeing an error about no organization?

If the command returns an error saying your account is not part of an organization, the creation may not have completed. Return to the Organizations console and check the status. You may need to verify your email first.

Help me create my AWS Organization

Enable SCPs for the organization

Your Organization exists, but Service Control Policies are not enforcing anything yet. You need to explicitly enable the SCP policy type so you can attach policies to Organizational Units in the next steps.

  • In the Organizations console, choose Policies in the left navigation pane.
  • Choose Service control policies.
  • Choose Enable service control policies.

You should now see the FullAWSAccess policy listed and attached to the root. This is the default SCP that allows all actions. In the next steps, you will add deny policies that restrict specific actions.

What is the FullAWSAccess policy?

Every Organization starts with a FullAWSAccess SCP attached to the root. This policy explicitly allows all actions. SCPs work as permission boundaries, so you layer deny policies on top. The FullAWSAccess policy ensures nothing is blocked until you deliberately restrict it.

Don't see the Enable button?

If SCPs appear already enabled with FullAWSAccess listed, you are all set. Creating an Organization with All Features can automatically enable SCPs in some cases.

If you see a permission error, confirm you are signed into the management account (the same account you used to create the Organization).

Help me enable SCPs

Before you move on, predict what you think will happen if you try to use a service in a region that is not us-east-1 right now. Will it succeed or fail?

Right now it will succeed. You have the Organization structure, but no restrictive policies attached yet. The only SCP in place is FullAWSAccess, which allows everything. SCPs only restrict actions when you attach deny policies to an OU or account.

Your Organization is live and SCPs are ready to enforce boundaries. Next up, you will build the OU hierarchy that gives your policies something to target.

Build the OU Hierarchy

Your AWS Organization is live with all features enabled and SCPs ready to go. Now you need structure inside that Organization so you can apply different rules to different environments.

Right now, every account sits in a flat root with no differentiation. Organizational Units (OUs) fix this by letting you group accounts by purpose. A Production OU gets strict rules. A Development OU gets looser rules. This structural foundation is what makes targeted governance possible.

In this step, get ready to:
  • Create a Production OU and a Development OU under Root.
  • Confirm the hierarchy is visible in the Organizations console.
Create Organizational Units

You will create two OUs directly under Root. Each one represents an environment tier that will eventually get its own set of SCPs.

  • In the AWS Organizations console, choose AWS accounts in the left navigation pane.
  • Select the checkbox next to Root.
  • Choose Actions, then under Organizational unit choose Create new.
  • Enter Production as the name.
  • Choose Create organizational unit.

You should see the Production OU appear under Root in the account list.

  • Select the checkbox next to Root again.
  • Choose Actions, then under Organizational unit choose Create new.
  • Enter Development as the name.
  • Choose Create organizational unit.

Why two OUs?

Production workloads need the tightest controls. Region restrictions, root-user lockdowns, and mandatory encryption all belong here. Development accounts need more flexibility so engineers can experiment without tripping compliance guardrails.

By placing accounts into different OUs, you can attach different SCPs to each one. Same organization, different rules per environment.

Don't see the Create new option?

Make sure you selected the checkbox next to Root before choosing Actions. The option only appears when a parent node (Root or another OU) is selected.

help me create an Organizational Unit in AWS Organizations

Observe the hierarchy

Before you move on, take a moment to predict what the tree view should look like. You created two OUs under Root and did not move any accounts. What do you expect to see when you expand the hierarchy?

  • On the AWS accounts page, expand Root in the tree view.
  • Confirm you see the Production and Development OUs listed under Root, along with your management account.

You should see Root at the top, with your management account and both OUs nested beneath it. The management account stays in Root.

Why does the management account stay in Root?

AWS best practice is to never move the management account into an OU. The management account is exempt from SCPs regardless of where it sits. Placing it in an OU creates a false sense of policy enforcement that does not actually apply.

Your OU hierarchy is in place. You have the structural foundation that separates production from development. Next up, you will give those OUs real teeth by attaching SCPs that enforce hard security boundaries no one can bypass.

Enforce Hard Boundaries with SCPs

Your OU hierarchy gives you the structure to separate environments, but right now those OUs are just organizational labels with no teeth. Anyone with AdministratorAccess can still do anything in any region.

Service Control Policies change that. SCPs create boundaries that cannot be bypassed, not even by an administrator in a member account. They are the "hard ceiling" layer of the governance model.

In this step, get ready to:
  • Create an SCP that restricts all actions to approved regions only.
  • Create an SCP that blocks the root user from performing any action in member accounts.
  • Attach both SCPs to the Production OU and test the boundaries.
Create a region restriction SCP

The first policy physically prevents any non-global service action from running outside your approved region. This stops accidental or malicious resource creation in regions you do not monitor.

  • In the AWS Organizations console, choose Policies in the left navigation.
  • Choose Service control policies.
  • Choose Create policy.
  • For Policy name, enter DenyUnauthorizedRegions.
  • In the JSON editor on the left side, select all the default content and replace it by pasting the following policy:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyUnauthorizedRegions",
      "Effect": "Deny",
      "NotAction": [
        "iam:*",
        "organizations:*",
        "route53:*",
        "support:*",
        "sts:*",
        "cloudfront:*"
      ],
      "Resource": "*",
      "Condition": {
        "StringNotEquals": {
          "aws:RequestedRegion": ["us-east-1"]
        }
      }
    }
  ]
}
  • Choose Create policy.

What does this policy do?

This SCP uses a Deny effect with NotAction to block everything EXCEPT the listed global services when the requested region is not us-east-1.

Global services like IAM, Organizations, Route 53, STS, Support, and CloudFront are exempt because they operate without a regional endpoint. Blocking them would break fundamental account operations.

You should now see DenyUnauthorizedRegions listed on the Service control policies page alongside the default FullAWSAccess policy.

Create a deny root user SCP

The second policy blocks every action when the caller is the root user of a member account. This enforces the enterprise pattern of never using root credentials for day-to-day work.

  • From the Service control policies page, choose Create policy.
  • For Policy name, enter DenyRootUserActions.
  • In the JSON editor, select all the default content and replace it with the following policy:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyRootUser",
      "Effect": "Deny",
      "Action": "*",
      "Resource": "*",
      "Condition": {
        "StringLike": {
          "aws:PrincipalArn": ["arn:aws:iam::*:root"]
        }
      }
    }
  ]
}
  • Choose Create policy.

What does this policy do?

The aws:PrincipalArn condition checks if the caller's ARN matches the root user pattern arn:aws:iam::*:root. If it does, every action is denied.

This means even if someone has the root credentials for a member account, the SCP blocks them from doing anything. Root credentials become useless for operations inside the OU.

You should now see both DenyUnauthorizedRegions and DenyRootUserActions listed on the Service control policies page.

Attach SCPs to the Production OU and test

The policies exist but have no effect until you attach them to a target. Attaching them to the Production OU means every member account inside that OU inherits these hard boundaries.

  • Navigate to the AWS accounts page in the left navigation.
  • Choose the Production OU name (click the name, not the radio button) to open its details page.
  • Choose the Policies tab.
  • Under Service Control Policies, choose Attach.
  • Select the radio button next to DenyUnauthorizedRegions and choose Attach policy.
  • Choose Attach again under Service Control Policies.
  • Select the radio button next to DenyRootUserActions and choose Attach policy.

The Policies tab for the Production OU should now show three attached SCPs: FullAWSAccess, DenyUnauthorizedRegions, and DenyRootUserActions.

Why keep FullAWSAccess alongside deny policies?

SCPs use a deny-list strategy here. The FullAWSAccess policy allows all actions by default. Your two Deny policies then subtract from that allowance. Removing FullAWSAccess without a replacement allow-list would block ALL actions in the OU.

Now test whether the region restriction actually works. Before you try, predict what will happen: do you think you will be blocked from creating a resource in a restricted region?

  • In the AWS Console header, click the region selector (top-right) and switch to Asia Pacific (Singapore) ap-southeast-1.
  • Navigate to the S3 console and attempt to choose Create bucket.

You will discover that the bucket creation succeeds. The region restriction did NOT block you.

Why did the SCP not block me?

SCPs affect only member accounts in the OU. They have no effect on users or roles in the management account. Your current account IS the management account, and it sits in Root, not inside the Production OU.

This is a critical interview point. Even if you moved the management account into the Production OU, SCPs still would not apply to it. The management account is always exempt from SCPs. To fully test SCP enforcement, you would need a separate member account placed inside the Production OU.

Don't see your policies on the Production OU?

  • Make sure you clicked the Production OU name (not the radio button) to open its details page before looking at the Policies tab.
  • Confirm you chose Attach under Service Control Policies on the OU details page, not from the root or another OU.
  • If a policy is missing, return to Policies > Service control policies and verify both policies were created successfully.

Still stuck? Help me troubleshoot my SCP attachment to the Production OU.

Your governance stack now has real enforcement. SCPs create a hard ceiling that no IAM policy can override in member accounts. Next up, you will set up IAM Identity Center so humans can actually sign in through a governed access path with temporary, scoped credentials.

Set Up IAM Identity Center

Your Organization now has hard boundaries in place. SCPs physically prevent anyone from using unapproved regions or the root user, even with full admin permissions.

But no one can actually sign in through a governed access path yet. Without a centralized access system, people default to creating IAM users with long-lived access keys. IAM Identity Center replaces that pattern with temporary credentials scoped to specific roles and accounts.

In this step, get ready to:
  • Enable IAM Identity Center as an Organization instance.
  • Create groups and a user in the Identity Center directory.
  • Create permission sets and assign them to your management account.
Enable IAM Identity Center

IAM Identity Center is the service that gives humans a governed way to access AWS accounts. It issues temporary credentials through a web portal instead of long-lived access keys.

  • Open the IAM Identity Center console at https://console.aws.amazon.com/singlesignon/.
  • Under Enable IAM Identity Center, choose Enable.
  • Since you already have an Organization, it enables as an Organization instance automatically.
  • Note the AWS access portal URL shown on the dashboard (it looks like https://d-xxxxxxxxxx.awsapps.com/start). Copy this URL somewhere safe.

You should see the IAM Identity Center dashboard with your portal URL displayed prominently at the top.

What is the AWS access portal?

The access portal is a web page where federated users sign in to get temporary credentials. Instead of managing individual IAM users and static access keys, everyone goes through this single portal.

In production, this portal URL would be connected to an external identity provider like Okta or Microsoft Entra ID. For this project, you will use the built-in Identity Center directory.

Don't see the Enable button?

If IAM Identity Center is already enabled (perhaps from a previous setup), you will see the dashboard directly. That is fine. Continue to the next substep.

If you see an error about permissions, confirm you are signed in as the management account root user or an IAM user with administrator access. Help me troubleshoot IAM Identity Center enablement.

Create groups and a user

Groups define who gets what level of access. You will create two groups that map to different roles in an enterprise, then create a user to test the flow.

  • In the IAM Identity Center navigation pane, choose Groups.
  • Choose Create group.
  • Enter PlatformEngineers in the Group name field.
  • Choose Create group.

You should see PlatformEngineers appear in the groups list.

  • Choose Create group again.
  • Enter Developers in the Group name field.
  • Choose Create group.

Both groups now appear in the list. Next, create a user and add them to the PlatformEngineers group.

  • In the navigation pane, choose Users.
  • Choose Add user.
  • Enter a username (this cannot be changed later).
  • Keep Send an email to this user with password setup instructions selected.
  • Enter your own email address in the Email address field and confirm it.
  • Enter a First name, Last name, and Display name.
  • Choose Next.

Why use your own email?

The invitation email goes to the address you enter. Using your own email lets you accept the invitation and sign into the access portal to verify everything works.

  • On the Add user to groups page, select the checkbox next to PlatformEngineers.
  • Choose Next.
  • On the Review and add user page, confirm the details look correct.
  • Choose Add user.

A notification confirms the user was added. Check your email for a sign-in invitation with the subject line "Invitation to join AWS IAM Identity Center".

Didn't receive the invitation email?

The email comes from no-reply@signin.aws or no-reply@login.awsapps.com. Check your spam folder. The invitation expires in 7 days.

If you still do not see it, go back to the user in IAM Identity Center, choose Reset password, and select Send an email to the user with instructions for resetting the password. Help me troubleshoot IAM Identity Center invitation emails.

Create permission sets and assign to accounts

Permission sets define what someone can do once they sign in. You will create two predefined sets and then assign each to a group on your management account.

  • In the navigation pane, under Multi-account permissions, choose Permission sets.
  • Choose Create permission set.
  • Select Predefined permission set.
  • Choose AdministratorAccess from the policy list.
  • Choose Next.
  • Keep the session duration at 1 hour (the default).
  • Choose Next, then choose Create.

You should see a notification that the permission set was created. Now create the second one.

  • Choose Create permission set again.
  • Select Predefined permission set.
  • Choose ViewOnlyAccess from the policy list.
  • Choose Next, keep the 1-hour session duration, then choose Next and Create.

Both permission sets now appear in the list. Next, assign them to groups on your management account.

What is a permission set?

A permission set is a collection of AWS managed or custom policies that IAM Identity Center turns into an IAM role in the target account. When a user signs in and picks a permission set, they assume that role and get temporary credentials that expire after the session duration.

This means no one ever holds long-lived keys. Credentials rotate automatically every session.

  • In the navigation pane, under Multi-account permissions, choose AWS accounts.
  • Select the checkbox next to your management account.
  • Choose Assign users or groups.
  • On the Groups tab, select the checkbox next to PlatformEngineers.
  • Choose Next.
  • Select the checkbox next to the AdministratorAccess permission set.
  • Choose Next.
  • Review the assignment and choose Submit.

Wait for the account to be configured. A notification confirms the assignment is complete.

  • Repeat the assignment: choose AWS accounts again, select your management account, and choose Assign users or groups.
  • On the Groups tab, select Developers.
  • Choose Next.
  • Select the ViewOnlyAccess permission set.
  • Choose Next, then Submit.

Both groups now have their respective permission sets assigned to the management account.

Before you sign in to the access portal, what do you expect to see? Think about which group your user belongs to and which permission set is assigned to that group.

  • Open the AWS access portal URL that you noted earlier (the https://d-xxxxxxxxxx.awsapps.com/start link from the IAM Identity Center dashboard).
  • Sign in with the user credentials from your invitation email.
  • After signing in, you should see your management account listed with the AdministratorAccess role available.
  • Click on the account and select Management console next to AdministratorAccess to open the AWS Console with scoped permissions.

You land in the AWS Console with temporary credentials issued by IAM Identity Center. This is the governed access path that replaces static IAM users.

Why does the portal show AdministratorAccess?

Your user is a member of the PlatformEngineers group, and you assigned the AdministratorAccess permission set to that group on the management account. IAM Identity Center shows only the permission sets available to you based on your group membership.

In production, different users in different groups would see different permission sets. A developer in the Developers group would only see ViewOnlyAccess here.

Can't sign into the access portal?

Make sure you accepted the invitation email and set a password before trying to sign in. The username is case-sensitive and is exactly what you entered during user creation.

If you see "No AWS accounts available" after signing in, wait a minute and refresh. The account assignment can take a moment to propagate. Help me troubleshoot IAM Identity Center access portal sign-in issues.

Your humans now have a governed access path with temporary credentials. Next up, you will write Terraform code to manage IAM roles without ever clicking through the console.

Manage IAM Roles with Terraform

You have hard boundaries enforced by SCPs and a governed access path through Identity Center. The final piece of the enterprise pattern is how IAM roles actually get created.

In production, no human clicks "Create Role" in the console. Every IAM role and policy lives in a Git repository as Terraform code. Changes go through pull requests, get reviewed, and are applied by a pipeline. In this step, you will write Terraform that creates a scoped deployment role, demonstrating the "Git-managed IAM" workflow.

In this step, get ready to:
  • Create a Terraform project with the AWS provider configured.
  • Define an IAM role with a scoped trust policy as code.
  • Apply the configuration and verify the role exists in AWS.
Create the Terraform project structure

Terraform needs a project directory containing configuration files that declare the infrastructure you want. You will create a minimal project with just the AWS provider configured.

  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir aws-governance-tf
cd aws-governance-tf
  • Open this folder in your code editor.
  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type VS Code (or Cursor) and press Enter to open it.
  • Click File in the top menu bar.
  • Click Open Folder.
  • Select the aws-governance-tf folder on your Desktop, then click Open.
  • Create a new file named main.tf and paste the following provider configuration:
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "us-east-1"
}

What does this code do?

This file tells Terraform two things:

  • The required_providers block declares that you need the AWS provider from HashiCorp's registry, pinned to any version in the 5.x range.
  • The provider block configures the AWS provider to operate in us-east-1. Terraform uses your existing AWS CLI credentials to authenticate.
  • Save main.tf.
  • Initialize Terraform by running this command in your terminal (make sure you are inside the aws-governance-tf folder):
terraform init

You should see Terraform has been successfully initialized! in the output. This means the AWS provider was downloaded and is ready to use.

Seeing an error during init?

  • Make sure your terminal is inside the aws-governance-tf folder. Run pwd to check your current directory.
  • If you see a network error, check your internet connection. Terraform needs to download the provider plugin from the registry.
  • If the file is not found, confirm main.tf is saved in the aws-governance-tf folder (not a subfolder).

Terraform init not working?

✔️ Awesome, I've got everything!

Great. Double check you have saved main.tf and move on to the next substep.

ⓧ I'd like to double check the full code

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "us-east-1"
}
Define IAM roles as code

Instead of creating a role through the console, you will declare it in a Terraform file. The role uses a trust policy with a tag-based condition, meaning only principals tagged with a specific team can assume it.

  • Create a new file named iam_roles.tf in the same aws-governance-tf folder and paste the following code:
# Look up the current AWS account ID dynamically
data "aws_caller_identity" "current" {}

# Create a scoped deployment role
resource "aws_iam_role" "app_deployment" {
  name = "app-deployment-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
        }
        Action = "sts:AssumeRole"
        Condition = {
          StringEquals = {
            "aws:PrincipalTag/team" = "platform"
          }
        }
      }
    ]
  })
}

# Attach S3 full access to the deployment role
resource "aws_iam_role_policy_attachment" "deploy_policy" {
  role       = aws_iam_role.app_deployment.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonS3FullAccess"
}

What does this code do?

  • The data "aws_caller_identity" block fetches your current account ID at plan time, so you do not have to hardcode it.
  • The aws_iam_role resource creates a role named app-deployment-role. Its trust policy only allows principals in your account that carry the tag aws:PrincipalTag/team = platform to assume it.
  • The aws_iam_role_policy_attachment resource attaches the AWS-managed AmazonS3FullAccess policy to the role, scoping what it can do once assumed.

This is the enterprise pattern: the role is scoped both in WHO can use it (tag condition) and WHAT it can do (attached policy). No one hand-creates this in the console.

  • Save iam_roles.tf.
  • Preview what Terraform will create by running:
terraform plan

You should see a summary line at the bottom: Plan: 2 to add, 0 to change, 0 to destroy. This confirms Terraform will create the role and the policy attachment.

Plan shows errors instead of 2 resources?

  • Check for syntax errors in iam_roles.tf. A missing closing brace or bracket is the most common cause.
  • If you see an authentication error, confirm your AWS CLI credentials are still valid by running aws sts get-caller-identity.
  • Make sure you ran terraform init first. If you skipped it, the provider plugin is missing.

Help me debug my terraform plan errors.

✔️ Awesome, I've got everything!

Great. Double check you have saved iam_roles.tf and move on to apply it.

ⓧ I'd like to double check the full code

data "aws_caller_identity" "current" {}

resource "aws_iam_role" "app_deployment" {
  name = "app-deployment-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
        }
        Action = "sts:AssumeRole"
        Condition = {
          StringEquals = {
            "aws:PrincipalTag/team" = "platform"
          }
        }
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "deploy_policy" {
  role       = aws_iam_role.app_deployment.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonS3FullAccess"
}
Apply and verify the role in AWS

The plan showed you what Terraform intends to create. Now you will apply it for real and confirm the role appears in your AWS account.

Before you run the next command, what do you think will happen? How many resources will Terraform create, and where will you find them?

  • Apply the Terraform configuration by running:
terraform apply

What happens during apply?

Terraform shows the same plan output and asks you to confirm. Type yes and press Enter to proceed. Terraform then makes the AWS API calls to create both resources.

  • When prompted, type yes and press Enter to confirm.

You should see Apply complete! Resources: 2 added, 0 changed, 0 destroyed. in the output. Your role now exists in AWS, created entirely from code.

  • Open the IAM console in your browser at https://console.aws.amazon.com/iam/.
  • Click Roles in the left navigation pane.
  • Search for app-deployment-role in the search bar.
  • Click the role name to open it.
  • Check the Trust relationships tab. You should see the condition aws:PrincipalTag/team equals platform.
  • Check the Permissions tab. You should see AmazonS3FullAccess listed.

Why this matters for interviews

This is the workflow in production: code is reviewed in Git, terraform plan runs in CI to preview changes, and terraform apply runs on merge. No console access needed. You can explain this entire pipeline from code to deployed resource.

Role not appearing in IAM?

  • Make sure you are looking in the us-east-1 region. IAM is a global service, but if your console defaulted to a different region the search may behave unexpectedly. Refresh the page.
  • If terraform apply reported an error, re-read the error message. A permissions issue means your CLI credentials may lack the iam:CreateRole permission.
  • Confirm you typed yes at the prompt. If you pressed Enter without typing yes, Terraform cancels the apply.

Help me find my Terraform-created role in the IAM console.

Secret mission

Codify Everything as Terraform

You built the governance layer manually in the console. In a real enterprise, the Organizations structure, OUs, SCPs, and Identity Center configuration would all live in a Git repository as Terraform code. Can you codify the entire stack?

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project uses only free AWS services (Organizations, SCPs, and IAM Identity Center), so there are no ongoing costs.

Resources you used:

  • AWS Organization (with Production and Development OUs).
  • Service Control Policies (DenyUnauthorizedRegions, DenyRootUserActions) attached to the Production OU.
  • IAM Identity Center instance (groups, user, permission sets, account assignments).
  • Terraform-managed IAM role (app-deployment-role).
  • Local Terraform project directory (aws-governance-tf).

Keep everything running

No action needed. Choose this if you are still actively building or plan to extend the governance stack. All services used in this project are free, so nothing will incur charges while idle.

  • Your Organization, OUs, and SCPs remain in place.
  • IAM Identity Center stays enabled with your groups, user, and permission sets.
  • The app-deployment-role IAM role remains in your account.
  • Your local aws-governance-tf folder stays on your machine.

Pause - I'll come back to this later

Shut down active access paths to free up identity overhead while keeping your structure intact. Since all services are free, "pausing" means disabling human access so the configuration stays ready to resume.

  • In the IAM Identity Center console, choose Users, select your user, expand General information, and choose Disable user access. This prevents sign-in to the AWS access portal without deleting anything.
  • Leave everything else in place. OUs, SCPs, permission sets, and the Terraform-managed role cost nothing while idle.

Delete - I don't want to use this again

Remove all project resources and revert your account to a standalone state. Follow these steps in order because some resources have dependencies.

  • Destroy the Terraform-managed IAM role by running the following commands in your terminal:
cd ~/Desktop/aws-governance-tf
terraform destroy
  • Type yes when prompted. This removes app-deployment-role and its policy attachment.
  • Remove permission set assignments. In the IAM Identity Center console, go to Multi-account permissions, then AWS accounts. Select your management account. Under Assigned users and groups, select each group and choose Remove access. Confirm removal.
  • Delete permission sets. In the IAM Identity Center console, go to Multi-account permissions, then Permission sets. Select the AdministratorAccess permission set and choose Delete. Type the permission set name to confirm. Repeat for ViewOnlyAccess.
  • Delete the IAM Identity Center user. Go to Users, select the user, and choose Delete user. Type Delete in the confirmation dialog and confirm.
  • Delete the IAM Identity Center groups. Go to Groups, select PlatformEngineers, and delete it. Repeat for Developers.
  • Delete the IAM Identity Center instance. In the IAM Identity Center console, choose Settings in the left navigation, then the Management tab. In the Delete IAM Identity Center configuration section, choose Delete. Acknowledge each checkbox, type your instance name, and choose Confirm.
  • Detach SCPs from the Production OU. In the AWS Organizations console, go to AWS accounts, select the Production OU, then the Policies tab. Choose Detach next to DenyUnauthorizedRegions and DenyRootUserActions.
  • Delete the SCPs. In Organizations, go to Policies, then Service control policies. Select DenyUnauthorizedRegions and delete it. Repeat for DenyRootUserActions.
  • Delete the OUs. In AWS accounts, select the Production OU, choose Actions, then Delete organizational unit. Repeat for the Development OU.
  • Delete the Organization. Navigate to Settings in the Organizations console and choose Delete organization. Enter the organization ID in the confirmation dialog and choose Delete organization. Your account reverts to a standalone AWS account.
  • Delete the local Terraform project folder by running:
rm -rf ~/Desktop/aws-governance-tf

Windows users

Use this command instead to remove the local folder:

Remove-Item -Recurse -Force ~\Desktop\aws-governance-tf

Nice Work!

Nice Work!

You just built a complete enterprise IAM governance stack on AWS. From an empty account to a fully structured Organization with hard security boundaries, federated access, and infrastructure as code, you now have the pattern that separates production-ready AWS environments from unmanaged ones.

Here's what you learned:

  • Built an AWS Organization with a two-OU hierarchy and attached Service Control Policies that enforce hard boundaries no one can bypass, including region restriction and root user denial.
  • Configured IAM Identity Center with groups and permission sets so humans get temporary, scoped credentials instead of long-lived access keys.
  • Wrote Terraform to manage IAM roles entirely as code, demonstrating the Git-managed IAM workflow used in production environments.
  • Secret Mission: Codified the entire governance stack (Organizations, OUs, SCPs, and Identity Center) as Terraform for the full infrastructure-as-code interview answer.

Ready to quiz yourself?