Govern permission sets for multiple accounts by using Account Factory for Terraform
Anand Krishna Varanasi and Siamak Heshmati, Amazon Web Services
Summary
This pattern helps you integrate AWS Control Tower Account Factory Terraform (AFT) with AWS IAM Identity Center in order to configure permissions for multiple AWS accounts at scale. This approach uses custom AWS Lambda functions to automate permission set assignments to AWS accounts that are managed as an organization. This streamlines the process because it doesn’t require manual intervention from your platform engineering team. This solution can enhance operational efficiency, security and consistency. It promotes a secure and standardized onboarding process for AWS Control Tower, making it indispensable for enterprises that prioritize agility and reliability for their cloud infrastructure.
Prerequisites and limitations
Prerequisites
AWS accounts, managed through AWS Control Tower. For more information, see Getting started with AWS Control Tower.
Account Factory for Terraform, deployed in a dedicated account in your environment. For more information, see Deploy AWS Control Tower Account Factory for Terraform.
An IAM Identity Center instance, set up in your environment. For more information, see Getting started with IAM Identity Center.
An active IAM Identity Center group, configured. For more information, see Add groups to your IAM Identity Center directory.
Python version 3.9 or later, installed
Limitations
This solution can be used only with accounts that are managed through AWS Control Tower. This solution is deployed by using Account Factory for Terraform.
This pattern does not include instructions for setting up identity federation with an identity source. For more information about how to complete this set up, see IAM Identity Center identity source tutorials in the IAM Identity Center documentation.
Architecture
AFT overview
AFT sets up a Terraform pipeline that helps you provision and customize your accounts in AWS Control Tower. AFT follows a GitOps model that automates the processes of account provisioning in AWS Control Tower. You create an account request Terraform file and commit it to repository. This initiates the AFT workflow for account provisioning. After account provisioning is complete, AFT can automatically run additional customization steps. For more information, see AFT architecture in the AWS Control Tower documentation.
AFT provides the following main repositories:
aft-account-request
– This repository contains Terraform code to create or update AWS accounts.aft-account-customizations
– This repository contains Terraform code to create or customize resources on a per-account basis.aft-global-customizations
– This repository contains Terraform code to create or customize resources for all accounts, at scale.aft-account-provisioning-customizations
– This repository manages customizations that are applied only to specific accounts created by and managed with AFT. For example, you might use this repository to customize user or groups assignments in IAM Identity Center or to automate account closures.
Solution overview
This custom solution includes an AWS Step Functions state machine and an AWS Lambda function that assign permission sets to users and groups for multiple accounts. The state machine deployed through this pattern operates in conjunction with pre-existing AFT aft_account_provisioning_customizations
state machine. A user submits a request to update IAM Identity Center user and group assignments either when a new AWS account is created or after the account is created. They do this by pushing a change to the aft-account-request
repository. The request to create or update an account initiates a stream in Amazon DynamoDB Streams. This starts the Lambda function, which updates IAM Identity Center users and groups for the target AWS accounts.
The following is an example of the parameters you can provide in the Lambda function for permission set assignments to target users and groups:
custom_fields = { "InstanceArn" = "<Organization ID>", "PermissionSetArn" = "<Permission set ARN>", "PrincipalId" = "<Principal ID>", }
The following are the parameters in this statement:
InstanceArn
– The Amazon Resource Name (ARN) of the organizationPermissionSetArn
– The ARN of the permission setPrincipalId
– The identifier of a user or group in IAM Identity Center to which the permission set will be applied
Note
You must create the target permission set, users, and groups before running this solution.
While the InstanceArn
value must remain consistent, you can modify the Lambda function to assign multiple permission sets to multiple target identities. The parameters for permission sets must end in PermissionSetArn
, and the parameters for users and groups must end in PrincipalId
. You must define both attributes. The following is an example of how to define multiple permission sets and target users and groups:
custom_fields = { "InstanceArn" = "<Organization ID>", "AdminAccessPermissionSetArn" = "<Admin privileges permission set ARN>", "AdminAccessPrincipalId" = "<Admin principal ID>", "ReadOnlyAccessPermissionSetArn" = "<Read-only privileges permission set ARN>", "ReadOnlyAccessPrincipalId" = "<Read-only principal ID>", }
The following diagram shows a step-by-step workflow of how the solution updates permissions sets for users and groups in the target AWS accounts at scale. When the user initiates an account creation request, AFT initiates the aft-account-provisioning-framework
Step Functions state machine. This state machine starts the extract-alternate-sso
Lambda function. The Lambda function assigns permissions sets to users and groups in the target AWS accounts. These users or groups can be from any configured identity source in IAM Identity Center. Examples of identity sources include Okta, Active Directory, or Ping Identity.

