reverse-diagrams 0.2.6__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.6.dist-info → reverse_diagrams-1.0.0.dist-info}/METADATA +36 -23
- reverse_diagrams-1.0.0.dist-info/RECORD +20 -0
- reverse_diagrams-1.0.0.dist-info/licenses/LICENSE +13 -0
- src/aws/describe_identity_store.py +131 -66
- 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 +75 -31
- src/dgms/graph_template.py +4 -4
- src/export_report/export_csv.py +3 -2
- src/reports/__init__.py +0 -0
- src/reports/save_results.py +24 -0
- src/reverse_diagrams.py +325 -169
- src/version.py +2 -0
- reverse_diagrams-0.2.6.dist-info/RECORD +0 -17
- reverse_diagrams-0.2.6.dist-info/licenses/LICENSE +0 -21
- {reverse_diagrams-0.2.6.dist-info → reverse_diagrams-1.0.0.dist-info}/WHEEL +0 -0
- {reverse_diagrams-0.2.6.dist-info → reverse_diagrams-1.0.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,41 +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 - 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
|
|
5
5
|
Project-URL: Homepage, https://github.com/velez94/reverse_diagrams
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/velez94/reverse_diagrams/issues
|
|
7
7
|
Author-email: Alejandro Velez <avelez@labvel.io>
|
|
8
|
-
License:
|
|
8
|
+
License: Copyright [2024] [Alejandro Velez]
|
|
9
9
|
|
|
10
|
-
|
|
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
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
-
in the Software without restriction, including without limitation the rights
|
|
15
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
-
furnished to do so, subject to the following conditions:
|
|
14
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
-
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.
|
|
29
21
|
License-File: LICENSE
|
|
30
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
31
22
|
Classifier: Operating System :: OS Independent
|
|
32
23
|
Classifier: Programming Language :: Python :: 3
|
|
33
24
|
Requires-Python: >=3.8
|
|
34
25
|
Requires-Dist: boto3>=1.26.44
|
|
35
26
|
Requires-Dist: colorama>=0.4.4
|
|
36
|
-
Requires-Dist: diagrams>=0.
|
|
27
|
+
Requires-Dist: diagrams>=0.23.4
|
|
37
28
|
Requires-Dist: emoji>=2.2.0
|
|
38
|
-
Requires-Dist:
|
|
29
|
+
Requires-Dist: rich>=13.7.0
|
|
39
30
|
Description-Content-Type: text/markdown
|
|
40
31
|
|
|
41
32
|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
|
@@ -156,3 +147,25 @@ reverse_diagrams -c aws -p my-profile -i -r us-east-2
|
|
|
156
147
|
reverse_diagrams -c aws -p my-profile -o -i -r us-east-2
|
|
157
148
|
```
|
|
158
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,39 +44,62 @@ 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 get_members_pag(identity_store_id,
|
|
53
|
-
|
|
54
|
-
|
|
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")
|
|
55
84
|
response_iterator = paginator.paginate(
|
|
56
85
|
IdentityStoreId=identity_store_id,
|
|
57
|
-
PaginationConfig={
|
|
58
|
-
'MaxItems': 1000,
|
|
59
|
-
'PageSize': 4,
|
|
60
|
-
'StartingToken': next_token
|
|
61
|
-
}
|
|
86
|
+
PaginationConfig={"MaxItems": 1000, "PageSize": 4, "StartingToken": next_token},
|
|
62
87
|
)
|
|
63
88
|
response = response_iterator.build_full_result()
|
|
64
89
|
logging.info(response_iterator.build_full_result())
|
|
65
90
|
return response["GroupMemberships"]
|
|
66
91
|
|
|
67
92
|
|
|
68
|
-
def get_members(identity_store_id, groups,
|
|
93
|
+
def get_members(identity_store_id, groups, region):
|
|
94
|
+
l_client = client("identitystore", region_name=region)
|
|
69
95
|
group_members = []
|
|
70
|
-
for g in
|
|
71
|
-
|
|
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(
|
|
72
100
|
IdentityStoreId=identity_store_id,
|
|
73
101
|
GroupId=g["GroupId"],
|
|
74
102
|
MaxResults=20,
|
|
75
|
-
|
|
76
103
|
)
|
|
77
104
|
members = response["GroupMemberships"]
|
|
78
105
|
logging.info(members)
|
|
@@ -81,18 +108,21 @@ def get_members(identity_store_id, groups, client=boto3.client('identitystore',
|
|
|
81
108
|
|
|
82
109
|
if len(members) >= 20:
|
|
83
110
|
logging.info("Paginating ...")
|
|
84
|
-
ad_members = get_members_pag(
|
|
85
|
-
|
|
111
|
+
ad_members = get_members_pag(
|
|
112
|
+
identity_store_id=identity_store_id,
|
|
113
|
+
region=region,
|
|
114
|
+
next_token=response["NextToken"],
|
|
115
|
+
)
|
|
86
116
|
for ad in ad_members:
|
|
87
117
|
members.append(ad)
|
|
88
|
-
|
|
89
|
-
print(f"You have {len(ad_members)} Members")
|
|
118
|
+
logging.info(f"You have {len(ad_members)} Members")
|
|
90
119
|
|
|
91
120
|
group_members.append(
|
|
92
|
-
{
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
121
|
+
{
|
|
122
|
+
"group_id": g["GroupId"],
|
|
123
|
+
"group_name": g["DisplayName"],
|
|
124
|
+
"members": members,
|
|
125
|
+
}
|
|
96
126
|
)
|
|
97
127
|
|
|
98
128
|
return group_members
|
|
@@ -103,7 +133,7 @@ def list_group_memberships(identitystore_client, group_name, pagination=True):
|
|
|
103
133
|
Lists memberships for a group in an AWS SSO identity store.
|
|
104
134
|
|
|
105
135
|
Args:
|
|
106
|
-
identitystore_client (
|
|
136
|
+
identitystore_client (client): Boto3 SSO identity store client
|
|
107
137
|
group_name (str): Name of the group to list memberships for
|
|
108
138
|
pagination (bool): Whether to enable result pagination (default: True)
|
|
109
139
|
|
|
@@ -111,16 +141,16 @@ def list_group_memberships(identitystore_client, group_name, pagination=True):
|
|
|
111
141
|
list: List of member objects
|
|
112
142
|
"""
|
|
113
143
|
|
|
114
|
-
params = {
|
|
144
|
+
params = {"GroupName": group_name}
|
|
115
145
|
members = []
|
|
116
146
|
|
|
117
147
|
if pagination:
|
|
118
|
-
paginator = identitystore_client.get_paginator(
|
|
148
|
+
paginator = identitystore_client.get_paginator("list_group_memberships")
|
|
119
149
|
for page in paginator.paginate(**params):
|
|
120
|
-
members.extend(page[
|
|
150
|
+
members.extend(page["Members"])
|
|
121
151
|
else:
|
|
122
152
|
response = identitystore_client.list_group_memberships(**params)
|
|
123
|
-
members.extend(response[
|
|
153
|
+
members.extend(response["Members"])
|
|
124
154
|
|
|
125
155
|
return members
|
|
126
156
|
|
|
@@ -143,7 +173,7 @@ def l_groups_to_d_groups(l_groups: list = None):
|
|
|
143
173
|
"""
|
|
144
174
|
names = []
|
|
145
175
|
for a in l_groups:
|
|
146
|
-
names.append(a[
|
|
176
|
+
names.append(a["group_name"])
|
|
147
177
|
logging.info(names)
|
|
148
178
|
|
|
149
179
|
d_user_groups = dict(zip(names, l_groups))
|
|
@@ -151,36 +181,72 @@ def l_groups_to_d_groups(l_groups: list = None):
|
|
|
151
181
|
return d_user_groups
|
|
152
182
|
|
|
153
183
|
|
|
154
|
-
def extend_account_assignments(accounts_list, permissions_sets, store_arn,
|
|
155
|
-
client_sso=boto3.client('identitystore', region_name="us-east-2")):
|
|
184
|
+
def extend_account_assignments(accounts_list, permissions_sets, store_arn, region):
|
|
156
185
|
account_assignments = []
|
|
157
|
-
for p in
|
|
158
|
-
|
|
186
|
+
for p, y in zip(
|
|
187
|
+
permissions_sets,
|
|
188
|
+
track(
|
|
189
|
+
range(len(permissions_sets) - 1),
|
|
190
|
+
description="Getting account assignments ...",
|
|
191
|
+
),
|
|
192
|
+
):
|
|
159
193
|
for ac in accounts_list:
|
|
160
|
-
assign = list_account_assignments(
|
|
161
|
-
|
|
194
|
+
assign = list_account_assignments(
|
|
195
|
+
instance_arn=store_arn,
|
|
196
|
+
account_id=ac["Id"],
|
|
197
|
+
region=region,
|
|
198
|
+
permission_set_arn=p,
|
|
199
|
+
)
|
|
162
200
|
logging.debug(f"AccountAssignments {assign}")
|
|
163
201
|
for a in assign:
|
|
164
202
|
account_assignments.append(a)
|
|
165
203
|
return account_assignments
|
|
166
204
|
|
|
167
205
|
|
|
168
|
-
def add_users_and_groups_assign(
|
|
169
|
-
|
|
170
|
-
|
|
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
|
+
):
|
|
171
219
|
for g in user_and_group_list:
|
|
172
|
-
if
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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
|
+
]
|
|
178
235
|
for u in user_list:
|
|
179
|
-
if
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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
|
+
]
|
|
184
250
|
logging.debug(f"Account Assignments --> {account_assignments_list}")
|
|
185
251
|
return account_assignments_list
|
|
186
252
|
|
|
@@ -190,7 +256,6 @@ def order_accounts_assignments_list(accounts_dict, account_assignments):
|
|
|
190
256
|
for ac in accounts_dict:
|
|
191
257
|
final_account_assignments[ac["Name"]] = []
|
|
192
258
|
for a in account_assignments:
|
|
193
|
-
|
|
194
259
|
if ac["Id"] == a["AccountId"]:
|
|
195
260
|
final_account_assignments[ac["Name"]].append(a)
|
|
196
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
|