reverse-diagrams 1.2.4__py3-none-any.whl → 1.3.1__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-1.2.4.dist-info → reverse_diagrams-1.3.1.dist-info}/METADATA +42 -11
- {reverse_diagrams-1.2.4.dist-info → reverse_diagrams-1.3.1.dist-info}/RECORD +10 -11
- src/aws/describe_identity_store.py +11 -7
- src/aws/describe_organization.py +64 -47
- src/reports/console_view.py +62 -33
- src/reverse_diagrams.py +6 -10
- src/version.py +1 -1
- src/reports/organizations_complete_state.json +0 -93
- {reverse_diagrams-1.2.4.dist-info → reverse_diagrams-1.3.1.dist-info}/WHEEL +0 -0
- {reverse_diagrams-1.2.4.dist-info → reverse_diagrams-1.3.1.dist-info}/entry_points.txt +0 -0
- {reverse_diagrams-1.2.4.dist-info → reverse_diagrams-1.3.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: reverse_diagrams
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.1
|
|
4
4
|
Summary: Continuous Documentation Tool - Documentation as Code Tool - This package create reverse diagrams based on your current state in your cloud environment using diagrams library
|
|
5
5
|
Project-URL: Homepage, https://github.com/velez94/reverse_diagrams
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/velez94/reverse_diagrams/issues
|
|
@@ -40,10 +40,12 @@ Description-Content-Type: text/markdown
|
|
|
40
40
|
- [Use](#use)
|
|
41
41
|
- [Subcommands](#subcommands)
|
|
42
42
|
- [watch](#watch)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
- [Service supported](#service-supported)
|
|
44
|
+
- [AWS Organizations](#aws-organizations)
|
|
45
|
+
- [Identity and Access Manager Center (SSO)](#identity-and-access-manager-center-sso)
|
|
46
|
+
- [Additional Commands](#additional-commands)
|
|
47
|
+
- [watch](#watch-1)
|
|
48
|
+
- [Options](#options)
|
|
47
49
|
- [Combine the options](#combine-the-options)
|
|
48
50
|
- [Extras](#extras)
|
|
49
51
|
- [Enable autocomplete](#enable-autocomplete)
|
|
@@ -54,10 +56,11 @@ Description-Content-Type: text/markdown
|
|
|
54
56
|
|
|
55
57
|
> Continuous Documentation Tool - Documentation as Code Tool
|
|
56
58
|
|
|
57
|
-
This package create
|
|
59
|
+
This package create diagrams and help to audit your services from your shell.
|
|
60
|
+
|
|
58
61
|
# Requirement
|
|
59
62
|
|
|
60
|
-
AWS programmatic access using AWS CLI.
|
|
63
|
+
AWS programmatic access using AWS CLI. [Configuring the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html)
|
|
61
64
|
|
|
62
65
|
|
|
63
66
|
# Install
|
|
@@ -170,19 +173,47 @@ Create view of diagrams in console based on kind of diagram and json file.:
|
|
|
170
173
|
diagrams/json/account_assignments.json.jso
|
|
171
174
|
```
|
|
172
175
|
|
|
173
|
-
|
|
176
|
+
# Service supported
|
|
174
177
|
|
|
175
|
-
|
|
178
|
+
## AWS Organizations
|
|
176
179
|
|
|
177
180
|
```commandline
|
|
178
181
|
reverse_diagrams -p my-profile -o -r us-east-2
|
|
179
182
|
```
|
|
180
|
-
|
|
183
|
+
## Identity and Access Manager Center (SSO)
|
|
181
184
|
|
|
182
185
|
```commandline
|
|
183
186
|
reverse_diagrams -p my-profile -i -r us-east-2
|
|
184
187
|
```
|
|
185
|
-
|
|
188
|
+
# Additional Commands
|
|
189
|
+
|
|
190
|
+
## watch
|
|
191
|
+
You can watch the configuration and summary in your shell based on json files generated previously.
|
|
192
|
+
|
|
193
|
+
### Options
|
|
194
|
+
|
|
195
|
+
```commandline
|
|
196
|
+
$ reverse_diagrams watch -h
|
|
197
|
+
usage: reverse_diagrams watch [-h] [-wo WATCH_GRAPH_ORGANIZATION] [-wi WATCH_GRAPH_IDENTITY] [-wa WATCH_GRAPH_ACCOUNTS_ASSIGNMENTS]
|
|
198
|
+
|
|
199
|
+
Create view of diagrams in console based on kind of diagram and json file.
|
|
200
|
+
|
|
201
|
+
options:
|
|
202
|
+
-h, --help show this help message and exit
|
|
203
|
+
|
|
204
|
+
Create view of diagrams in console based on kind of diagram and json file.:
|
|
205
|
+
-wo WATCH_GRAPH_ORGANIZATION, --watch_graph_organization WATCH_GRAPH_ORGANIZATION
|
|
206
|
+
Set if you want to see graph for your organization structure summary. For example: reverse_diagrams watch watch -wo diagrams/json/organizations.json
|
|
207
|
+
-wi WATCH_GRAPH_IDENTITY, --watch_graph_identity WATCH_GRAPH_IDENTITY
|
|
208
|
+
Set if you want to see graph for your groups and users. For example: reverse_diagrams watch watch -wi diagrams/json/groups.json
|
|
209
|
+
-wa WATCH_GRAPH_ACCOUNTS_ASSIGNMENTS, --watch_graph_accounts_assignments WATCH_GRAPH_ACCOUNTS_ASSIGNMENTS
|
|
210
|
+
Set if you want to see graph for your IAM Center- Accounts assignments. For example: reverse_diagrams watch watch -wa diagrams/json/account_assignments.json
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
For example, to watch account assignments:
|
|
215
|
+
|
|
216
|
+

|
|
186
217
|
|
|
187
218
|
### Combine the options
|
|
188
219
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
src/__init__.py,sha256=lOE8TAJF_WdxgxEBxVz9t8dC3s3t2c21VWYPrzfznkE,17
|
|
2
|
-
src/reverse_diagrams.py,sha256=
|
|
3
|
-
src/version.py,sha256=
|
|
2
|
+
src/reverse_diagrams.py,sha256=dVkz429-8MtDAfQFxVhchuuVrH8D-IcYyTBgRnw65cA,4208
|
|
3
|
+
src/version.py,sha256=lyd6uObU7M31dNBuGYnxL9c0wbRwaQfFrSpXL3QGeKs,48
|
|
4
4
|
src/aws/__init__.py,sha256=lOE8TAJF_WdxgxEBxVz9t8dC3s3t2c21VWYPrzfznkE,17
|
|
5
|
-
src/aws/describe_identity_store.py,sha256=
|
|
6
|
-
src/aws/describe_organization.py,sha256=
|
|
5
|
+
src/aws/describe_identity_store.py,sha256=oqw7KfwQFGySnQz-qAuJDCpRoJLTpN2eiyamXiln6x0,15364
|
|
6
|
+
src/aws/describe_organization.py,sha256=_FEikrnsP1HaXhfglaQwHfOR1KGdDtF6gc5DAPcXsRs,13962
|
|
7
7
|
src/aws/describe_sso.py,sha256=z65RnoxJDVSMPB1TRJAxi8S8-DllwmaxxXaZ4uicSzU,4915
|
|
8
8
|
src/banner/__init__.py,sha256=lOE8TAJF_WdxgxEBxVz9t8dC3s3t2c21VWYPrzfznkE,17
|
|
9
9
|
src/banner/banner.py,sha256=XREWjVLp1-PHVdfBSoADgw0LvRpYU5u7NPaUraL9Els,3893
|
|
@@ -11,12 +11,11 @@ src/dgms/__init__.py,sha256=lOE8TAJF_WdxgxEBxVz9t8dC3s3t2c21VWYPrzfznkE,17
|
|
|
11
11
|
src/dgms/graph_mapper.py,sha256=xutxzxLCIGSBfHCAF-BnWXN21bjzusA43ZhKtXUir2E,7714
|
|
12
12
|
src/dgms/graph_template.py,sha256=IOEmTk9A0xqEhtdNnaFrVDJlBF0ggW0WpxosW4nbcQo,1217
|
|
13
13
|
src/reports/__init__.py,sha256=lOE8TAJF_WdxgxEBxVz9t8dC3s3t2c21VWYPrzfznkE,17
|
|
14
|
-
src/reports/console_view.py,sha256=
|
|
15
|
-
src/reports/organizations_complete_state.json,sha256=nP30DTrwlm5aw6YZB03CiLyK9snjTgdH1ZjZRq3bXVI,2628
|
|
14
|
+
src/reports/console_view.py,sha256=1_ET53Bn_vKlLmqr0Sih5szP5kNFCQRH4A8tXJgip2Y,5832
|
|
16
15
|
src/reports/save_results.py,sha256=g-UphsQ_tfDhvNH3QNV7j68TWWvy44vbbjaNyn4KWhU,719
|
|
17
16
|
src/reports/tes.py,sha256=c6TdxhAedfHjPrqaRw0nucdCEQOM9xKsgw35IOIDdYs,17691
|
|
18
|
-
reverse_diagrams-1.
|
|
19
|
-
reverse_diagrams-1.
|
|
20
|
-
reverse_diagrams-1.
|
|
21
|
-
reverse_diagrams-1.
|
|
22
|
-
reverse_diagrams-1.
|
|
17
|
+
reverse_diagrams-1.3.1.dist-info/METADATA,sha256=xOmutWsxQYayFL0MQOw80RD9phB-eP4sGo812soczRk,9542
|
|
18
|
+
reverse_diagrams-1.3.1.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
|
|
19
|
+
reverse_diagrams-1.3.1.dist-info/entry_points.txt,sha256=VZNkrc7qUDbddTCH3pGd83EhUT3PHTx9MzpAk6bb6qc,63
|
|
20
|
+
reverse_diagrams-1.3.1.dist-info/licenses/LICENSE,sha256=o6nDaQ7M9xbR0L7HSJ3A-1JbBPoZro_zhVPO4-M5CAQ,571
|
|
21
|
+
reverse_diagrams-1.3.1.dist-info/RECORD,,
|
|
@@ -15,6 +15,10 @@ from ..dgms.graph_template import (
|
|
|
15
15
|
graph_template_sso,
|
|
16
16
|
graph_template_sso_complete,
|
|
17
17
|
)
|
|
18
|
+
from ..reports.console_view import (
|
|
19
|
+
create_account_assignments_view,
|
|
20
|
+
create_group_console_view,
|
|
21
|
+
)
|
|
18
22
|
from ..reports.save_results import save_results
|
|
19
23
|
from .describe_organization import list_accounts
|
|
20
24
|
from .describe_sso import (
|
|
@@ -24,7 +28,6 @@ from .describe_sso import (
|
|
|
24
28
|
list_instances,
|
|
25
29
|
list_permissions_set,
|
|
26
30
|
)
|
|
27
|
-
from ..reports.console_view import create_group_console_view, create_account_assignments_view, load_json
|
|
28
31
|
|
|
29
32
|
|
|
30
33
|
def list_groups_pag(identity_store_id, region, next_token: str = None):
|
|
@@ -59,8 +62,7 @@ def list_groups(identity_store_id, region):
|
|
|
59
62
|
identity_client = client("identitystore", region_name=region)
|
|
60
63
|
|
|
61
64
|
groups = identity_client.list_groups(
|
|
62
|
-
IdentityStoreId=identity_store_id,
|
|
63
|
-
MaxResults=20
|
|
65
|
+
IdentityStoreId=identity_store_id, MaxResults=20
|
|
64
66
|
)
|
|
65
67
|
|
|
66
68
|
logging.info(groups)
|
|
@@ -278,7 +280,7 @@ def extend_account_assignments(accounts_list, permissions_sets, store_arn, regio
|
|
|
278
280
|
for p, y in zip(
|
|
279
281
|
permissions_sets,
|
|
280
282
|
track(
|
|
281
|
-
range(len(permissions_sets)
|
|
283
|
+
range(len(permissions_sets)),
|
|
282
284
|
description="Getting account assignments ...",
|
|
283
285
|
),
|
|
284
286
|
):
|
|
@@ -314,7 +316,7 @@ def add_users_and_groups_assign(
|
|
|
314
316
|
for a, y in zip(
|
|
315
317
|
account_assignments_list,
|
|
316
318
|
track(
|
|
317
|
-
range(len(account_assignments_list)
|
|
319
|
+
range(len(account_assignments_list)),
|
|
318
320
|
description="Create user and groups assignments ...",
|
|
319
321
|
),
|
|
320
322
|
):
|
|
@@ -483,8 +485,10 @@ def graph_identity_center(diagrams_path, region, auto):
|
|
|
483
485
|
print(Fore.RED + "❌ Error creating diagrams")
|
|
484
486
|
print(command)
|
|
485
487
|
|
|
486
|
-
create_group_console_view(groups=
|
|
487
|
-
create_account_assignments_view(
|
|
488
|
+
create_group_console_view(groups=d_groups) # (f"{json_path}/groups.json")
|
|
489
|
+
create_account_assignments_view(
|
|
490
|
+
assign=f_accounts
|
|
491
|
+
) # load_json(f"{json_path}/account_assignments.json"))
|
|
488
492
|
else:
|
|
489
493
|
print(
|
|
490
494
|
Fore.YELLOW
|
src/aws/describe_organization.py
CHANGED
|
@@ -242,80 +242,93 @@ def search_ou_map(map_ou: dict, ou_id, level=0, tree="."):
|
|
|
242
242
|
return None
|
|
243
243
|
|
|
244
244
|
|
|
245
|
-
def init_org_complete(
|
|
245
|
+
def init_org_complete(
|
|
246
|
+
root_id,
|
|
247
|
+
org,
|
|
248
|
+
list_ous,
|
|
249
|
+
):
|
|
250
|
+
"""
|
|
251
|
+
Init organization dictionary.
|
|
252
|
+
|
|
253
|
+
:param root_id:
|
|
254
|
+
:param org:
|
|
255
|
+
:param list_ous:
|
|
256
|
+
:return:
|
|
257
|
+
"""
|
|
246
258
|
organizations_complete = {
|
|
247
259
|
"rootId": root_id,
|
|
248
|
-
"masterAccountId": org[
|
|
260
|
+
"masterAccountId": org["MasterAccountId"],
|
|
249
261
|
"noOutAccounts": [],
|
|
250
|
-
"organizationalUnits": {}
|
|
262
|
+
"organizationalUnits": {},
|
|
251
263
|
}
|
|
252
|
-
|
|
253
264
|
# Iterate in ous for getting ous tree
|
|
254
265
|
for a, i in zip(list_ous, range(len(list_ous))):
|
|
255
|
-
|
|
256
266
|
for p in a["Parents"]:
|
|
257
267
|
if p["Type"] == "ROOT":
|
|
258
|
-
organizations_complete["organizationalUnits"][a[
|
|
259
|
-
"Id": a[
|
|
260
|
-
"Name": a[
|
|
268
|
+
organizations_complete["organizationalUnits"][a["Name"]] = {
|
|
269
|
+
"Id": a["Id"],
|
|
270
|
+
"Name": a["Name"],
|
|
261
271
|
"accounts": {},
|
|
262
|
-
"nestedOus": {}
|
|
272
|
+
"nestedOus": {},
|
|
273
|
+
}
|
|
263
274
|
return organizations_complete
|
|
264
275
|
|
|
265
276
|
|
|
266
277
|
# create organization complete map
|
|
267
|
-
def map_organizations_complete(
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
278
|
+
def map_organizations_complete(
|
|
279
|
+
organizations_complete: dict,
|
|
280
|
+
list_ous,
|
|
281
|
+
llist_accounts,
|
|
282
|
+
reference_outs_list,
|
|
283
|
+
):
|
|
271
284
|
"""
|
|
272
285
|
Create complete mapper file.
|
|
273
286
|
|
|
274
|
-
|
|
275
287
|
:param reference_outs_list:
|
|
276
288
|
:param organizations_complete:
|
|
277
289
|
:param list_ous:
|
|
278
290
|
:param llist_accounts:
|
|
279
291
|
:return:
|
|
280
292
|
"""
|
|
281
|
-
|
|
282
293
|
# Iterate in ous for getting ous tree
|
|
283
294
|
for a, i in zip(list_ous, range(len(list_ous))):
|
|
284
|
-
|
|
285
295
|
for p in a["Parents"]:
|
|
286
|
-
|
|
287
296
|
if p["Type"] == "ORGANIZATIONAL_UNIT":
|
|
288
|
-
|
|
289
|
-
o = find_ou_name(reference_outs_list, p['Id'])
|
|
297
|
+
o = find_ou_name(reference_outs_list, p["Id"])
|
|
290
298
|
|
|
291
299
|
if o not in organizations_complete["organizationalUnits"].keys():
|
|
292
|
-
p = search_ou_map(
|
|
300
|
+
p = search_ou_map(
|
|
301
|
+
organizations_complete["organizationalUnits"], ou_id=o
|
|
302
|
+
)
|
|
293
303
|
o = p["Name"]
|
|
294
304
|
|
|
295
305
|
organizations_complete["organizationalUnits"][o]["nestedOus"][
|
|
296
|
-
find_ou_name(reference_outs_list, a[
|
|
297
|
-
|
|
298
|
-
"Id": a['Id'],
|
|
299
|
-
"Name": a['Name'],
|
|
300
|
-
"accounts": [],
|
|
301
|
-
"nestedOus": {}
|
|
302
|
-
|
|
303
|
-
}
|
|
306
|
+
find_ou_name(reference_outs_list, a["Id"])
|
|
307
|
+
] = {"Id": a["Id"], "Name": a["Name"], "accounts": [], "nestedOus": {}}
|
|
304
308
|
# print(organizations_complete["organizationalUnits"][o]["nestedOus"])
|
|
305
|
-
if
|
|
306
|
-
|
|
309
|
+
if (
|
|
310
|
+
len(organizations_complete["organizationalUnits"][o]["nestedOus"])
|
|
311
|
+
> 0
|
|
312
|
+
):
|
|
313
|
+
new_list_ous = organizations_complete["organizationalUnits"][o][
|
|
314
|
+
"nestedOus"
|
|
315
|
+
]
|
|
307
316
|
|
|
308
317
|
new_list_ous = plop_dict_out(ous_list=list_ous, ou=new_list_ous)
|
|
309
318
|
organizations_complete = map_organizations_complete(
|
|
310
319
|
organizations_complete=organizations_complete,
|
|
311
320
|
list_ous=new_list_ous,
|
|
312
321
|
llist_accounts=llist_accounts,
|
|
313
|
-
reference_outs_list=reference_outs_list
|
|
322
|
+
reference_outs_list=reference_outs_list,
|
|
323
|
+
)
|
|
314
324
|
|
|
315
325
|
return organizations_complete
|
|
316
326
|
|
|
317
327
|
|
|
318
|
-
def plop_dict_out(
|
|
328
|
+
def plop_dict_out(
|
|
329
|
+
ous_list: list,
|
|
330
|
+
ou,
|
|
331
|
+
):
|
|
319
332
|
"""
|
|
320
333
|
Clean list.
|
|
321
334
|
|
|
@@ -324,7 +337,6 @@ def plop_dict_out(ous_list: list, ou, ):
|
|
|
324
337
|
:return:
|
|
325
338
|
"""
|
|
326
339
|
for o in ou.keys():
|
|
327
|
-
|
|
328
340
|
# for c in ou.keys():
|
|
329
341
|
for unit in ous_list:
|
|
330
342
|
if unit["Id"] == ou[o]["Id"]:
|
|
@@ -348,18 +360,16 @@ def set_accounts_tree(llist_accounts, organizations_complete, list_ous):
|
|
|
348
360
|
for p in c["parents"]:
|
|
349
361
|
if p["Type"] == "ROOT":
|
|
350
362
|
organizations_complete["noOutAccounts"].append(
|
|
351
|
-
{
|
|
352
|
-
"account": c["account"],
|
|
353
|
-
"name": c['name']
|
|
354
|
-
}
|
|
363
|
+
{"account": c["account"], "name": c["name"]}
|
|
355
364
|
)
|
|
356
365
|
|
|
357
366
|
for o, j in zip(list_ous, range(len(list_ous))):
|
|
358
367
|
if p["Id"] == o["Id"] and p["Type"] == "ORGANIZATIONAL_UNIT":
|
|
359
|
-
organizations_complete["organizationalUnits"][
|
|
360
|
-
|
|
368
|
+
organizations_complete["organizationalUnits"][
|
|
369
|
+
find_ou_name(list_ous, o["Id"])
|
|
370
|
+
]["accounts"][c["name"]] = {
|
|
361
371
|
"account": c["account"],
|
|
362
|
-
"name": c[
|
|
372
|
+
"name": c["name"],
|
|
363
373
|
}
|
|
364
374
|
|
|
365
375
|
return organizations_complete
|
|
@@ -391,8 +401,7 @@ def graph_organizations(diagrams_path, region, auto):
|
|
|
391
401
|
logging.debug(roots)
|
|
392
402
|
|
|
393
403
|
print(
|
|
394
|
-
Fore.BLUE
|
|
395
|
-
+ emoji.emojize(":sparkle: List Organizational Units " + Fore.RESET)
|
|
404
|
+
Fore.BLUE + emoji.emojize(":sparkle: List Organizational Units " + Fore.RESET)
|
|
396
405
|
)
|
|
397
406
|
logging.debug("The Organizational Units list ")
|
|
398
407
|
ous = list_organizational_units(parent_id=roots[0]["Id"], region=region)
|
|
@@ -432,12 +441,20 @@ def graph_organizations(diagrams_path, region, auto):
|
|
|
432
441
|
file_name = "organizations_complete.json"
|
|
433
442
|
# view in console
|
|
434
443
|
organizations_complete_f = map_organizations_complete(
|
|
435
|
-
organizations_complete=init_org_complete(
|
|
436
|
-
|
|
437
|
-
|
|
444
|
+
organizations_complete=init_org_complete(
|
|
445
|
+
org=organization, root_id=roots[0]["Id"], list_ous=i_ous
|
|
446
|
+
),
|
|
447
|
+
llist_accounts=i_accounts,
|
|
448
|
+
list_ous=i_ous,
|
|
449
|
+
reference_outs_list=i_ous.copy(),
|
|
450
|
+
)
|
|
451
|
+
organizations_complete_f = (
|
|
452
|
+
set_accounts_tree(
|
|
453
|
+
llist_accounts=i_accounts,
|
|
454
|
+
organizations_complete=organizations_complete_f,
|
|
455
|
+
list_ous=i_ous,
|
|
456
|
+
),
|
|
438
457
|
)
|
|
439
|
-
organizations_complete_f = set_accounts_tree(llist_accounts=i_accounts,
|
|
440
|
-
organizations_complete=organizations_complete_f, list_ous=i_ous),
|
|
441
458
|
|
|
442
459
|
save_results(results=organizations_complete_f, filename=f"{json_path}/{file_name}")
|
|
443
460
|
|
src/reports/console_view.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
"""Create Console View."""
|
|
1
2
|
import json
|
|
2
|
-
|
|
3
|
+
|
|
4
|
+
import inquirer
|
|
3
5
|
from rich.columns import Columns
|
|
6
|
+
from rich.console import Console
|
|
4
7
|
from rich.panel import Panel
|
|
5
|
-
from colorama import Fore
|
|
6
|
-
import inquirer
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
# load json file from path function
|
|
@@ -14,7 +15,7 @@ def load_json(path):
|
|
|
14
15
|
:param path:
|
|
15
16
|
:return:
|
|
16
17
|
"""
|
|
17
|
-
with open(path,
|
|
18
|
+
with open(path, "r") as f:
|
|
18
19
|
return json.load(f)
|
|
19
20
|
|
|
20
21
|
|
|
@@ -28,7 +29,7 @@ def get_members(group):
|
|
|
28
29
|
members_groups = {}
|
|
29
30
|
for m in group:
|
|
30
31
|
members_groups[group[m]["group_name"]] = []
|
|
31
|
-
for mm in group[m][
|
|
32
|
+
for mm in group[m]["members"]:
|
|
32
33
|
members_groups[group[m]["group_name"]].append(mm["MemberId"]["UserName"])
|
|
33
34
|
|
|
34
35
|
return members_groups
|
|
@@ -57,7 +58,13 @@ def create_group_console_view(groups):
|
|
|
57
58
|
"""
|
|
58
59
|
members = get_members(groups)
|
|
59
60
|
console = Console()
|
|
60
|
-
c = [
|
|
61
|
+
c = [
|
|
62
|
+
Panel(
|
|
63
|
+
f"[b][green]{group}[/b]\n[yellow]{pretty_members(members[group])}",
|
|
64
|
+
expand=True,
|
|
65
|
+
)
|
|
66
|
+
for group in groups
|
|
67
|
+
]
|
|
61
68
|
console.print(Columns(c))
|
|
62
69
|
|
|
63
70
|
|
|
@@ -69,7 +76,6 @@ def single_create_group_assignments_view(members, group_name):
|
|
|
69
76
|
:param members:
|
|
70
77
|
:return:
|
|
71
78
|
"""
|
|
72
|
-
|
|
73
79
|
console = Console()
|
|
74
80
|
c = [Panel(f"[b]{group_name}[/b]\n[blue]{pretty_members(members)}", expand=True)]
|
|
75
81
|
console.print(Columns(c))
|
|
@@ -83,9 +89,12 @@ def create_string_account_assignment(account_assignment):
|
|
|
83
89
|
:return:
|
|
84
90
|
"""
|
|
85
91
|
string = ""
|
|
86
|
-
if
|
|
92
|
+
if (
|
|
93
|
+
account_assignment["PrincipalType"] == "GROUP"
|
|
94
|
+
and "GroupName" in account_assignment.keys()
|
|
95
|
+
):
|
|
87
96
|
string += f"GroupName: {account_assignment['GroupName']}\n"
|
|
88
|
-
elif account_assignment[
|
|
97
|
+
elif account_assignment["PrincipalType"] == "USER":
|
|
89
98
|
string += f"UserName: {account_assignment['UserName']}\n"
|
|
90
99
|
if "PermissionSetName" in account_assignment.keys():
|
|
91
100
|
string += f"PermissionSetName: {account_assignment['PermissionSetName']}\n\n"
|
|
@@ -102,7 +111,6 @@ def pretty_account_assignments(accounts: dict):
|
|
|
102
111
|
"""
|
|
103
112
|
string = ""
|
|
104
113
|
if isinstance(accounts, dict):
|
|
105
|
-
|
|
106
114
|
for a in accounts.keys():
|
|
107
115
|
for c in accounts[a]:
|
|
108
116
|
string += create_string_account_assignment(account_assignment=c)
|
|
@@ -120,9 +128,13 @@ def single_create_account_assignments_view(assign, account_name):
|
|
|
120
128
|
:param assign:
|
|
121
129
|
:return:
|
|
122
130
|
"""
|
|
123
|
-
|
|
124
131
|
console = Console()
|
|
125
|
-
c = [
|
|
132
|
+
c = [
|
|
133
|
+
Panel(
|
|
134
|
+
f"[b]{account_name}[/b]\n[blue]{pretty_account_assignments(assign)}",
|
|
135
|
+
expand=True,
|
|
136
|
+
)
|
|
137
|
+
]
|
|
126
138
|
console.print(Columns(c))
|
|
127
139
|
|
|
128
140
|
|
|
@@ -134,23 +146,29 @@ def create_console_view_from_input(assign):
|
|
|
134
146
|
:return:
|
|
135
147
|
"""
|
|
136
148
|
# execute while the user decide to leave
|
|
137
|
-
con =
|
|
138
|
-
while con ==
|
|
149
|
+
con = "yes"
|
|
150
|
+
while con == "yes":
|
|
139
151
|
questions = [
|
|
140
|
-
inquirer.List(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
152
|
+
inquirer.List(
|
|
153
|
+
"account",
|
|
154
|
+
message="Which account do you want to see?",
|
|
155
|
+
choices=list(assign.keys()),
|
|
156
|
+
),
|
|
144
157
|
]
|
|
145
158
|
answers = inquirer.prompt(questions)
|
|
146
|
-
single_create_account_assignments_view(
|
|
159
|
+
single_create_account_assignments_view(
|
|
160
|
+
assign[answers["account"]], account_name=answers["account"]
|
|
161
|
+
)
|
|
147
162
|
# execute while the user decide to leave
|
|
148
|
-
continue_ = [
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
163
|
+
continue_ = [
|
|
164
|
+
inquirer.List(
|
|
165
|
+
name="ans",
|
|
166
|
+
message="Do you want to watch another account ?",
|
|
167
|
+
choices=["yes", "no"],
|
|
168
|
+
)
|
|
169
|
+
]
|
|
152
170
|
continue_ans = inquirer.prompt(continue_)
|
|
153
|
-
con = continue_ans[
|
|
171
|
+
con = continue_ans["ans"]
|
|
154
172
|
|
|
155
173
|
|
|
156
174
|
def ask_control(case):
|
|
@@ -161,12 +179,15 @@ def ask_control(case):
|
|
|
161
179
|
:param case:
|
|
162
180
|
:return:
|
|
163
181
|
"""
|
|
164
|
-
control_ = [
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
182
|
+
control_ = [
|
|
183
|
+
inquirer.List(
|
|
184
|
+
name="ans",
|
|
185
|
+
message=f"Do you want to watch all {case}?",
|
|
186
|
+
choices=["all", "one-at-time"],
|
|
187
|
+
)
|
|
188
|
+
]
|
|
168
189
|
control_ans = inquirer.prompt(control_)
|
|
169
|
-
control = control_ans[
|
|
190
|
+
control = control_ans["ans"]
|
|
170
191
|
return control
|
|
171
192
|
|
|
172
193
|
|
|
@@ -178,12 +199,17 @@ def create_account_assignments_view(assign):
|
|
|
178
199
|
:return:
|
|
179
200
|
"""
|
|
180
201
|
control = ask_control(case="account assignments or account by account")
|
|
181
|
-
if control ==
|
|
202
|
+
if control == "one-at-time":
|
|
182
203
|
create_console_view_from_input(assign=assign)
|
|
183
204
|
else:
|
|
184
|
-
|
|
185
205
|
console = Console()
|
|
186
|
-
c = [
|
|
206
|
+
c = [
|
|
207
|
+
Panel(
|
|
208
|
+
f"[b]{account}[/b]\n[blue]{pretty_account_assignments(assign)}",
|
|
209
|
+
expand=True,
|
|
210
|
+
)
|
|
211
|
+
for account in assign
|
|
212
|
+
]
|
|
187
213
|
console.print(Columns(c))
|
|
188
214
|
|
|
189
215
|
|
|
@@ -191,7 +217,10 @@ def create_account_assignments_view(assign):
|
|
|
191
217
|
|
|
192
218
|
# pretty for organizations
|
|
193
219
|
|
|
194
|
-
|
|
220
|
+
|
|
221
|
+
def watch_on_demand(
|
|
222
|
+
args,
|
|
223
|
+
):
|
|
195
224
|
"""
|
|
196
225
|
Watch on demand graphs in console.
|
|
197
226
|
|
src/reverse_diagrams.py
CHANGED
|
@@ -8,8 +8,8 @@ from boto3 import setup_default_session
|
|
|
8
8
|
from .aws.describe_identity_store import graph_identity_center
|
|
9
9
|
from .aws.describe_organization import graph_organizations
|
|
10
10
|
from .banner.banner import get_version
|
|
11
|
-
from .version import __version__
|
|
12
11
|
from .reports.console_view import watch_on_demand
|
|
12
|
+
from .version import __version__
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def main() -> int:
|
|
@@ -22,7 +22,7 @@ def main() -> int:
|
|
|
22
22
|
parser = argparse.ArgumentParser(
|
|
23
23
|
prog="reverse_diagrams",
|
|
24
24
|
description="Create architecture diagram, inspect and audit your AWS services from your current state.",
|
|
25
|
-
epilog="Thanks for using %(prog)s!"
|
|
25
|
+
epilog="Thanks for using %(prog)s!",
|
|
26
26
|
)
|
|
27
27
|
|
|
28
28
|
parser.add_argument(
|
|
@@ -66,7 +66,7 @@ def main() -> int:
|
|
|
66
66
|
name="watch",
|
|
67
67
|
description="Create view of diagrams in console based on kind of diagram and json file.",
|
|
68
68
|
help="Create pretty console view: \n"
|
|
69
|
-
|
|
69
|
+
"For example: %(prog)s watch -wi diagrams/json/account_assignments.json ",
|
|
70
70
|
)
|
|
71
71
|
# Add idp options
|
|
72
72
|
watch_group = watch_parser.add_argument_group(
|
|
@@ -76,22 +76,19 @@ def main() -> int:
|
|
|
76
76
|
"-wo",
|
|
77
77
|
"--watch_graph_organization",
|
|
78
78
|
help="Set if you want to see graph for your organization structure summary.\n"
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
"For example: %(prog)s watch -wo diagrams/json/organizations.json",
|
|
81
80
|
)
|
|
82
81
|
watch_group.add_argument(
|
|
83
82
|
"-wi",
|
|
84
83
|
"--watch_graph_identity",
|
|
85
84
|
help="Set if you want to see graph for your groups and users. \n"
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
"For example: %(prog)s watch -wi diagrams/json/groups.json",
|
|
88
86
|
)
|
|
89
87
|
watch_group.add_argument(
|
|
90
88
|
"-wa",
|
|
91
89
|
"--watch_graph_accounts_assignments",
|
|
92
90
|
help="Set if you want to see graph for your IAM Center- Accounts assignments. \n"
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
"For example: %(prog)s watch -wa diagrams/json/account_assignments.json",
|
|
95
92
|
)
|
|
96
93
|
|
|
97
94
|
parser.add_argument("-v", "--version", help="Show version", action="store_true")
|
|
@@ -126,7 +123,6 @@ def main() -> int:
|
|
|
126
123
|
diagrams_path=diagrams_path, region=region, auto=args.auto_create
|
|
127
124
|
)
|
|
128
125
|
if args.commands == "watch":
|
|
129
|
-
|
|
130
126
|
watch_on_demand(args=args)
|
|
131
127
|
|
|
132
128
|
if args.version:
|
src/version.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""Set version file."""
|
|
2
|
-
__version__ = "1.
|
|
2
|
+
__version__ = "1.3.1"
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"rootId": "r-w3ow",
|
|
3
|
-
"masterAccountId": "029921763173",
|
|
4
|
-
"noOutAccounts": [
|
|
5
|
-
{
|
|
6
|
-
"account": "029921763173",
|
|
7
|
-
"name": "Alejandro Velez"
|
|
8
|
-
}
|
|
9
|
-
],
|
|
10
|
-
"organizationalUnits": {
|
|
11
|
-
"Research": {
|
|
12
|
-
"Id": "ou-w3ow-oegm0al0",
|
|
13
|
-
"Name": "Research",
|
|
14
|
-
"accounts": {},
|
|
15
|
-
"nestedOus": {}
|
|
16
|
-
},
|
|
17
|
-
"Dev": {
|
|
18
|
-
"Id": "ou-w3ow-k24p2opx",
|
|
19
|
-
"Name": "Dev",
|
|
20
|
-
"accounts": {
|
|
21
|
-
"LabVelCT": {
|
|
22
|
-
"account": "994261317734",
|
|
23
|
-
"name": "LabVelCT"
|
|
24
|
-
},
|
|
25
|
-
"Dev": {
|
|
26
|
-
"account": "571340586587",
|
|
27
|
-
"name": "Dev"
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
"nestedOus": {}
|
|
31
|
-
},
|
|
32
|
-
"Core": {
|
|
33
|
-
"Id": "ou-w3ow-93hiq3zr",
|
|
34
|
-
"Name": "Core",
|
|
35
|
-
"accounts": {
|
|
36
|
-
"Log archive": {
|
|
37
|
-
"account": "884478634998",
|
|
38
|
-
"name": "Log archive"
|
|
39
|
-
},
|
|
40
|
-
"Audit": {
|
|
41
|
-
"account": "895882538541",
|
|
42
|
-
"name": "Audit"
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
"nestedOus": {}
|
|
46
|
-
},
|
|
47
|
-
"Custom": {
|
|
48
|
-
"Id": "ou-w3ow-5qsqi8b5",
|
|
49
|
-
"Name": "Custom",
|
|
50
|
-
"accounts": {
|
|
51
|
-
"Prod": {
|
|
52
|
-
"account": "582441254763",
|
|
53
|
-
"name": "Prod"
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
"nestedOus": {
|
|
57
|
-
"NetstedOU": {
|
|
58
|
-
"Id": "ou-w3ow-i9xzgb9x",
|
|
59
|
-
"Name": "NetstedOU",
|
|
60
|
-
"accounts": [],
|
|
61
|
-
"nestedOus": {}
|
|
62
|
-
},
|
|
63
|
-
"NetstedOU2": {
|
|
64
|
-
"Id": "ou-w3ow-i9xzgxxx",
|
|
65
|
-
"Name": "NetstedOU2",
|
|
66
|
-
"accounts": [],
|
|
67
|
-
"nestedOus": {}
|
|
68
|
-
},
|
|
69
|
-
"NetstedOU3": {
|
|
70
|
-
"Id": "ou-w3ow-i9xzgxx3",
|
|
71
|
-
"Name": "NetstedOU3",
|
|
72
|
-
"accounts": [],
|
|
73
|
-
"nestedOus": {}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
"Shared": {
|
|
78
|
-
"Id": "ou-w3ow-w7dzhzcz",
|
|
79
|
-
"Name": "Shared",
|
|
80
|
-
"accounts": {
|
|
81
|
-
"DevSecOps": {
|
|
82
|
-
"account": "105171185823",
|
|
83
|
-
"name": "DevSecOps"
|
|
84
|
-
},
|
|
85
|
-
"SharedServices": {
|
|
86
|
-
"account": "155794986228",
|
|
87
|
-
"name": "SharedServices"
|
|
88
|
-
}
|
|
89
|
-
},
|
|
90
|
-
"nestedOus": {}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|