I want to export a list of all AWS IAM Identity Center permission sets and their assigned principals across member accounts in AWS Organizations.
Short description
To generate reports of IAM Identity Center permission sets, use Python scripts. You can create either a JSON report of permission sets with their assigned principals or a .csv file of accounts with their permission set assignments.
Important:
Resolution
Note: If you receive errors when you run AWS Command Line Interface (AWS CLI) commands, then see Troubleshooting errors for the AWS CLI. Also, make sure that you're using the most recent AWS CLI version.
Prerequisites:
Generate a report of permission sets with assigned principals
Complete the following steps:
-
Save the following Python script with a .py extension, such as permission_sets_report.py:
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()
Note: If you receive the "IndexError: list index out of range" error, then the script is in an AWS Region that isn't the Region where you configured IAM Identity Center.
-
Run the Python script in a Terminal (macOS) or PowerShell (Windows) window.
The script creates a JSON file that's named AssignmentsForPermissionSets.json that contains your permission sets and their assigned principals.
Example output:
{ "AdministratorAccess": { "Users": [
"Charlie",
"Ted"
],
"Groups": [
"Admins",
"Developers"
]
},
"PowerUserAccess": {
"Users": [
"Chandler",
"Joey"
],
"Groups": [
"Developers",
"Testers"
]
},
"SystemAdministrator": {
"Users": [
"Sherlock"
],
"Groups": [
"DevOps"
]
}
}
Note: If a permission set isn't in the report, then you didn't provision a permission set for the accounts.
Generate a report with the permission set assignments of accounts
Complete the following steps:
-
Save the following Python script with a .py extension, such as account_assignments_report.py:
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()
-
Run the Python script in a Terminal (macOS) or PowerShell (Windows) window.
The script creates a .csv file that's named IdentityStoreReport.csv that contains your account assignments. Your system saves the .csv file in the same directory as the permission sets report.
Example .csv file 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 |
Note: If an account isn't in the report, then you didn't provision permission sets for the account.