I want to see a list of all AWS IAM Identity Center permission sets and their respective principals for all accounts in my organization. Or, I want to see a list of all accounts of my organization and their individual permissions sets and principals.
Resolution
To see a list of provisioned permission sets and their respective principals that are assigned in IAM Identity Center, use a Python script. This action generates a JSON report that allows you to see the permissions that IAM Identity Center grants to different users or groups. Use the generated report's permission sets and principals to better govern and secure your environment.
Or, run a different Python script to retrieve the respective permission set and principal that IAM Identity Center maps to each account in your organization. This script generates the report as a .csv file.
Note: There's no native IAM Identity Center console feature, AWS Command Line Interface (AWS CLI) command, or API action that allows you to create these reports. Therefore, you must use the following scripts as a workaround.
Prerequisites
Before you proceed, verify the following prerequisites for your setup:
- Make sure that you're using the most recent version of the AWS CLI.
- Install or update the AWS SDK for Python and AWS CLI. For more information, refer the Quickstart guide to AWS Boto3.
- Properly configure the AWS CLI and the AWS SDK with working credentials. Use one of the following methods:
Run the aws configure command on the AWS CLI.
-or-
Configure the AWS CLI or AWS Cloud Development Kit (AWS CDK) to get temporary access through an AWS Identity and Access Management (IAM) role.
- Make sure that you configured a named profile for the AWS CLI that has saved credentials for an IAM principal with the following permissions:
Access to the AWS Organizations management account or the delegated administrator account for IAM Identity Center
AWSSSOReadOnly and AWSSSODirectoryReadOnly, applied as AWS managed policies
Generate a list of permission sets and principals
This script generates a JSON report of all permission sets and the respective principals that are assigned to each permission set in IAM Identity Center. Under each permission set, the report lists the associated users and groups assigned for that permission set.
1. Save the following script with a .py extension:
Note: In Step 3, your system saves the retrieved JSON file in the same directory.
import boto3, json
idstoreclient = boto3.client('identitystore')
ssoadminclient = boto3.client('sso-admin')
orgsclient= boto3.client('organizations')
users={}
groups={}
permissionSets={}
Accounts=[]
Instances= (ssoadminclient.list_instances()).get('Instances')
InstanceARN=Instances[0].get('InstanceArn')
IdentityStoreId=Instances[0].get('IdentityStoreId')
#Dictionary mapping User IDs to usernames
def mapUserIDs():
ListUsers=idstoreclient.list_users(IdentityStoreId=IdentityStoreId)
ListOfUsers=ListUsers['Users']
while 'NextToken' in ListUsers.keys():
ListUsers=idstoreclient.list_users(IdentityStoreId=IdentityStoreId,NextToken=ListUsers['NextToken'])
ListOfUsers.extend(ListUsers['Users'])
for eachUser in ListOfUsers:
users.update({eachUser.get('UserId'):eachUser.get('UserName')})
mapUserIDs()
#Dictionary mapping Group IDs to display names
def mapGroupIDs():
ListGroups=idstoreclient.list_groups(IdentityStoreId=IdentityStoreId)
ListOfGroups=ListGroups['Groups']
while 'NextToken' in ListGroups.keys():
ListGroups=idstoreclient.list_groups(IdentityStoreId=IdentityStoreId,NextToken=ListGroups['NextToken'])
ListOfGroups.extend(ListGroups['Groups'])
for eachGroup in ListOfGroups:
groups.update({eachGroup.get('GroupId'):eachGroup.get('DisplayName')})
mapGroupIDs()
#Dictionary mapping permission set ARNs to permission set names
def mapPermissionSetIDs():
ListPermissionSets=ssoadminclient.list_permission_sets(InstanceArn=InstanceARN)
ListOfPermissionSets=ListPermissionSets['PermissionSets']
while 'NextToken' in ListPermissionSets.keys():
ListPermissionSets=ssoadminclient.list_permission_sets(InstanceArn=InstanceARN,NextToken=ListPermissionSets['NextToken'])
ListOfPermissionSets.extend(ListPermissionSets['PermissionSets'])
for eachPermissionSet in ListOfPermissionSets:
permissionSetDescription=ssoadminclient.describe_permission_set(InstanceArn=InstanceARN,PermissionSetArn=eachPermissionSet)
permissionSetDetails=permissionSetDescription.get('PermissionSet')
permissionSets.update({permissionSetDetails.get('PermissionSetArn'):permissionSetDetails.get('Name')})
mapPermissionSetIDs()
#Listing Permissionsets provisioned to an account
def GetPermissionSetsProvisionedToAccount(AccountID):
ListOfPermissionSetsProvisionedToAccount=[]
PermissionSetsProvisionedToAccount=ssoadminclient.list_permission_sets_provisioned_to_account(InstanceArn=InstanceARN,AccountId=AccountID)
try:
ListOfPermissionSetsProvisionedToAccount = PermissionSetsProvisionedToAccount['PermissionSets']
while 'NextToken' in PermissionSetsProvisionedToAccount.keys():
PermissionSetsProvisionedToAccount=ssoadminclient.list_permission_sets_provisioned_to_account(InstanceArn=InstanceARN,AccountId=AccountID,NextToken=PermissionSetsProvisionedToAccount['NextToken'])
ListOfPermissionSetsProvisionedToAccount.extend(PermissionSetsProvisionedToAccount['PermissionSets'])
return(ListOfPermissionSetsProvisionedToAccount)
except:
return(ListOfPermissionSetsProvisionedToAccount)
#To retrieve the assignment of each permissionset/user/group/account assignment
def ListAccountAssignments(AccountID):
PermissionSetsList=GetPermissionSetsProvisionedToAccount(AccountID)
Assignments=[]
for permissionSet in PermissionSetsList:
AccountAssignments=ssoadminclient.list_account_assignments(InstanceArn=InstanceARN,AccountId=AccountID,PermissionSetArn=permissionSet)
Assignments.extend(AccountAssignments['AccountAssignments'])
while 'NextToken' in AccountAssignments.keys():
AccountAssignments=ssoadminclient.list_aaccount_assignments(InstanceArn=InstanceARN,AccountId=AccountID,PermissionSetArn=permissionSet,NextToken=AccountAssignments['NextToken'])
Assignments.extend(AccountAssignments['AccountAssignments'])
return(Assignments)
#To list all the accounts in the organization
def ListAccountsInOrganization():
AccountsList=orgsclient.list_accounts()
ListOfAccounts=AccountsList['Accounts']
while 'NextToken' in AccountsList.keys():
AccountsList=orgsclient.list_accounts(NextToken=AccountsList['NextToken'])
ListOfAccounts.extend(AccountsList['Accounts'])
for eachAccount in ListOfAccounts:
Accounts.append(str(eachAccount.get('Id')))
return(Accounts)
#To translate set datatype to json
class SetEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, set):
return list(obj)
return json.JSONEncoder.default(self, obj)
def GetListOfAssignmentsForPermissionSets():
ListOfAccountIDs=ListAccountsInOrganization()
entries=[]
PermissionSetListForAssignments={}
for eachAccountID in ListOfAccountIDs:
GetAccountAssignments=ListAccountAssignments(eachAccountID)
for eachAssignment in GetAccountAssignments:
if(permissionSets.get(eachAssignment.get('PermissionSetArn'))) not in PermissionSetListForAssignments.keys():
SetOfUsersandGroups={'Users':set(),'Groups':set()}
PermissionSetListForAssignments[permissionSets.get(eachAssignment.get('PermissionSetArn'))]=SetOfUsersandGroups
SetOfUsersandGroups=PermissionSetListForAssignments.get(permissionSets.get(eachAssignment.get('PermissionSetArn')))
if(eachAssignment.get('PrincipalType')=='GROUP'):
setOfGroups=SetOfUsersandGroups.get('Groups')
setOfGroups.add(groups.get(eachAssignment.get('PrincipalId')))
SetOfUsersandGroups.update({'Groups':setOfGroups})
PermissionSetListForAssignments.update({permissionSets.get(eachAssignment.get('PermissionSetArn')):SetOfUsersandGroups})
else:
setOfUsers=SetOfUsersandGroups.get('Users')
setOfUsers.add(users.get(eachAssignment.get('PrincipalId')))
SetOfUsersandGroups.update({'Users':setOfUsers})
PermissionSetListForAssignments.update({permissionSets.get(eachAssignment.get('PermissionSetArn')):SetOfUsersandGroups})
with open("AssignmentsForPermissionSets.json", "w") as outfile:
json.dump(PermissionSetListForAssignments, outfile, cls=SetEncoder)
print("Done!AssignmentsForPermissionSets.json generated successfully!")
GetListOfAssignmentsForPermissionSets()
2. Run this script in a Terminal (macOS) or PowerShell (Windows) window. This application must have the credentials of an IAM user or role with the permissions to access your IAM Identity Center configuration.
3. You receive the output as a JSON file titled AssignmentsForPermissionSets. This contains the extracted information of all the users and groups that are assigned to all the permission sets in IAM Identity Center. Here's an example output:
{ "AdministratorAccess": {
"Users": [
"Charlie",
"Ted"
],
"Groups": [
"Admins",
"Developers"
]
},
"PowerUserAccess": {
"Users": [
"Chandler",
"Joey"
],
"Groups": [
"Developers",
"Testers"
]
},
"SystemAdministrator": {
"Users": [
"Sherlock"
],
"Groups": [
"DevOps"
]
}
}
Note: A report that doesn't include a permission set implies that the permission set isn't provisioned to any account.
Generate a list of AWS Accounts and their respective principals and permission set assignments
This script generates a .csv report of all the AWS accounts in your organization. For each account, the report lists all permission sets and their respective principals that are assigned to the account through IAM Identity Center.
1. Save the following script with a .py extension:
Note: In Step 3, your system saves the retrieved .csv file in the same directory:
import boto3, csv
idstoreclient = boto3.client('identitystore')
ssoadminclient = boto3.client('sso-admin')
orgsclient= boto3.client('organizations')
users={}
groups={}
permissionSets={}
Accounts={}
Instances= (ssoadminclient.list_instances()).get('Instances')
InstanceARN=Instances[0].get('InstanceArn')
IdentityStoreId=Instances[0].get('IdentityStoreId')
#Dictionary mapping User IDs to usernames
def mapUserIDs():
ListUsers=idstoreclient.list_users(IdentityStoreId=IdentityStoreId)
ListOfUsers=ListUsers['Users']
while 'NextToken' in ListUsers.keys():
ListUsers=idstoreclient.list_users(IdentityStoreId=IdentityStoreId,NextToken=ListUsers['NextToken'])
ListOfUsers.extend(ListUsers['Users'])
for eachUser in ListOfUsers:
users.update({eachUser.get('UserId'):eachUser.get('UserName')})
mapUserIDs()
#Dictionary mapping Group IDs to display names
def mapGroupIDs():
ListGroups=idstoreclient.list_groups(IdentityStoreId=IdentityStoreId)
ListOfGroups=ListGroups['Groups']
while 'NextToken' in ListGroups.keys():
ListGroups=idstoreclient.list_groups(IdentityStoreId=IdentityStoreId,NextToken=ListGroups['NextToken'])
ListOfGroups.extend(ListGroups['Groups'])
for eachGroup in ListOfGroups:
groups.update({eachGroup.get('GroupId'):eachGroup.get('DisplayName')})
mapGroupIDs()
#Dictionary mapping permission set ARNs to permission set names
def mapPermissionSetIDs():
ListPermissionSets=ssoadminclient.list_permission_sets(InstanceArn=InstanceARN)
ListOfPermissionSets=ListPermissionSets['PermissionSets']
while 'NextToken' in ListPermissionSets.keys():
ListPermissionSets=ssoadminclient.list_permission_sets(InstanceArn=InstanceARN,NextToken=ListPermissionSets['NextToken'])
ListOfPermissionSets.extend(ListPermissionSets['PermissionSets'])
for eachPermissionSet in ListOfPermissionSets:
permissionSetDescription=ssoadminclient.describe_permission_set(InstanceArn=InstanceARN,PermissionSetArn=eachPermissionSet)
permissionSetDetails=permissionSetDescription.get('PermissionSet')
permissionSets.update({permissionSetDetails.get('PermissionSetArn'):permissionSetDetails.get('Name')})
mapPermissionSetIDs()
#Listing Permissionsets provisioned to an account
def GetPermissionSetsProvisionedToAccount(AccountID):
PermissionSetsProvisionedToAccount=ssoadminclient.list_permission_sets_provisioned_to_account(InstanceArn=InstanceARN,AccountId=AccountID)
ListOfPermissionSetsProvisionedToAccount = PermissionSetsProvisionedToAccount['PermissionSets']
while 'NextToken' in PermissionSetsProvisionedToAccount.keys():
PermissionSetsProvisionedToAccount=ssoadminclient.list_permission_sets_provisioned_to_account(InstanceArn=InstanceARN,AccountId=AccountID,NextToken=PermissionSetsProvisionedToAccount['NextToken'])
ListOfPermissionSetsProvisionedToAccount.extend(PermissionSetsProvisionedToAccount['PermissionSets']) return(ListOfPermissionSetsProvisionedToAccount)
#To retrieve the assignment of each permissionset/user/group/account assignment
def ListAccountAssignments(AccountID):
PermissionSetsList=GetPermissionSetsProvisionedToAccount(AccountID)
Assignments=[]
for permissionSet in PermissionSetsList:
AccountAssignments=ssoadminclient.list_account_assignments(InstanceArn=InstanceARN,AccountId=AccountID,PermissionSetArn=permissionSet)
Assignments.extend(AccountAssignments['AccountAssignments'])
while 'NextToken' in AccountAssignments.keys():
AccountAssignments=ssoadminclient.list_aaccount_assignments(InstanceArn=InstanceARN,AccountId=AccountID,PermissionSetArn=permissionSet,NextToken=AccountAssignments['NextToken'])
Assignments.extend(AccountAssignments['AccountAssignments'])
return(Assignments)
#To list all the accounts in the organization
def ListAccountsInOrganization():
AccountsList=orgsclient.list_accounts()
ListOfAccounts=AccountsList['Accounts']
while 'NextToken' in AccountsList.keys():
AccountsList=orgsclient.list_accounts(NextToken=AccountsList['NextToken'])
ListOfAccounts.extend(AccountsList['Accounts'])
for eachAccount in ListOfAccounts:
Accounts.update({eachAccount.get('Id'):eachAccount.get('Name')})
return(Accounts)
def WriteToExcel():
Accounts=ListAccountsInOrganization()
ListOfAccountIDs=list(Accounts.keys())
entries=[]
for eachAccountID in ListOfAccountIDs:
try:
GetAccountAssignments=ListAccountAssignments(eachAccountID)
for eachAssignment in GetAccountAssignments:
entry=[]
entry.append(eachAssignment.get('AccountId'))
entry.append(Accounts.get(eachAssignment.get('AccountId')))
entry.append(permissionSets.get(eachAssignment.get('PermissionSetArn')))
entry.append(eachAssignment.get('PrincipalType'))
if(eachAssignment.get('PrincipalType')=='GROUP'):
entry.append(groups.get(eachAssignment.get('PrincipalId')))
else:
entry.append(users.get(eachAssignment.get('PrincipalId')))
entries.append(entry)
except:
continue
filename = "IdentityStoreReport.csv"
headers=['Account ID', 'Account Name', 'Permission Set','Principal Type', 'Principal']
with open(filename, 'w') as report:
csvwriter = csv.writer(report)
csvwriter.writerow(headers)
csvwriter.writerows(entries)
print("Done! 'IdentityStoreReport.csv' report is generated successfully!")
WriteToExcel()
2. Run this script in a terminal or PowerShell window. This application must have the credentials of an IAM user or role with the permissions to access your IAM Identity Center configuration.
3. You receive the output as a .csv file titled IdentityStoreReport. This contains a tabulated view, by AWS account and of all the assignments in IAM Identity Center. Headers include Account ID, Account Name, Permission Set, Principal Type, and Principal Name.
Note: A report that doesn't include an account implies that no permission set was provisioned to that account.
Here's an example output:
| | | | |
---|
| | | | |
Account ID | Account Name | Permission Set | Principal Type | Principal |
123456789012 | Development | PowerUserAccess | GROUP | Developers |
123456789012 | Development | PowerUserAccess | USER | Ross |
123456789012 | Development | AdministratorAccess | USER | Phoebe |
123456789012 | Development | SystemAdministrator | USER | Jake |
345678901234 | Production | AdministratorAccess | GROUP | Admins |
345678901234 | Production | AdministratorAccess | GROUP | Testing |
901234567890 | Staging | PowerUserAccess | GROUP | Testing |
901234567890 | Staging | AdministratorAccess | GROUP | Client |
901234567890 | Staging | PowerUserAccess | USER | Gina |
901234567890 | Staging | PowerUserAccess | GROUP | Admins |
Considerations and limitations
To avoid issues when you run this script, note the following considerations and limitations:
- IAM Identity Center APIs have a collective throttle maximum of 20 transactions per second (TPS). For more information, see IAM Identity Center throttle limits. You might encounter the exceptions RequestLimitExceeded and ThrottlingException in large environments. In this case, implement strategies to manage API throttling.
- If an AWS Account isn't in the report, then no permission set was provisioned to that account.
- The more accounts that you have in your setup, the more time it takes to generate the report.