reverse-diagrams 0.1.10__py3-none-any.whl → 0.2.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,13 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: reverse_diagrams
3
- Version: 0.1.10
4
- Summary: Continuous Documentation Tool - Documentation as Code Tool -
5
- This package create reverse diagrams based on your current state in your cloud environment
3
+ Version: 0.2.6
4
+ Summary: Continuous Documentation Tool - Documentation as Code Tool - This package create reverse diagrams based on your current state in your cloud environment
6
5
  Project-URL: Homepage, https://github.com/velez94/reverse_diagrams
7
6
  Project-URL: Bug Tracker, https://github.com/velez94/reverse_diagrams/issues
8
- Author-email: Alejandro Velez <wilmar.velezl@sophossolutions.com>
7
+ Author-email: Alejandro Velez <avelez@labvel.io>
9
8
  License: MIT License
10
9
 
11
- Copyright (c) [2022] [Alejandro Velez]
10
+ Copyright (c) [2023] [Alejandro Velez]
12
11
 
13
12
  Permission is hereby granted, free of charge, to any person obtaining a copy
14
13
  of this software and associated documentation files (the "Software"), to deal
@@ -73,8 +72,7 @@ The following are the available options
73
72
 
74
73
  ```commandline
75
74
  $ reverse_diagrams -h
76
-
77
- usage: reverse_diagrams [-h] [-c CLOUD] [-p PROFILE] [-o] [-i] [-v]
75
+ usage: reverse_diagrams [-h] [-c CLOUD] [-p PROFILE] [-od OUTPUT_DIR_PATH] [-r REGION] [-o] [-i] [-v] [-d]
78
76
 
79
77
  options:
80
78
  -h, --help show this help message and exit
@@ -82,10 +80,15 @@ options:
82
80
  Cloud Provider, aws, gcp, azure
83
81
  -p PROFILE, --profile PROFILE
84
82
  AWS cli profile for Access Analyzer Api
83
+ -od OUTPUT_DIR_PATH, --output_dir_path OUTPUT_DIR_PATH
84
+ Name of folder to save the diagrams python code files
85
+ -r REGION, --region REGION
86
+ AWS cli profile for Access Analyzer Api
85
87
  -o, --graph_organization
86
88
  Set if you want to create graph for your organization
87
89
  -i, --graph_identity Set if you want to create graph for your IAM Center
88
90
  -v, --version Show version
91
+ -d, --debug Debug Mode
89
92
 
90
93
  ```
91
94
  For example:
@@ -0,0 +1,17 @@
1
+ src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ src/reverse_diagrams.py,sha256=FIWMS9anHgfDkDJIUUtb6mnZZ11q3nX8Tlu5OgeFMys,8654
3
+ src/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ src/aws/describe_identity_store.py,sha256=5LRtm1IwMKMRX6vRqxIUzna3VqZkHAWD2HylUHdeB1Y,7246
5
+ src/aws/describe_organization.py,sha256=ki0o3VhtH6mMV6EmZzlKPRfL5SKKVZGweK3NEiChXfY,3053
6
+ src/aws/describe_sso.py,sha256=AOob-7fQk6paWjBT3dBx0Fizb5IhjWp1IIrOIv6s-yQ,1720
7
+ src/banner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ src/banner/banner.py,sha256=D4XgGeWINUEpaQeMNIyuU1gY54bgv4UhantsDRj7TBQ,901
9
+ src/dgms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ src/dgms/graph_mapper.py,sha256=1YWY4eQPZzDlqahjmgBIQSmvmiCrmAdwZoOdggnI6zE,6259
11
+ src/dgms/graph_template.py,sha256=4twiySM5MFl3oRpLkjTGgdswIwi2ee3lTjPmTx5SmG4,1170
12
+ src/export_report/export_csv.py,sha256=6A3ZpoBnk6l1GVVmpH-_id6vKdd6JGipNCUwURtyIUs,88
13
+ reverse_diagrams-0.2.6.dist-info/METADATA,sha256=FTOqse6qfcxYMrKjh4vIseE3a4QpojRe3jIcZ99Ohik,5395
14
+ reverse_diagrams-0.2.6.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
15
+ reverse_diagrams-0.2.6.dist-info/entry_points.txt,sha256=VZNkrc7qUDbddTCH3pGd83EhUT3PHTx9MzpAk6bb6qc,63
16
+ reverse_diagrams-0.2.6.dist-info/licenses/LICENSE,sha256=IaXsSIrH5zPkhwGm3_eitFhOsUeh8vnvs_ZazfXa4fM,1095
17
+ reverse_diagrams-0.2.6.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.12.2
2
+ Generator: hatchling 1.21.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) [2022] [Alejandro Velez]
3
+ Copyright (c) [2023] [Alejandro Velez]
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -4,13 +4,40 @@ from colorama import Fore
4
4
  import logging
