reverse-diagrams 0.2.5__py3-none-any.whl → 1.0.0__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.2.5.dist-info → reverse_diagrams-1.0.0.dist-info}/METADATA +36 -24
- reverse_diagrams-1.0.0.dist-info/RECORD +20 -0
- {reverse_diagrams-0.2.5.dist-info → reverse_diagrams-1.0.0.dist-info}/WHEEL +1 -1
- reverse_diagrams-1.0.0.dist-info/licenses/LICENSE +13 -0
- src/aws/describe_identity_store.py +172 -49
- src/aws/describe_organization.py +91 -36
- src/aws/describe_sso.py +133 -20
- src/banner/banner.py +7 -2
- src/dgms/graph_mapper.py +76 -32
- src/dgms/graph_template.py +4 -4
- src/export_report/export_csv.py +3 -2
- src/reports/save_results.py +24 -0
- src/reverse_diagrams.py +325 -169
- src/version.py +2 -0
- docs/graph_org.py +0 -8
- docs/graph_sso.py +0 -39
- docs/graph_sso_complete.py +0 -596
- reverse_diagrams-0.2.5.dist-info/RECORD +0 -21
- reverse_diagrams-0.2.5.dist-info/licenses/LICENSE +0 -21
- {reverse_diagrams-0.2.5.dist-info → reverse_diagrams-1.0.0.dist-info}/entry_points.txt +0 -0
- /__init__.py → /src/reports/__init__.py +0 -0
|
@@ -1,42 +1,32 @@
|
|
|
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: 1.0.0
|
|
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
|
|
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
7
|
Author-email: Alejandro Velez <avelez@labvel.io>
|
|
9
|
-
License:
|
|
8
|
+
License: Copyright [2024] [Alejandro Velez]
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
11
|
+
you may not use this file except in compliance with the License.
|
|
12
|
+
You may obtain a copy of the License at
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
-
in the Software without restriction, including without limitation the rights
|
|
16
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
-
furnished to do so, subject to the following conditions:
|
|
14
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
19
15
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
-
SOFTWARE.
|
|
16
|
+
Unless required by applicable law or agreed to in writing, software
|
|
17
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
18
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
19
|
+
See the License for the specific language governing permissions and
|
|
20
|
+
limitations under the License.
|
|
30
21
|
License-File: LICENSE
|
|
31
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
32
22
|
Classifier: Operating System :: OS Independent
|
|
33
23
|
Classifier: Programming Language :: Python :: 3
|
|
34
24
|
Requires-Python: >=3.8
|
|
35
25
|
Requires-Dist: boto3>=1.26.44
|
|
36
26
|
Requires-Dist: colorama>=0.4.4
|
|
37
|
-
Requires-Dist: diagrams>=0.
|
|
27
|
+
Requires-Dist: diagrams>=0.23.4
|
|
38
28
|
Requires-Dist: emoji>=2.2.0
|
|
39
|
-
Requires-Dist:
|
|
29
|
+
Requires-Dist: rich>=13.7.0
|
|
40
30
|
Description-Content-Type: text/markdown
|
|
41
31
|
|
|
42
32
|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
|
@@ -157,3 +147,25 @@ reverse_diagrams -c aws -p my-profile -i -r us-east-2
|
|
|
157
147
|
reverse_diagrams -c aws -p my-profile -o -i -r us-east-2
|
|
158
148
|
```
|
|
159
149
|
|
|
150
|
+
## Extras
|
|
151
|
+
### Enable autocomplete
|
|
152
|
+
Argcomplete provides easy, extensible command line tab completion of arguments for your Python application.
|
|
153
|
+
|
|
154
|
+
It makes two assumptions:
|
|
155
|
+
|
|
156
|
+
* You’re using bash or zsh as your shell
|
|
157
|
+
|
|
158
|
+
* You’re using argparse to manage your command line arguments/options
|
|
159
|
+
|
|
160
|
+
Argcomplete is particularly useful if your program has lots of options or subparsers, and if your program can dynamically suggest completions for your argument/option values (for example, if the user is browsing resources over the network).
|
|
161
|
+
Run:
|
|
162
|
+
```bash
|
|
163
|
+
activate-global-python-argcomplete
|
|
164
|
+
```
|
|
165
|
+
and to make sure that bash knows about this script, you use
|
|
166
|
+
```bash
|
|
167
|
+
|
|
168
|
+
echo 'eval "$(register-python-argcomplete reverse_diagrams)"' >> ~/.bashrc
|
|
169
|
+
source ~/.bashrc
|
|
170
|
+
|
|
171
|
+
```
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
src/reverse_diagrams.py,sha256=xC4alfmJ4CZcgnjShXE13ZvehhSuxSkrQxhs4LX1FVU,9496
|
|
3
|
+
src/version.py,sha256=GdBzLFWoHZyrTuCHs8_6o2940bb1o4TwZpxxsOIS-kI,48
|
|
4
|
+
src/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
src/aws/describe_identity_store.py,sha256=2mmniQowKhatfg7ekLdJASz424j0gkP9TJ-ArEeb8Po,8838
|
|
6
|
+
src/aws/describe_organization.py,sha256=S9r-lCy3NX1e1qpLw_gMl_-nbeE5RXcISLMdThDOp7w,4731
|
|
7
|
+
src/aws/describe_sso.py,sha256=LMejRRupMckB6r2akK8Nyu35AFzyvprwh4QnzAQvmoA,4832
|
|
8
|
+
src/banner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
src/banner/banner.py,sha256=aGFVaW7RVdhgMi8b3YeC6MQodhJd01MO3iTTHlQRw8s,979
|
|
10
|
+
src/dgms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
src/dgms/graph_mapper.py,sha256=vzBgjdFzO7nseqTXp0Z68-f5OgtZaDsThfMNy8Q7kjg,7402
|
|
12
|
+
src/dgms/graph_template.py,sha256=QMTsbYPt9uZkWS9r7h8UDc7NP7BKcCP1j523soeQrOQ,1176
|
|
13
|
+
src/export_report/export_csv.py,sha256=7j53bcuXK1x6ciGzq88psfyguhQWo36uVFYxp0y8p34,92
|
|
14
|
+
src/reports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
+
src/reports/save_results.py,sha256=eOYGmp1-2Kfaf5k-cUZ7UIAQoBm59ta8sxlDUoZCfK4,689
|
|
16
|
+
reverse_diagrams-1.0.0.dist-info/METADATA,sha256=udbRPGZhORkHUAyUOYW9DLhqjb6dt6QcjPytoEaWUTQ,5528
|
|
17
|
+
reverse_diagrams-1.0.0.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
|
|
18
|
+
reverse_diagrams-1.0.0.dist-info/entry_points.txt,sha256=VZNkrc7qUDbddTCH3pGd83EhUT3PHTx9MzpAk6bb6qc,63
|
|
19
|
+
reverse_diagrams-1.0.0.dist-info/licenses/LICENSE,sha256=o6nDaQ7M9xbR0L7HSJ3A-1JbBPoZro_zhVPO4-M5CAQ,571
|
|
20
|
+
reverse_diagrams-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Copyright [2024] [Alejandro Velez]
|
|
2
|
+
|
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License.
|
|
5
|
+
You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
See the License for the specific language governing permissions and
|
|
13
|
+
limitations under the License.
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import boto3
|
|
2
|
-
from .describe_sso import list_account_assignments
|
|
3
|
-
from colorama import Fore
|
|
4
1
|
import logging
|
|
5
2
|
|
|
3
|
+
from colorama import Fore
|
|
4
|
+
from rich.progress import track
|
|
5
|
+
|
|
6
|
+
from .describe_sso import client, list_account_assignments
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def list_groups_pag(identity_store_id, region, next_token: str = None):
|
|
10
|
+
identity_client = client("identitystore", region_name=region)
|
|
6
11
|
|
|
7
|
-
|
|
8
|
-
next_token: str = None):
|
|
9
|
-
paginator = client.get_paginator('list_groups')
|
|
12
|
+
paginator = identity_client.get_paginator("list_groups")
|
|
10
13
|
response_iterator = paginator.paginate(
|
|
11
14
|
IdentityStoreId=identity_store_id,
|
|
12
|
-
PaginationConfig={
|
|
13
|
-
'MaxItems': 1000,
|
|
14
|
-
'PageSize': 4,
|
|
15
|
-
'StartingToken': next_token
|
|
16
|
-
}
|
|
15
|
+
PaginationConfig={"MaxItems": 1000, "PageSize": 4, "StartingToken": next_token},
|
|
17
16
|
)
|
|
18
17
|
response = response_iterator.build_full_result()
|
|
19
18
|
logging.info(response_iterator.build_full_result())
|
|
20
19
|
return response["Groups"]
|
|
21
20
|
|
|
22
21
|
|
|
23
|
-
def list_groups(identity_store_id,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
def list_groups(identity_store_id, region):
|
|
23
|
+
identity_client = client("identitystore", region_name=region)
|
|
24
|
+
|
|
25
|
+
groups = identity_client.list_groups(
|
|
26
|
+
IdentityStoreId=identity_store_id, MaxResults=20
|
|
27
27
|
)
|
|
28
28
|
|
|
29
29
|
logging.info(groups)
|
|
@@ -32,7 +32,11 @@ def list_groups(identity_store_id, client=boto3.client('identitystore', region_n
|
|
|
32
32
|
|
|
33
33
|
if len(groups["Groups"]) >= 20:
|
|
34
34
|
logging.info("Paginating ...")
|
|
35
|
-
ad_groups = list_groups_pag(
|
|
35
|
+
ad_groups = list_groups_pag(
|
|
36
|
+
identity_store_id=identity_store_id,
|
|
37
|
+
region=region,
|
|
38
|
+
next_token=groups["NextToken"],
|
|
39
|
+
)
|
|
36
40
|
for ad in ad_groups:
|
|
37
41
|
l_groups.append(ad)
|
|
38
42
|
logging.info(f"You have {len(l_groups)} Groups")
|
|
@@ -40,33 +44,117 @@ def list_groups(identity_store_id, client=boto3.client('identitystore', region_n
|
|
|
40
44
|
return l_groups
|
|
41
45
|
|
|
42
46
|
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
# define pagination list user function
|
|
48
|
+
def list_users_pag(identity_store_id, region, next_token: str = None):
|
|
49
|
+
identity_client = client("identitystore", region_name=region)
|
|
50
|
+
paginator = identity_client.get_paginator("list_users")
|
|
51
|
+
response_iterator = paginator.paginate(
|
|
45
52
|
IdentityStoreId=identity_store_id,
|
|
53
|
+
PaginationConfig={"MaxItems": 1000, "PageSize": 4, "StartingToken": next_token},
|
|
54
|
+
)
|
|
55
|
+
return response_iterator["Users"]
|
|
46
56
|
|
|
57
|
+
|
|
58
|
+
def list_users(identity_store_id, region):
|
|
59
|
+
identity_client = client("identitystore", region_name=region)
|
|
60
|
+
|
|
61
|
+
response = identity_client.list_users(
|
|
62
|
+
IdentityStoreId=identity_store_id,
|
|
47
63
|
)
|
|
64
|
+
# create pagination option
|
|
65
|
+
users = response["Users"]
|
|
66
|
+
if len(users) >= 20:
|
|
67
|
+
logging.info("Paginating ...")
|
|
68
|
+
ad_users = list_users_pag(
|
|
69
|
+
identity_store_id=identity_store_id,
|
|
70
|
+
region=region,
|
|
71
|
+
next_token=response["NextToken"],
|
|
72
|
+
)
|
|
73
|
+
for ad in ad_users:
|
|
74
|
+
users.append(ad)
|
|
75
|
+
logging.info(f"You have {len(users)} Users")
|
|
48
76
|
|
|
49
|
-
return
|
|
77
|
+
return users
|
|
50
78
|
|
|
51
79
|
|
|
52
|
-
def
|
|
80
|
+
def get_members_pag(identity_store_id, region, next_token: str = None):
|
|
81
|
+
identity_client = client("identitystore", region_name=region)
|
|
82
|
+
|
|
83
|
+
paginator = identity_client.get_paginator("list_group_memberships")
|
|
84
|
+
response_iterator = paginator.paginate(
|
|
85
|
+
IdentityStoreId=identity_store_id,
|
|
86
|
+
PaginationConfig={"MaxItems": 1000, "PageSize": 4, "StartingToken": next_token},
|
|
87
|
+
)
|
|
88
|
+
response = response_iterator.build_full_result()
|
|
89
|
+
logging.info(response_iterator.build_full_result())
|
|
90
|
+
return response["GroupMemberships"]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_members(identity_store_id, groups, region):
|
|
94
|
+
l_client = client("identitystore", region_name=region)
|
|
53
95
|
group_members = []
|
|
54
|
-
for g in
|
|
55
|
-
|
|
96
|
+
for g, y in zip(
|
|
97
|
+
groups, track(range(len(groups) - 1), description="Getting groups members...")
|
|
98
|
+
):
|
|
99
|
+
response = l_client.list_group_memberships(
|
|
56
100
|
IdentityStoreId=identity_store_id,
|
|
57
101
|
GroupId=g["GroupId"],
|
|
58
|
-
|
|
102
|
+
MaxResults=20,
|
|
59
103
|
)
|
|
104
|
+
members = response["GroupMemberships"]
|
|
105
|
+
logging.info(members)
|
|
106
|
+
|
|
107
|
+
logging.info(len(members))
|
|
108
|
+
|
|
109
|
+
if len(members) >= 20:
|
|
110
|
+
logging.info("Paginating ...")
|
|
111
|
+
ad_members = get_members_pag(
|
|
112
|
+
identity_store_id=identity_store_id,
|
|
113
|
+
region=region,
|
|
114
|
+
next_token=response["NextToken"],
|
|
115
|
+
)
|
|
116
|
+
for ad in ad_members:
|
|
117
|
+
members.append(ad)
|
|
118
|
+
logging.info(f"You have {len(ad_members)} Members")
|
|
119
|
+
|
|
60
120
|
group_members.append(
|
|
61
|
-
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
121
|
+
{
|
|
122
|
+
"group_id": g["GroupId"],
|
|
123
|
+
"group_name": g["DisplayName"],
|
|
124
|
+
"members": members,
|
|
125
|
+
}
|
|
65
126
|
)
|
|
66
127
|
|
|
67
128
|
return group_members
|
|
68
129
|
|
|
69
130
|
|
|
131
|
+
def list_group_memberships(identitystore_client, group_name, pagination=True):
|
|
132
|
+
"""
|
|
133
|
+
Lists memberships for a group in an AWS SSO identity store.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
identitystore_client (client): Boto3 SSO identity store client
|
|
137
|
+
group_name (str): Name of the group to list memberships for
|
|
138
|
+
pagination (bool): Whether to enable result pagination (default: True)
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
list: List of member objects
|
|
142
|
+
"""
|
|
143
|
+
|
|
144
|
+
params = {"GroupName": group_name}
|
|
145
|
+
members = []
|
|
146
|
+
|
|
147
|
+
if pagination:
|
|
148
|
+
paginator = identitystore_client.get_paginator("list_group_memberships")
|
|
149
|
+
for page in paginator.paginate(**params):
|
|
150
|
+
members.extend(page["Members"])
|
|
151
|
+
else:
|
|
152
|
+
response = identitystore_client.list_group_memberships(**params)
|
|
153
|
+
members.extend(response["Members"])
|
|
154
|
+
|
|
155
|
+
return members
|
|
156
|
+
|
|
157
|
+
|
|
70
158
|
def complete_group_members(group_members, users_list):
|
|
71
159
|
for m in group_members:
|
|
72
160
|
for u in m["members"]:
|
|
@@ -85,7 +173,7 @@ def l_groups_to_d_groups(l_groups: list = None):
|
|
|
85
173
|
"""
|
|
86
174
|
names = []
|
|
87
175
|
for a in l_groups:
|
|
88
|
-
names.append(a[
|
|
176
|
+
names.append(a["group_name"])
|
|
89
177
|
logging.info(names)
|
|
90
178
|
|
|
91
179
|
d_user_groups = dict(zip(names, l_groups))
|
|
@@ -93,36 +181,72 @@ def l_groups_to_d_groups(l_groups: list = None):
|
|
|
93
181
|
return d_user_groups
|
|
94
182
|
|
|
95
183
|
|
|
96
|
-
def extend_account_assignments(accounts_list, permissions_sets, store_arn,
|
|
97
|
-
client_sso=boto3.client('identitystore', region_name="us-east-2")):
|
|
184
|
+
def extend_account_assignments(accounts_list, permissions_sets, store_arn, region):
|
|
98
185
|
account_assignments = []
|
|
99
|
-
for p in
|
|
100
|
-
|
|
186
|
+
for p, y in zip(
|
|
187
|
+
permissions_sets,
|
|
188
|
+
track(
|
|
189
|
+
range(len(permissions_sets) - 1),
|
|
190
|
+
description="Getting account assignments ...",
|
|
191
|
+
),
|
|
192
|
+
):
|
|
101
193
|
for ac in accounts_list:
|
|
102
|
-
assign = list_account_assignments(
|
|
103
|
-
|
|
194
|
+
assign = list_account_assignments(
|
|
195
|
+
instance_arn=store_arn,
|
|
196
|
+
account_id=ac["Id"],
|
|
197
|
+
region=region,
|
|
198
|
+
permission_set_arn=p,
|
|
199
|
+
)
|
|
104
200
|
logging.debug(f"AccountAssignments {assign}")
|
|
105
201
|
for a in assign:
|
|
106
202
|
account_assignments.append(a)
|
|
107
203
|
return account_assignments
|
|
108
204
|
|
|
109
205
|
|
|
110
|
-
def add_users_and_groups_assign(
|
|
111
|
-
|
|
112
|
-
|
|
206
|
+
def add_users_and_groups_assign(
|
|
207
|
+
account_assignments_list,
|
|
208
|
+
user_and_group_list,
|
|
209
|
+
user_list,
|
|
210
|
+
list_permissions_set_arn_name,
|
|
211
|
+
):
|
|
212
|
+
for a, y in zip(
|
|
213
|
+
account_assignments_list,
|
|
214
|
+
track(
|
|
215
|
+
range(len(account_assignments_list) - 1),
|
|
216
|
+
description="Create user and groups assignments ...",
|
|
217
|
+
),
|
|
218
|
+
):
|
|
113
219
|
for g in user_and_group_list:
|
|
114
|
-
if
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
220
|
+
if (
|
|
221
|
+
len(a) > 0
|
|
222
|
+
and a["PrincipalType"] == "GROUP"
|
|
223
|
+
and g["group_id"] == a["PrincipalId"]
|
|
224
|
+
):
|
|
225
|
+
logging.info(
|
|
226
|
+
Fore.YELLOW
|
|
227
|
+
+ f"Account {a['AccountId']} assign to {a['PrincipalType']} {g['group_name']} with permission set {list_permissions_set_arn_name[a['PermissionSetArn']]} or {a['PermissionSetArn']}"
|
|
228
|
+
+ Fore.RESET
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
a["GroupName"] = g["group_name"]
|
|
232
|
+
a["PermissionSetName"] = list_permissions_set_arn_name[
|
|
233
|
+
a["PermissionSetArn"]
|
|
234
|
+
]
|
|
120
235
|
for u in user_list:
|
|
121
|
-
if
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
236
|
+
if (
|
|
237
|
+
len(a) > 0
|
|
238
|
+
and a["PrincipalType"] == "USER"
|
|
239
|
+
and u["UserId"] == a["PrincipalId"]
|
|
240
|
+
):
|
|
241
|
+
logging.info(
|
|
242
|
+
Fore.YELLOW
|
|
243
|
+
+ f"Account {a['AccountId']} assign to {a['PrincipalType']} {u['UserName']} with permission set {a['PermissionSetArn']} or {list_permissions_set_arn_name[a['PermissionSetArn']]}"
|
|
244
|
+
+ Fore.RESET
|
|
245
|
+
)
|
|
246
|
+
a["UserName"] = u["UserName"]
|
|
247
|
+
a["PermissionSetName"] = list_permissions_set_arn_name[
|
|
248
|
+
a["PermissionSetArn"]
|
|
249
|
+
]
|
|
126
250
|
logging.debug(f"Account Assignments --> {account_assignments_list}")
|
|
127
251
|
return account_assignments_list
|
|
128
252
|
|
|
@@ -132,7 +256,6 @@ def order_accounts_assignments_list(accounts_dict, account_assignments):
|
|
|
132
256
|
for ac in accounts_dict:
|
|
133
257
|
final_account_assignments[ac["Name"]] = []
|
|
134
258
|
for a in account_assignments:
|
|
135
|
-
|
|
136
259
|
if ac["Id"] == a["AccountId"]:
|
|
137
260
|
final_account_assignments[ac["Name"]].append(a)
|
|
138
261
|
|
src/aws/describe_organization.py
CHANGED
|
@@ -1,36 +1,79 @@
|
|
|
1
|
-
import boto3
|
|
2
1
|
import logging
|
|
3
2
|
|
|
3
|
+
from colorama import Fore
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
from .describe_sso import client
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def describe_organization(region):
|
|
9
|
+
"""
|
|
10
|
+
Describe the organization.
|
|
11
|
+
|
|
12
|
+
:param region: AWS Region
|
|
13
|
+
:return:
|
|
14
|
+
"""
|
|
15
|
+
print(f"{Fore.GREEN}❇️ Describe Organization {Fore.RESET}")
|
|
16
|
+
org_client = client("organizations", region_name=region)
|
|
17
|
+
organization = org_client.describe_organization()
|
|
7
18
|
organization = organization["Organization"]
|
|
8
19
|
return organization
|
|
9
20
|
|
|
10
21
|
|
|
11
|
-
def list_roots(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
22
|
+
def list_roots(region):
|
|
23
|
+
"""
|
|
24
|
+
List the roots
|
|
25
|
+
:param region: AWS Region
|
|
26
|
+
:return:
|
|
27
|
+
"""
|
|
28
|
+
org_client = client("organizations", region_name=region)
|
|
29
|
+
roots = org_client.list_roots()
|
|
15
30
|
return roots["Roots"]
|
|
16
31
|
|
|
17
32
|
|
|
18
|
-
def
|
|
19
|
-
|
|
33
|
+
# def list organizational units pagination
|
|
34
|
+
def list_organizational_units_pag(parent_id, region, next_token=None):
|
|
35
|
+
org_client = client("organizations", region_name=region)
|
|
36
|
+
paginator = org_client.get_paginator("list_organizational_units_for_parent")
|
|
37
|
+
response_iterator = paginator.paginate(
|
|
20
38
|
ParentId=parent_id,
|
|
39
|
+
PaginationConfig={"MaxItems": 1000, "PageSize": 4, "StartingToken": next_token},
|
|
40
|
+
)
|
|
41
|
+
return response_iterator["OrganizationalUnits"]
|
|
42
|
+
|
|
21
43
|
|
|
44
|
+
def list_organizational_units(parent_id, region, org_units=None):
|
|
45
|
+
org_client = client("organizations", region_name=region)
|
|
46
|
+
if org_units is None:
|
|
47
|
+
org_units = []
|
|
48
|
+
ous = org_client.list_organizational_units_for_parent(
|
|
49
|
+
ParentId=parent_id,
|
|
50
|
+
MaxResults=20,
|
|
22
51
|
)
|
|
52
|
+
ous = ous["OrganizationalUnits"]
|
|
53
|
+
|
|
54
|
+
if len(ous) >= 20:
|
|
55
|
+
logging.info("Paginating ...")
|
|
56
|
+
add_ous = list_organizational_units_pag(
|
|
57
|
+
parent_id, region, next_token=ous["NextToken"]
|
|
58
|
+
)
|
|
59
|
+
for ou in add_ous:
|
|
60
|
+
ous.append(ou)
|
|
61
|
+
logging.debug(add_ous)
|
|
23
62
|
|
|
24
|
-
for o in ous
|
|
63
|
+
for o in ous:
|
|
25
64
|
org_units.append(o)
|
|
26
|
-
logging.debug(
|
|
65
|
+
logging.debug(
|
|
66
|
+
f"The parent Id is: {parent_id}",
|
|
67
|
+
)
|
|
27
68
|
logging.debug(ous)
|
|
28
69
|
if len(ous) > 0:
|
|
29
70
|
for ou in ous["OrganizationalUnits"]:
|
|
30
71
|
logging.debug(ou)
|
|
31
72
|
if "Id" in ou.keys():
|
|
32
|
-
logging.debug("Search nested for:
|
|
33
|
-
ous_next = list_organizational_units(
|
|
73
|
+
logging.debug(f"Search nested for: {ou['Name']}")
|
|
74
|
+
ous_next = list_organizational_units(
|
|
75
|
+
ou["Id"], region=region, org_units=org_units
|
|
76
|
+
)
|
|
34
77
|
logging.debug(ous_next)
|
|
35
78
|
if len(ous_next) > 0:
|
|
36
79
|
logging.debug("Find Netsted")
|
|
@@ -38,50 +81,61 @@ def list_organizational_units(parent_id, client=boto3.client('organizations'), o
|
|
|
38
81
|
return org_units
|
|
39
82
|
|
|
40
83
|
|
|
41
|
-
def list_parents(child_id,
|
|
42
|
-
|
|
43
|
-
|
|
84
|
+
def list_parents(child_id, region):
|
|
85
|
+
"""
|
|
86
|
+
List the parents of a child.
|
|
44
87
|
|
|
88
|
+
:param child_id:
|
|
89
|
+
:param region:
|
|
90
|
+
:return:
|
|
91
|
+
"""
|
|
92
|
+
org_client = client("organizations", region_name=region)
|
|
93
|
+
response = org_client.list_parents(
|
|
94
|
+
ChildId=child_id,
|
|
45
95
|
)
|
|
46
96
|
return response["Parents"]
|
|
47
97
|
|
|
48
98
|
|
|
49
|
-
def index_ous(list_ous,
|
|
99
|
+
def index_ous(list_ous, region):
|
|
100
|
+
"""
|
|
101
|
+
Index the parents of a child.
|
|
102
|
+
|
|
103
|
+
:param list_ous:
|
|
104
|
+
:param region:
|
|
105
|
+
:return list_ous:
|
|
106
|
+
|
|
107
|
+
"""
|
|
108
|
+
org_client = client("organizations", region_name=region)
|
|
50
109
|
for ou in list_ous:
|
|
51
110
|
if "Id" in ou.keys() and len(ou) > 0:
|
|
52
|
-
response =
|
|
111
|
+
response = org_client.list_parents(
|
|
53
112
|
ChildId=ou["Id"],
|
|
54
|
-
|
|
55
113
|
)
|
|
56
114
|
logging.debug(response["Parents"])
|
|
57
115
|
ou["Parents"] = response["Parents"]
|
|
58
116
|
return list_ous
|
|
59
117
|
|
|
60
118
|
|
|
61
|
-
def list_accounts_pag(
|
|
62
|
-
|
|
119
|
+
def list_accounts_pag(region, next_token: str = None):
|
|
120
|
+
org_client = client("organizations", region_name=region)
|
|
121
|
+
paginator = org_client.get_paginator("list_accounts")
|
|
63
122
|
response_iterator = paginator.paginate(
|
|
64
|
-
PaginationConfig={
|
|
65
|
-
'MaxItems': 1000,
|
|
66
|
-
'PageSize': 20,
|
|
67
|
-
'StartingToken': next_token
|
|
68
|
-
}
|
|
123
|
+
PaginationConfig={"MaxItems": 1000, "PageSize": 20, "StartingToken": next_token}
|
|
69
124
|
)
|
|
70
125
|
response = response_iterator.build_full_result()
|
|
71
126
|
logging.info(response_iterator.build_full_result())
|
|
72
127
|
return response["Accounts"]
|
|
73
128
|
|
|
74
129
|
|
|
75
|
-
def list_accounts(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
)
|
|
130
|
+
def list_accounts(region):
|
|
131
|
+
org_client = client("organizations", region_name=region)
|
|
132
|
+
accounts = org_client.list_accounts()
|
|
79
133
|
logging.info(accounts)
|
|
80
134
|
l_account = accounts["Accounts"]
|
|
81
135
|
logging.info(len(accounts["Accounts"]))
|
|
82
136
|
if len(accounts["Accounts"]) >= 20:
|
|
83
137
|
logging.info("Paginating ...")
|
|
84
|
-
ad_accounts = list_accounts_pag(
|
|
138
|
+
ad_accounts = list_accounts_pag(region=region, next_token=accounts["NextToken"])
|
|
85
139
|
for ad in ad_accounts:
|
|
86
140
|
l_account.append(ad)
|
|
87
141
|
logging.info(f"You Organizations have {len(l_account)} Accounts")
|
|
@@ -89,14 +143,15 @@ def list_accounts(client=boto3.client('organizations')):
|
|
|
89
143
|
return l_account
|
|
90
144
|
|
|
91
145
|
|
|
92
|
-
def index_accounts(list_account):
|
|
146
|
+
def index_accounts(list_account, region):
|
|
93
147
|
accounts = []
|
|
94
|
-
|
|
148
|
+
org_client = client("organizations", region_name=region)
|
|
95
149
|
for a in list_account:
|
|
96
|
-
response =
|
|
150
|
+
response = org_client.list_parents(
|
|
97
151
|
ChildId=a["Id"],
|
|
98
|
-
|
|
99
152
|
)
|
|
100
153
|
|
|
101
|
-
accounts.append(
|
|
154
|
+
accounts.append(
|
|
155
|
+
{"account": a["Id"], "name": a["Name"], "parents": response["Parents"]}
|
|
156
|
+
)
|
|
102
157
|
return accounts
|