The diagram shows the following workflow when new accounts are created:
A user pushes a
custom_fields
change to theaft-account-request
repository.AWS CodePipeline starts an AWS CodeBuild job that records the user-defined metadata into the
aft-request-audit
Amazon DynamoDB table. This table has attributes to record user-defined metadata. Theddb_event_name
attribute defines the type of AFT operation:If the value is
INSERT
, then the solution assigns the permissions set to the target identities when the new AWS account is created.If the value is
UPDATE
, then the solution assigns the permissions set to the target identities after the AWS account is created.
Amazon DynamoDB Streams initiates the
aft_alternate_sso_extract
Lambda function.The
aft_alternate_sso_extract
Lambda function assumes an AWS Identity and Access Management (IAM) role in the AWS Control Tower management account.The Lambda function assigns the permissions sets to the target users and groups by making an AWS SDK for Python (Boto3) create_account_assignment
API call to IAM Identity Center. It retrieves the permission set and identity assignments from the aft-request-audit
Amazon DynamoDB table.When the Step Functions workflow completes, the permission sets are assigned to the target identities.
Automation and scale
AFT operates at scale by using AWS services such as CodePipeline, AWS CodeBuild, DynamoDB, and Lambda, which are highly scalable. For additional automation, you can integrate this solution with a ticket or issue management system, such as Jira. For more information, see the Additional information section of this pattern.
Tools
AWS services
Account Factory for Terraform (AFT) is the main tool in this solution. The
aft-account-provisioning-customizations
repository contains the Terraform code for creating customizations for AWS accounts, such as custom IAM Identity Center user or group assignments.Amazon DynamoDB is a fully managed NoSQL database service that provides fast, predictable, and scalable performance.
AWS Lambda is a compute service that helps you run code without needing to provision or manage servers. It runs your code only when needed and scales automatically, so you pay only for the compute time that you use.
AWS Step Functions is a serverless orchestration service that helps you combine AWS Lambda functions and other AWS services to build business-critical applications.
Other tools
Code repository
The code repository for AFT is available in the GitHub AWS Control Tower Account Factory for Terraform
Best practices
Understand the AWS shared responsibility model
. Follow the security recommendations for AWS Control Tower. For more information, see Security in AWS Control Tower.
Follow the principle of least privilege. For more information, see Apply least-privilege permissions.
Build specific and focused permission sets and IAM roles for groups and business units.
Epics
Task | Description | Skills required |
---|---|---|
Create an IAM role. | In the AWS Control Tower management account, use Terraform to create an IAM role. This role has cross-account access and a trust policy that allows federated access from the identity provider. It also has permissions to grant access to other accounts through AWS Control Tower. The Lambda function will assume this role. Do the following:
| AWS DevOps, Cloud architect |
Customize the solution for your environment. |
| AWS DevOps, Cloud architect |
Deploy the solution. |
| AWS DevOps, Cloud architect |
Set up a code repository connection. | Set up a connection between the code repository where you will store the configuration files and your AWS account. For instructions, see the Add third-party source providers to pipelines using CodeConnections in the AWS CodePipeline documentation. | AWS DevOps, Cloud architect |
Task | Description | Skills required |
---|---|---|
Start AFT pipeline to deploy a new account. | Follow the instructions in Provision a new account with AFT in order to start the pipeline that creates a new AWS account in your AWS Control Tower environment. Wait for the account creation process to complete. | AWS DevOps, Cloud architect |
Validate the changes. |
| AWS DevOps, Cloud architect |
Troubleshooting
Issue | Solution |
---|---|
Permission set assignment is not working. | Make sure the group ARN, organization id, and Lambda parameters are correct. For examples, see the Solution overview section of this pattern. |
Updating code in the repository does not start the pipeline. | This issue is related to the connectivity between your AWS account and the repository. In the AWS Management Console, validate that the connection is active. For more information, see GitHub connections in the AWS CodePipeline documentation. |
Additional information
Integrating with a ticket management tool
You can choose to integrate this solution with a ticket or issue management tool, such as Jira or ServiceNow. The following diagram shows an example workflow for this option. You can integrate the ticket management tool with the AFT solution repositories by using your tool’s connectors. For Jira connectors, see Integrate Jira with GitHubaft-account-request
GitHub repository. You can design any custom workflow that meets the requirements of your use case.

The diagram shows the following workflow:
Users request a custom permission set assignment in a ticket management tool, such as Jira.
After the case is approved, a workflow begins to update the permission set assignment. (Optional) You can use plugins for custom automation of this step.
Operators send the Terraform code with the updated permission set parameters to the
aft-account-request
repository into a development or feature branch.GitHub Actions initiates AWS CodeBuild by using an OpenID Connect (OIDC) call. CodeBuild performs infrastructure as code (IaC) security scans by using tools such as tfsec
and checkov . It warns the operators of any security violations. If no violations are found, GitHub Actions creates an automated pull request and assigns a code review to the code owners. It also creates a tag for the pull request.
If the code owner approves the code review, another GitHub Actions workflow starts. It checks pull request standards, including:
If the pull request title meets requirements.
If pull request body contains approved case numbers.
If the pull request is properly tagged.
If the pull requests meets standards, GitHub Actions starts the AFT product workflow. It uses starts the
ct-aft-account-request
pipeline in AWS CodePipeline. This pipeline starts theaft-account-provisioning-framework
custom state machine in Step Functions. This state machine works as previously described in the Solution overview section of this pattern.