5
5
 
6
6
 
7
- def list_groups(identity_store_id, client=boto3.client('identitystore', region_name="us-east-2"), ):
8
- response = client.list_groups(
7
+ def list_groups_pag(identity_store_id, client=boto3.client('identitystore', region_name="us-east-2"),
8
+ next_token: str = None):
9
+ paginator = client.get_paginator('list_groups')
10
+ response_iterator = paginator.paginate(
9
11
  IdentityStoreId=identity_store_id,
12
+ PaginationConfig={
13
+ 'MaxItems': 1000,
14
+ 'PageSize': 4,
15
+ 'StartingToken': next_token
16
+ }
17
+ )
18
+ response = response_iterator.build_full_result()
19
+ logging.info(response_iterator.build_full_result())
20
+ return response["Groups"]
21
+
10
22
 
23
+ def list_groups(identity_store_id, client=boto3.client('identitystore', region_name="us-east-2"), ):
24
+ groups = client.list_groups(
25
+ IdentityStoreId=identity_store_id,
26
+ MaxResults=20
11
27
  )
12
28
 
13
- return response["Groups"]
29
+ logging.info(groups)
30
+ l_groups = groups["Groups"]
31
+ logging.info(len(groups["Groups"]))
32
+
33
+ if len(groups["Groups"]) >= 20:
34
+ logging.info("Paginating ...")
35
+ ad_groups = list_groups_pag(identity_store_id=identity_store_id, client=client, next_token=groups["NextToken"])
36
+ for ad in ad_groups:
37
+ l_groups.append(ad)
38
+ logging.info(f"You have {len(l_groups)} Groups")
39
+
40
+ return l_groups
14
41
 
15
42
 
16
43
  def list_users(identity_store_id, client=boto3.client('identitystore', region_name="us-east-2"), ):
@@ -22,24 +49,82 @@ def list_users(identity_store_id, client=boto3.client('identitystore', region_na
22
49
  return response["Users"]
23
50
 
24
51
 
52
+ def get_members_pag(identity_store_id, client=boto3.client('identitystore', region_name="us-east-2"),
53
+ next_token: str = None):
54
+ paginator = client.get_paginator('list_group_memberships')
55
+ response_iterator = paginator.paginate(
56
+ IdentityStoreId=identity_store_id,
57
+ PaginationConfig={
58
+ 'MaxItems': 1000,
59
+ 'PageSize': 4,
60
+ 'StartingToken': next_token
61
+ }
62
+ )
63
+ response = response_iterator.build_full_result()
64
+ logging.info(response_iterator.build_full_result())
65
+ return response["GroupMemberships"]
66
+
67
+
25
68
  def get_members(identity_store_id, groups, client=boto3.client('identitystore', region_name="us-east-2")):
26
69
  group_members = []
27
70
  for g in groups:
28
71
  response = client.list_group_memberships(
29
72
  IdentityStoreId=identity_store_id,
30
73
  GroupId=g["GroupId"],
74
+ MaxResults=20,
31
75
 
32
76
  )
77
+ members = response["GroupMemberships"]
78
+ logging.info(members)
79
+
80
+ logging.info(len(members))
81
+
82
+ if len(members) >= 20:
83
+ logging.info("Paginating ...")
84
+ ad_members = get_members_pag(identity_store_id=identity_store_id, client=client,
85
+ next_token=response["NextToken"])
86
+ for ad in ad_members:
87
+ members.append(ad)
88
+ logging.info(f"You have {len(ad_members)} Members")
89
+ print(f"You have {len(ad_members)} Members")
90
+
33
91
  group_members.append(
34
92
  {"group_id": g["GroupId"],
35
93
  "group_name": g["DisplayName"],
36
- "members": response["GroupMemberships"]
94
+ "members": members
37
95
  }
38
96
  )
39
97
 
40
98
  return group_members
41
99
 
42
100
 
101
+ def list_group_memberships(identitystore_client, group_name, pagination=True):
102
+ """
103
+ Lists memberships for a group in an AWS SSO identity store.
104
+
105
+ Args:
106
+ identitystore_client (boto3.client): Boto3 SSO identity store client
107
+ group_name (str): Name of the group to list memberships for
108
+ pagination (bool): Whether to enable result pagination (default: True)
109
+
110
+ Returns:
111
+ list: List of member objects
112
+ """
113
+
114
+ params = {'GroupName': group_name}
115
+ members = []
116
+
117
+ if pagination:
118
+ paginator = identitystore_client.get_paginator('list_group_memberships')
119
+ for page in paginator.paginate(**params):
120
+ members.extend(page['Members'])
121
+ else:
122
+ response = identitystore_client.list_group_memberships(**params)
123
+ members.extend(response['Members'])
124
+
125
+ return members
126
+
127
+
43
128
  def complete_group_members(group_members, users_list):
44
129
  for m in group_members:
45
130
  for u in m["members"]:
@@ -50,6 +135,22 @@ def complete_group_members(group_members, users_list):
50
135
  return group_members
51
136
 
52
137
 
138
+ def l_groups_to_d_groups(l_groups: list = None):
139
+ """
140
+
141
+ :param l_groups:
142
+ :return:
143
+ """
144
+ names = []
145
+ for a in l_groups:
146
+ names.append(a['group_name'])
147
+ logging.info(names)
148
+
149
+ d_user_groups = dict(zip(names, l_groups))
150
+ logging.info(d_user_groups)
151
+ return d_user_groups
152
+
153
+
53
154
  def extend_account_assignments(accounts_list, permissions_sets, store_arn,
54
155
  client_sso=boto3.client('identitystore', region_name="us-east-2")):
55
156
  account_assignments = []
@@ -69,15 +170,15 @@ def add_users_and_groups_assign(account_assignments_list, user_and_group_list, u
69
170
  for a in account_assignments_list:
70
171
  for g in user_and_group_list:
71
172
  if len(a) > 0 and a['PrincipalType'] == 'GROUP' and g["group_id"] == a['PrincipalId']:
72
- print( Fore.YELLOW +
73
- f"Account {a['AccountId']} assign to {a['PrincipalType']} {g['group_name']} with permission set {list_permissions_set_arn_name[a['PermissionSetArn']]} or {a['PermissionSetArn']}" + Fore.RESET)
173
+ print(Fore.YELLOW +
174
+ f"Account {a['AccountId']} assign to {a['PrincipalType']} {g['group_name']} with permission set {list_permissions_set_arn_name[a['PermissionSetArn']]} or {a['PermissionSetArn']}" + Fore.RESET)
74
175
 
75
176
  a["GroupName"] = g['group_name']
76
177
  a["PermissionSetName"] = list_permissions_set_arn_name[a['PermissionSetArn']]
77
178
  for u in user_list:
78
179
  if len(a) > 0 and a['PrincipalType'] == 'USER' and u["UserId"] == a['PrincipalId']:
79
180
  print(Fore.YELLOW +
80
- f"Account {a['AccountId']} assign to {a['PrincipalType']} {u['UserName']} with permission set {a['PermissionSetArn']} or {list_permissions_set_arn_name[a['PermissionSetArn']]}"+ Fore.RESET)
181
+ f"Account {a['AccountId']} assign to {a['PrincipalType']} {u['UserName']} with permission set {a['PermissionSetArn']} or {list_permissions_set_arn_name[a['PermissionSetArn']]}" + Fore.RESET)
81
182
  a["UserName"] = u['UserName']
82
183
  a["PermissionSetName"] = list_permissions_set_arn_name[a['PermissionSetArn']]
83
184
  logging.debug(f"Account Assignments --> {account_assignments_list}")
@@ -33,7 +33,7 @@ def list_organizational_units(parent_id, client=boto3.client('organizations'), o
33
33
  ous_next = list_organizational_units(ou["Id"], client=client, org_units=org_units)
34
34
  logging.debug(ous_next)
35
35
  if len(ous_next) > 0:
36
- logging.debug("Find NetsteD")
36
+ logging.debug("Find Netsted")
37
37
 
38
38
  return org_units
39
39
 
@@ -76,9 +76,9 @@ def list_accounts(client=boto3.client('organizations')):
76
76
  accounts = client.list_accounts(
77
77
 
78
78
  )
79
- print(accounts)
79
+ logging.info(accounts)
80
80
  l_account = accounts["Accounts"]
81
- print(len(accounts["Accounts"]))
81
+ logging.info(len(accounts["Accounts"]))
82
82
  if len(accounts["Accounts"]) >= 20:
83
83
  logging.info("Paginating ...")
84
84
  ad_accounts = list_accounts_pag(client=client, next_token=accounts["NextToken"])
src/banner/banner.py CHANGED
@@ -1,53 +1,22 @@
1
1
  from colorama import Fore
2
2
 
3
3
 
4
- banner = """
5
- \t \t \t \t Reverse Diagrams
6
- ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
7
- ░░░▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒░░░░░░░░░░
8
- ░▓███████████████████████████████████████████████████████████████████████████▓░░░░░░░░░░░░
9
- ▓████▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
10
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
11
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓
12
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓██▓
13
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
14
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
15
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
16
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
17
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
18
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
19
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
20
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░████▓
21
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░█████
22
- ███▓▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▓██████████████████▓▓▓██████████▓░░░░█████
23
- ▓▓▓█▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓██████████████████▓▓██████████████▒░░░█████
24
- █▓██▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒█████████████████████████████████▓▒░░░░█████
25
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓██████▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
26
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓██████▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
27
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓██████▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
28
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓██████▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
29
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓██████▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
30
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓██████▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
31
- ████▓░░░░░░░░░░░░░░░░░░░░░░░▒▓▓▓░░░░░░░░░░░░░▓██████▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
32
- ████▓░░░░░░░░░░░░░░░░░░▒▒▓████▓░░░░░░░░░░░░░░▓██████▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
33
- ████▓░░░░░░░░░░░░░▒▒▓████████▓░░░░░░░░░░░░░░░▓██████▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
34
- ████▓░░░░░░░░▒▒▓█████████████████████████▓█▓▓▓██████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
35
- ████▓░░░░░▓▓████████████████████████████▓▓▓▓███████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
36
- ███▓▓░░░░░░░▒▓▓█████████████████████████▓▓███████▓▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░████▓
37
- ███▓▓░░░░░░░░░░░░▒▓▓█████████▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
38
- ████▓░░░░░░░░░░░░░░░░░▒▓▓█████▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
39
- ████▓░░░░░░░░░░░░░░░░░░░░░░▒▓▓█▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
40
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
41
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
42
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
43
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
44
- ████▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░████▓
45
- ██▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
46
- ▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
47
- ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
48
- ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█████
49
- ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒████▓
50
- ░░░░░░░░░▓█▓▓▓███████████████████████████████████████████████████████████▓█▓▓▓██████████▓░
4
+ banner = """Reverse Diagrams
5
+
6
+ ##### ###### # # ###### ##### #### ######
7
+ # # # # # # # # # #
8
+ # # ##### # # ##### # # #### #####
9
+ ##### # # # # ##### # #
10
+ # # # # # # # # # # #
11
+ # # ###### ## ###### # # #### ######
12
+
13
+
14
+ ##### # ## #### ##### ## # # ####
15
+ # # # # # # # # # # # ## ## #
16
+ # # # # # # # # # # # ## # ####
17
+ # # # ###### # ### ##### ###### # # #
18
+ # # # # # # # # # # # # # # #
19
+ ##### # # # #### # # # # # # ####
51
20
  """
52
21
 
53
22
 
src/dgms/graph_mapper.py CHANGED
@@ -1,6 +1,8 @@
1
1
  import logging
2
+ import os.path
2
3
  import re
3
4
 
5
+
4
6
  def format_name_string(a_string, action=None):
5
7
  """
6
8
 
@@ -11,48 +13,61 @@ def format_name_string(a_string, action=None):
11
13
  if action == 'split':
12
14
  if len(a_string) > 17:
13
15
  a_string = a_string[:16] + "\\n" + a_string[16:]
14
- elif action== 'format':
16
+ elif action == 'format':
15
17
 
16
18
  a_string = re.sub('[-!?@.+]', '', a_string)
17
19
  a_string = a_string.replace(" ", '')
18
20
  return a_string
19
21
 
20
22
 
21
- def create_sso_mapper_complete(template_file, acc_assignments):
23
+ def create_sso_mapper_complete(template_file, acc_assignments, d_groups):
24
+
22
25
  with open(template_file, 'a') as f:
23
26
  ident = " "
24
27
 
25
28
  for key, value in acc_assignments.items():
26
- print(f"\n with Cluster('Account: {key}'):", file=f)
27
- if len(value) > 0:
28
29
 
30
+ if len(value) > 0:
31
+ print(f"\n with Cluster('Account: {key}'):", file=f)
29
32
  for m in value:
30
33
  logging.debug(m)
31
34
 
32
35
  if "GroupName" in m.keys():
33
-
34
36
  print(f"\n{ident}with Cluster('Group: {m['GroupName']}'):", file=f)
35
- print(f"\n{ident}{ident}gg_{format_name_string(m['GroupName'], 'format')}=Users(\"{format_name_string(m['GroupName'],'split')}\")\n"
36
- f"{ident}{ident}gg_{format_name_string(m['GroupName'], 'format')} \\\n"
37
- f"{ident}{ident}{ident}- Edge(color=\"brown\", style=\"dotted\") \\\n"
38
- f"{ident}{ident}{ident}- IAMPermissions(\"{format_name_string(m['PermissionSetName'], 'split')}\")",
39
- file=f)
37
+ print(
38
+ f"\n{ident}{ident}gg_{format_name_string(m['GroupName'], 'format')}=Users(\"{format_name_string(m['GroupName'], 'split')}\")\n"
39
+ f"{ident}{ident}gg_{format_name_string(m['GroupName'], 'format')} \\\n"
40
+ f"{ident}{ident}{ident}- Edge(color=\"brown\", style=\"dotted\", label=\"Permissions Set\") \\\n"
41
+ f"{ident}{ident}{ident}- IAMPermissions(\"{format_name_string(m['PermissionSetName'], 'split')}\")\n"
42
+ f"{ident}{ident}mm_{format_name_string(m['GroupName'], 'format')}={create_users_men(d_groups[m['GroupName']]['members'])} \n" # ['members']}
43
+ f"{ident}{ident}gg_{format_name_string(m['GroupName'], 'format')} \\\n"
44
+ f"{ident}{ident}{ident}- Edge(color=\"darkgreen\", style=\"dotted\", label=\"Member\") \\\n"
45
+ f"{ident}{ident}{ident}- mm_{format_name_string(m['GroupName'], 'format')} \n",
40
46
 
41
- if "UserName" in m.keys():
47
+ file=f)
42
48
 
49
+ if "UserName" in m.keys():
43
50
  print(f"\n{ident}with Cluster('User: {m['UserName']}'):", file=f)
44
51
  print(
45
- f"\n{ident}{ident}uu_{format_name_string(m['UserName'], 'format')}=User(\"{format_name_string(m['UserName'],'split')}\")\n"
46
- f"{ident}{ident}uu_{format_name_string(m['UserName'],'format')} \\\n"
52
+ f"\n{ident}{ident}uu_{format_name_string(m['UserName'], 'format')}=User(\"{format_name_string(m['UserName'], 'split')}\")\n"
53
+ f"{ident}{ident}uu_{format_name_string(m['UserName'], 'format')} \\\n"
47
54
  f"{ident}{ident}{ident}- Edge(color=\"brown\", style=\"dotted\") \\\n"
48
- f"{ident}{ident}{ident}- IAMPermissions(\"{format_name_string(m['PermissionSetName'],'split')}\")",
55
+ f"{ident}{ident}{ident}- IAMPermissions(\"{format_name_string(m['PermissionSetName'], 'split')}\")",
49
56
  file=f)
50
57
  # print(f"\n{ident}ou >> uu_{format_name_string(m['UserName'])}\n", file=f)
51
58
  f.close()
52
59
 
53
60
 
54
- def create_file(template_content, file_name):
55
- with open(file_name, 'w') as f:
61
+ def create_file(template_content, file_name, directory_path="."):
62
+ """
63
+
64
+ :param template_content:
65
+ :param file_name:
66
+ :param directory_path:
67
+ :return:
68
+ """
69
+ f_path=os.path.join(directory_path, file_name)
70
+ with open(f_path, 'w') as f:
56
71
  f.write(template_content)
57
72
  f.close()
58
73
 
@@ -75,10 +90,10 @@ def create_mapper(template_file, org, root_id, list_ous, list_accounts):
75
90
 
76
91
  for p in a["Parents"]:
77
92
  if p['Type'] == 'ROOT':
78
- print(f"\n{ident}oo>> ou_{format_name_string(a['Name'],'format')}", file=f)
93
+ print(f"\n{ident}oo>> ou_{format_name_string(a['Name'], 'format')}", file=f)
79
94
  if p['Type'] == 'ORGANIZATIONAL_UNIT':
80
95
  print(
81
- f"\n{ident}ou_{format_name_string(find_ou_name(list_ous, p['Id']),'format')}>> ou_{format_name_string(a['Name'],'format')}",
96
+ f"\n{ident}ou_{format_name_string(find_ou_name(list_ous, p['Id']), 'format')}>> ou_{format_name_string(a['Name'], 'format')}",
82
97
  file=f)
83
98
 
84
99
  for c, i in zip(list_accounts, range(len(list_accounts))):
@@ -90,7 +105,7 @@ def create_mapper(template_file, org, root_id, list_ous, list_accounts):
90
105
  for o, j in zip(list_ous, range(len(list_ous))):
91
106
  if p['Id'] == o["Id"] and p['Type'] == 'ORGANIZATIONAL_UNIT':
92
107
  print(
93
- f"\n{ident}ou_{format_name_string(o['Name'],'format')}>> OrganizationsAccount(\"{c['account']}\\n{format_name_string(c['name'], action='split')}\")",
108
+ f"\n{ident}ou_{format_name_string(o['Name'], 'format')}>> OrganizationsAccount(\"{c['account']}\\n{format_name_string(c['name'], action='split')}\")",
94
109
  file=f)
95
110
 
96
111
  f.close()
@@ -107,10 +122,25 @@ def create_sso_mapper(template_file, group_and_members):
107
122
  users = "["
108
123
  for m in g["members"]:
109
124
  user_name = m["MemberId"]["UserName"]
110
- users += f"User(\"{format_name_string(user_name,'split')}\"),"
125
+ users += f"User(\"{format_name_string(user_name, 'split')}\"),"
111
126
 
112
127
  users += "]"
113
128
  print(f"\n{ident}{ident}gg_{l}= {users}", file=f)
114
129
  else:
115
130
  print(f"\n{ident}gg_{l}= Users(\"{format_name_string(g['group_name'], 'split')}\")", file=f)
116
131
 
132
+
133
+ def create_users_men(members):
134
+ if len(members) > 0:
135
+
136
+ users = "["
137
+ for m in members:
138
+ user_name = m["MemberId"]["UserName"]
139
+ users += f"User(\"{format_name_string(user_name, 'split')}\"),"
140
+
141
+ users += "]"
142
+
143
+ else:
144
+ users = "[]"
145
+
146
+ return users
src/reverse_diagrams.py CHANGED
@@ -1,3 +1,5 @@
1
+ import os
2
+
1
3
  import boto3
2
4
  import argparse
3
5
  import logging
@@ -7,13 +9,13 @@ from datetime import datetime
7
9
  from .aws.describe_organization import describe_organization, \
8
10
  list_accounts, index_accounts, list_roots, list_organizational_units, index_ous
9
11
  from .aws.describe_identity_store import order_accounts_assignments_list, extend_account_assignments, \
10
- list_groups, get_members, list_users, complete_group_members, add_users_and_groups_assign
12
+ list_groups, get_members, list_users, complete_group_members, add_users_and_groups_assign, l_groups_to_d_groups
11
13
  from .aws.describe_sso import list_instances, extends_permissions_set, list_permissions_set
12
14
  from .dgms.graph_mapper import create_mapper, create_sso_mapper_complete, create_sso_mapper, create_file
13
15
  from .dgms.graph_template import graph_template, graph_template_sso, graph_template_sso_complete
14
16
  from .banner.banner import get_version
15
17
 
16
- __version__ = "0.1.10"
18
+ __version__ = "0.2.4"
17
19
 
18
20
 
19
21
  def main() -> int:
@@ -21,7 +23,6 @@ def main() -> int:
21
23
  Crete architecture diagram from your current state
22
24
  :return:
23
25
  """
24
- print('Date:', datetime.now())
25
26
 
26
27
  # Initialize parser
27
28
  parser = argparse.ArgumentParser()
@@ -29,12 +30,15 @@ def main() -> int:
29
30
  help="Cloud Provider, aws, gcp, azure", default="aws")
30
31
  parser.add_argument("-p", "--profile",
31
32
  help="AWS cli profile for Access Analyzer Api", default=None)
33
+ parser.add_argument("-od", "--output_dir_path",
34
+ help="Name of folder to save the diagrams python code files", default=None)
32
35
  parser.add_argument("-r", "--region",
33
36
  help="AWS cli profile for Access Analyzer Api", default="us-east-2")
34
37
  parser.add_argument("-o", "--graph_organization",
35
38
  help="Set if you want to create graph for your organization", action='store_true')
36
39
  parser.add_argument("-i", "--graph_identity",
37
40
  help="Set if you want to create graph for your IAM Center", action='store_true')
41
+
38
42
  parser.add_argument("-v", "--version",
39
43
  help="Show version", action='store_true')
40
44
  parser.add_argument("-d", "--debug",
@@ -46,6 +50,11 @@ def main() -> int:
46
50
  if args.debug:
47
51
  logging.basicConfig(level=logging.DEBUG)
48
52
 
53
+ if args.output_dir_path:
54
+ diagrams_path = args.output_dir_path
55
+ else:
56
+ diagrams_path = "."
57
+
49
58
  if args.cloud == "aws":
50
59
  if args.profile:
51
60
  profile = args.profile
@@ -57,7 +66,7 @@ def main() -> int:
57
66
  region = args.region
58
67
 
59
68
  if args.graph_organization:
60
- create_file(template_content=graph_template, file_name="graph_org.py")
69
+ create_file(template_content=graph_template, file_name="graph_org.py", directory_path=diagrams_path)
61
70
 
62
71
  client_org = boto3.client('organizations')
63
72
  organization = describe_organization(client_org)
@@ -77,17 +86,21 @@ def main() -> int:
77
86
  l_accounts = list_accounts(client_org)
78
87
  logging.debug(l_accounts)
79
88
  logging.debug("The Account list with parents info")
89
+ print(Fore.YELLOW + emoji.emojize(
90
+ f":information: There are {len(l_accounts)} Accounts in your organization" + Fore.RESET))
80
91
  i_accounts = index_accounts(l_accounts)
81
92
  logging.debug(i_accounts)
82
93
 
83
94
  create_mapper(template_file="graph_org.py", org=organization, root_id=roots[0]["Id"], list_ous=ous,
84
95
  list_accounts=i_accounts)
85
96
 
86
- print(Fore.YELLOW + emoji.emojize( ":sparkles: Run -> python3 graph_org.py " + Fore.RESET))
97
+ print(
98
+ Fore.YELLOW + emoji.emojize(f":sparkles: Run -> python3 {diagrams_path}/graph_org.py " + Fore.RESET))
87
99
 
88
100
  if args.graph_identity:
89
- create_file(template_content=graph_template_sso, file_name="graph_sso.py")
90
- create_file(template_content=graph_template_sso_complete, file_name="graph_sso_complete.py")
101
+ create_file(template_content=graph_template_sso, file_name="graph_sso.py", directory_path=diagrams_path)
102
+ create_file(template_content=graph_template_sso_complete, file_name="graph_sso_complete.py",
103
+ directory_path=diagrams_path)
91
104
 
92
105
  client_identity = boto3.client('identitystore', region_name=region)
93
106
  client_sso = boto3.client('sso-admin', region_name=region)
@@ -97,9 +110,11 @@ def main() -> int:
97
110
  logging.debug(store_instances)
98
111
  store_id = store_instances[0]["IdentityStoreId"]
99
112
  store_arn = store_instances[0]["InstanceArn"]
100
- print(Fore.BLUE + "List groups" + Fore.RESET)
113
+ print(Fore.BLUE + emoji.emojize(":sparkle: List groups" + Fore.RESET))
101
114
  l_groups = list_groups(store_id, client=client_identity)
102
115
  logging.debug(l_groups)
116
+ print(Fore.YELLOW + emoji.emojize(
117
+ f":information: There are {len(l_groups)} Groups in your Identity Store" + Fore.RESET))
103
118
 
104
119
  print(Fore.BLUE + emoji.emojize(":sparkle: Get groups and Users info" + Fore.RESET))
105
120
 
@@ -111,6 +126,7 @@ def main() -> int:
111
126
  l_users = list_users(store_id, client=client_identity)
112
127
  logging.debug(l_users)
113
128
  c_users_and_groups = complete_group_members(m_groups, l_users)
129
+ d_groups = l_groups_to_d_groups(l_groups=c_users_and_groups)
114
130
 
115
131
  logging.debug(c_users_and_groups)
116
132
  # Get Account assingments
@@ -132,9 +148,15 @@ def main() -> int:
132
148
  print(Fore.BLUE + emoji.emojize(":sparkle: Getting account assignments, users and groups" + Fore.RESET))
133
149
  f_accounts = order_accounts_assignments_list(accounts_dict=l_accounts,
134
150
  account_assignments=account_assignments)
135
- create_sso_mapper_complete(template_file="graph_sso_complete.py", acc_assignments=f_accounts)
136
- create_sso_mapper(template_file="graph_sso.py", group_and_members=c_users_and_groups)
137
- print(Fore.YELLOW + emoji.emojize( ":sparkles: Run -> python3 graph_sso_complete.py " + Fore.RESET))
151
+ f_path= os.path.join(diagrams_path, "graph_sso_complete.py")
152
+ create_sso_mapper_complete(template_file=f_path,
153
+ acc_assignments=f_accounts,
154
+ d_groups=d_groups)
155
+
156
+ f_path = os.path.join(diagrams_path, "graph_sso.py")
157
+ create_sso_mapper(template_file=f_path, group_and_members=c_users_and_groups)
158
+ print(Fore.YELLOW + emoji.emojize(
159
+ f":sparkles: Run -> python3 {diagrams_path}/graph_sso_complete.py " + Fore.RESET))
138
160
  else:
139
161
  print(Fore.RED + emoji.emojize(":warning: " + f"The cloud provider {args.cloud} is no available" + Fore.RESET))
140
162
  if args.version:
__init__.py DELETED
File without changes
graph_org.py DELETED
@@ -1,84 +0,0 @@
1
-
2
- from diagrams import Diagram, Cluster
3
-
4
- from diagrams.aws.management import Organizations, OrganizationsAccount, OrganizationsOrganizationalUnit
5
-
6
- with Diagram("Organizations-State", show=False, direction="TB"):
7
- ou = OrganizationsOrganizationalUnit("OU")
8
- oa = OrganizationsAccount("Account")
9
-
10
- with Cluster('Organizations'):
11
-
12
- oo = Organizations('o-9tlhkjyoii\n029921763173\nr-w3ow')
13
-
14
- ou_Sandbox= OrganizationsOrganizationalUnit("ou-w3ow-1sumtdvp\nSandbox")
15
-
16
- oo>> ou_Sandbox
17
-
18
- ou_Security= OrganizationsOrganizationalUnit("ou-w3ow-oqvta8tc\nSecurity")
19
-
20
- oo>> ou_Security
21
-
22
- ou_Workloads= OrganizationsOrganizationalUnit("ou-w3ow-1lpmyfug\nWorkloads")
23
-
24
- oo>> ou_Workloads
25
-
26
- ou_Dev= OrganizationsOrganizationalUnit("ou-w3ow-k24p2opx\nDev")
27
-
28
- oo>> ou_Dev
29
-
30
- ou_DevSecOps= OrganizationsOrganizationalUnit("ou-w3ow-b334bby6\nDevSecOps")
31
-
32
- oo>> ou_DevSecOps
33
-
34
- ou_Core= OrganizationsOrganizationalUnit("ou-w3ow-93hiq3zr\nCore")
35
-
36
- oo>> ou_Core
37
-
38
- ou_PolicyStaging= OrganizationsOrganizationalUnit("ou-w3ow-18verpsm\nPolicy Staging")
39
-
40
- oo>> ou_PolicyStaging
41
-
42
- ou_Suspended= OrganizationsOrganizationalUnit("ou-w3ow-7vunsbkd\nSuspended")
43
-
44
- oo>> ou_Suspended
45
-
46
- ou_Shared= OrganizationsOrganizationalUnit("ou-w3ow-w7dzhzcz\nShared")
47
-
48
- oo>> ou_Shared
49
-
50
- ou_Infrastructure= OrganizationsOrganizationalUnit("ou-w3ow-9q06w8rz\nInfrastructure")
51
-
52
- oo>> ou_Infrastructure
53
-
54
- ou_BULab= OrganizationsOrganizationalUnit("ou-w3ow-qa633svy\nBU-Lab")
55
-
56
- ou_Workloads>> ou_BULab
57
-
58
- ou_Prod= OrganizationsOrganizationalUnit("ou-w3ow-4sdr4ejy\nProd")
59
-
60
- ou_BULab>> ou_Prod
61
-
62
- ou_SDLC= OrganizationsOrganizationalUnit("ou-w3ow-vop5vccd\nSDLC")
63
-
64
- ou_BULab>> ou_SDLC
65
-
66
- ou_Core>> OrganizationsAccount("884478634998\nLog archive")
67
-
68
- ou_Security>> OrganizationsAccount("835863553119\nSecOps")
69
-
70
- ou_Prod>> OrganizationsAccount("582441254763\nProd")
71
-
72
- ou_Core>> OrganizationsAccount("895882538541\nSecurityTooling")
73
-
74
- ou_DevSecOps>> OrganizationsAccount("105171185823\nDevSecOps")
75
-
76
- ou_Infrastructure>> OrganizationsAccount("994261317734\nOps")
77
-
78
- ou_Infrastructure>> OrganizationsAccount("155794986228\nSharedServices")
79
-
80
- oo >> OrganizationsAccount("029921763173\nLabVel")
81
-
82
- ou_Security>> OrganizationsAccount("837696987585\nOrganizationMana\nger")
83
-
84
- ou_SDLC>> OrganizationsAccount("571340586587\nDev")
@@ -1,19 +0,0 @@
1
- __init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- graph_org.py,sha256=pKRj8UT59SdjLYoZZO4t1bcv6_k45yfMQ1sWeJD0-JQ,2529
3
- src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- src/reverse_diagrams.py,sha256=CyiXEO93-SILGUXs7FpylFckCm5p_x8Q-1ykyigOUOI,7573
5
- src/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- src/aws/describe_identity_store.py,sha256=ExOE_H0oXRAY1hRalc29fRXcOl5cnZ88TRh8W_4xzz8,3859
7
- src/aws/describe_organization.py,sha256=AnYPxmwquJ2OvsH0xu7fOXAWH9mRFIF9ocHWMaK4HyY,3039
8
- src/aws/describe_sso.py,sha256=AOob-7fQk6paWjBT3dBx0Fizb5IhjWp1IIrOIv6s-yQ,1720
9
- src/banner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- src/banner/banner.py,sha256=b2YVfSa7ZhuxCT6G_NFl5a7yC6T9cWB4XG_T9aHiwIY,12441
11
- src/dgms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- src/dgms/graph_mapper.py,sha256=l4koVIQBgyAV2Pw_smlacAac2lY4_rC00EbaNEbEHlY,5163
13
- src/dgms/graph_template.py,sha256=4twiySM5MFl3oRpLkjTGgdswIwi2ee3lTjPmTx5SmG4,1170
14
- src/export_report/export_csv.py,sha256=6A3ZpoBnk6l1GVVmpH-_id6vKdd6JGipNCUwURtyIUs,88
15
- reverse_diagrams-0.1.10.dist-info/METADATA,sha256=gM4tBIKMB3xJC6juzJkcTw1B16qooDLAKdyPttlHLgU,5112
16
- reverse_diagrams-0.1.10.dist-info/WHEEL,sha256=hKi7AIIx6qfnsRbr087vpeJnrVUuDokDHZacPPMW7-Y,87
17
- reverse_diagrams-0.1.10.dist-info/entry_points.txt,sha256=VZNkrc7qUDbddTCH3pGd83EhUT3PHTx9MzpAk6bb6qc,63
18
- reverse_diagrams-0.1.10.dist-info/licenses/LICENSE,sha256=MM9PkfvzhAUao9B4KNX1DhHSKAhDf_-raLPgZPldwhw,1095
19
- reverse_diagrams-0.1.10.dist-info/RECORD,,