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.
- {reverse_diagrams-0.1.10.dist-info → reverse_diagrams-0.2.6.dist-info}/METADATA +10 -7
- reverse_diagrams-0.2.6.dist-info/RECORD +17 -0
- {reverse_diagrams-0.1.10.dist-info → reverse_diagrams-0.2.6.dist-info}/WHEEL +1 -1
- {reverse_diagrams-0.1.10.dist-info → reverse_diagrams-0.2.6.dist-info}/licenses/LICENSE +1 -1
- src/aws/describe_identity_store.py +108 -7
- src/aws/describe_organization.py +3 -3
- src/banner/banner.py +16 -47
- src/dgms/graph_mapper.py +50 -20
- src/reverse_diagrams.py +33 -11
- __init__.py +0 -0
- graph_org.py +0 -84
- reverse_diagrams-0.1.10.dist-info/RECORD +0 -19
- {reverse_diagrams-0.1.10.dist-info → reverse_diagrams-0.2.6.dist-info}/entry_points.txt +0 -0
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: reverse_diagrams
|
|
3
|
-
Version: 0.
|
|
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 <
|
|
7
|
+
Author-email: Alejandro Velez <avelez@labvel.io>
|
|
9
8
|
License: MIT License
|
|
10
9
|
|
|
11
|
-
Copyright (c) [
|
|
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,,
|
|
@@ -4,13 +4,40 @@ from colorama import Fore
|
|
|
4
4
|
import logging
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
def
|
|
8
|
-
|
|
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
|
-
|
|
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":
|
|
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(
|
|
73
|
-
|
|
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
|
-
|
|
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}")
|
src/aws/describe_organization.py
CHANGED
|
@@ -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
|
|
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
|
-
|
|
79
|
+
logging.info(accounts)
|
|
80
80
|
l_account = accounts["Accounts"]
|
|
81
|
-
|
|
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
|
-
|
|
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(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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(
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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,,
|
|
File without changes
|