gcp-platforms-auto 0.8.2__py3-none-any.whl → 0.8.4__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.
- gcp_platforms_auto/__init__.py +3 -1
- gcp_platforms_auto/iam.py +176 -70
- {gcp_platforms_auto-0.8.2.dist-info → gcp_platforms_auto-0.8.4.dist-info}/METADATA +1 -2
- gcp_platforms_auto-0.8.4.dist-info/RECORD +9 -0
- gcp_platforms_auto-0.8.2.dist-info/RECORD +0 -9
- {gcp_platforms_auto-0.8.2.dist-info → gcp_platforms_auto-0.8.4.dist-info}/WHEEL +0 -0
- {gcp_platforms_auto-0.8.2.dist-info → gcp_platforms_auto-0.8.4.dist-info}/top_level.txt +0 -0
gcp_platforms_auto/__init__.py
CHANGED
gcp_platforms_auto/iam.py
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"""IAM access management utilities for GCP."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
+
import os
|
|
4
5
|
import google.cloud.logging
|
|
5
|
-
from google.cloud import asset_v1
|
|
6
|
+
from google.cloud import asset_v1
|
|
6
7
|
from typing import Optional
|
|
7
8
|
|
|
8
9
|
# Initialize Google Cloud Logging
|
|
@@ -14,49 +15,106 @@ logger = logging.getLogger("uvicorn")
|
|
|
14
15
|
logger.setLevel(logging.INFO)
|
|
15
16
|
|
|
16
17
|
|
|
17
|
-
def
|
|
18
|
+
def check_user_has_role_in_project(
|
|
19
|
+
project_id: str,
|
|
20
|
+
user_email: str,
|
|
21
|
+
organization_id: str,
|
|
22
|
+
role: str = "roles/owner",
|
|
23
|
+
expand_groups: bool = True
|
|
24
|
+
) -> bool:
|
|
18
25
|
"""
|
|
19
|
-
|
|
20
|
-
Automatically detects if the email is a service account or user.
|
|
26
|
+
Check if a user has a specific role in a GCP project.
|
|
21
27
|
|
|
22
28
|
Args:
|
|
23
|
-
|
|
29
|
+
project_id: GCP project ID (e.g., 'sky-starfi-mam-res-gcpro-1')
|
|
30
|
+
user_email: Email of the user to check (e.g., 'oshasha10@gcporg.com')
|
|
31
|
+
organization_id: GCP organization ID (e.g., '111111111111')
|
|
32
|
+
role: Role to check (e.g., 'roles/owner', 'roles/editor')
|
|
33
|
+
expand_groups: Whether to expand group memberships (default: True)
|
|
24
34
|
|
|
25
35
|
Returns:
|
|
26
|
-
|
|
36
|
+
bool: True if the user has the role in the project, False otherwise
|
|
37
|
+
|
|
38
|
+
Example:
|
|
39
|
+
>>> has_access = check_user_has_role_in_project(
|
|
40
|
+
... project_id='sky-starfi-mam-res-gcpro-1',
|
|
41
|
+
... user_email='oshasha10@gcporg.com',
|
|
42
|
+
... organization_id='111111111111',
|
|
43
|
+
... role='roles/owner'
|
|
44
|
+
... )
|
|
27
45
|
"""
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
46
|
+
client = asset_v1.AssetServiceClient()
|
|
47
|
+
|
|
48
|
+
# Construct the full resource name
|
|
49
|
+
scope = f"organizations/{organization_id}"
|
|
50
|
+
full_resource_name = f"//cloudresourcemanager.googleapis.com/projects/{project_id}"
|
|
51
|
+
identity = f"user:{user_email}"
|
|
52
|
+
|
|
53
|
+
# Build the request
|
|
54
|
+
request = asset_v1.AnalyzeIamPolicyRequest(
|
|
55
|
+
analysis_query=asset_v1.IamPolicyAnalysisQuery(
|
|
56
|
+
scope=scope,
|
|
57
|
+
resource_selector=asset_v1.IamPolicyAnalysisQuery.ResourceSelector(
|
|
58
|
+
full_resource_name=full_resource_name
|
|
59
|
+
),
|
|
60
|
+
identity_selector=asset_v1.IamPolicyAnalysisQuery.IdentitySelector(
|
|
61
|
+
identity=identity
|
|
62
|
+
),
|
|
63
|
+
access_selector=asset_v1.IamPolicyAnalysisQuery.AccessSelector(
|
|
64
|
+
roles=[role]
|
|
65
|
+
),
|
|
66
|
+
options=asset_v1.IamPolicyAnalysisQuery.Options(
|
|
67
|
+
expand_groups=expand_groups,
|
|
68
|
+
expand_roles=True,
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
try:
|
|
74
|
+
# Execute the analysis
|
|
75
|
+
logger.info(f"Checking if user {user_email} has role {role} in project {project_id}")
|
|
76
|
+
response = client.analyze_iam_policy(request=request)
|
|
77
|
+
|
|
78
|
+
# Check if any results were returned
|
|
79
|
+
if response.main_analysis and response.main_analysis.analysis_results:
|
|
80
|
+
logger.info(f"User {user_email} has role {role} in project {project_id}")
|
|
81
|
+
return True
|
|
82
|
+
|
|
83
|
+
logger.info(f"User {user_email} does not have role {role} in project {project_id}")
|
|
84
|
+
return False
|
|
85
|
+
|
|
86
|
+
except Exception as e:
|
|
87
|
+
logger.exception(f"Error analyzing IAM policy: {e}")
|
|
88
|
+
raise
|
|
32
89
|
|
|
33
90
|
|
|
34
|
-
def
|
|
91
|
+
def check_service_account_has_role_in_project(
|
|
35
92
|
project_id: str,
|
|
36
|
-
|
|
93
|
+
service_account_email: str,
|
|
37
94
|
organization_id: str,
|
|
38
95
|
role: str = "roles/owner",
|
|
39
96
|
expand_groups: bool = True
|
|
40
97
|
) -> bool:
|
|
41
98
|
"""
|
|
42
|
-
Check if a
|
|
99
|
+
Check if a service account has a specific role in a GCP project.
|
|
43
100
|
|
|
44
101
|
Args:
|
|
45
|
-
user_email: Email of the user or service account to check
|
|
46
|
-
(e.g., 'oshasha10@gcporg.com' or 'my-sa@project.iam.gserviceaccount.com')
|
|
47
|
-
role: Role to check (e.g., 'roles/owner', 'roles/editor')
|
|
48
102
|
project_id: GCP project ID (e.g., 'sky-starfi-mam-res-gcpro-1')
|
|
103
|
+
service_account_email: Email of the service account to check
|
|
104
|
+
(e.g., 'my-sa@project.iam.gserviceaccount.com')
|
|
49
105
|
organization_id: GCP organization ID (e.g., '111111111111')
|
|
106
|
+
role: Role to check (e.g., 'roles/owner', 'roles/editor')
|
|
50
107
|
expand_groups: Whether to expand group memberships (default: True)
|
|
51
108
|
|
|
52
109
|
Returns:
|
|
53
|
-
bool: True if the
|
|
110
|
+
bool: True if the service account has the role in the project, False otherwise
|
|
54
111
|
|
|
55
112
|
Example:
|
|
56
|
-
>>> has_access =
|
|
57
|
-
... user_email='oshasha10@gcporg.com',
|
|
58
|
-
... role='roles/owner',
|
|
113
|
+
>>> has_access = check_service_account_has_role_in_project(
|
|
59
114
|
... project_id='sky-starfi-mam-res-gcpro-1',
|
|
115
|
+
... service_account_email='my-sa@project.iam.gserviceaccount.com',
|
|
116
|
+
... organization_id='111111111111',
|
|
117
|
+
... role='roles/owner'
|
|
60
118
|
... )
|
|
61
119
|
"""
|
|
62
120
|
client = asset_v1.AssetServiceClient()
|
|
@@ -64,7 +122,7 @@ def check_user_has_role_in_project(
|
|
|
64
122
|
# Construct the full resource name
|
|
65
123
|
scope = f"organizations/{organization_id}"
|
|
66
124
|
full_resource_name = f"//cloudresourcemanager.googleapis.com/projects/{project_id}"
|
|
67
|
-
identity =
|
|
125
|
+
identity = f"serviceAccount:{service_account_email}"
|
|
68
126
|
|
|
69
127
|
# Build the request
|
|
70
128
|
request = asset_v1.AnalyzeIamPolicyRequest(
|
|
@@ -82,23 +140,21 @@ def check_user_has_role_in_project(
|
|
|
82
140
|
options=asset_v1.IamPolicyAnalysisQuery.Options(
|
|
83
141
|
expand_groups=expand_groups,
|
|
84
142
|
expand_roles=True,
|
|
85
|
-
# expand_resources=True
|
|
86
143
|
)
|
|
87
144
|
)
|
|
88
145
|
)
|
|
89
146
|
|
|
90
147
|
try:
|
|
91
148
|
# Execute the analysis
|
|
92
|
-
logger.info(f"Checking if {
|
|
149
|
+
logger.info(f"Checking if service account {service_account_email} has role {role} in project {project_id}")
|
|
93
150
|
response = client.analyze_iam_policy(request=request)
|
|
94
151
|
|
|
95
152
|
# Check if any results were returned
|
|
96
|
-
# If the user has the role, there will be analysis results
|
|
97
153
|
if response.main_analysis and response.main_analysis.analysis_results:
|
|
98
|
-
logger.info(f"{
|
|
154
|
+
logger.info(f"Service account {service_account_email} has role {role} in project {project_id}")
|
|
99
155
|
return True
|
|
100
156
|
|
|
101
|
-
logger.info(f"{
|
|
157
|
+
logger.info(f"Service account {service_account_email} does not have role {role} in project {project_id}")
|
|
102
158
|
return False
|
|
103
159
|
|
|
104
160
|
except Exception as e:
|
|
@@ -106,47 +162,112 @@ def check_user_has_role_in_project(
|
|
|
106
162
|
raise
|
|
107
163
|
|
|
108
164
|
|
|
109
|
-
def
|
|
165
|
+
def check_group_has_role_in_project(
|
|
166
|
+
project_id: str,
|
|
167
|
+
group_email: str,
|
|
168
|
+
organization_id: str,
|
|
169
|
+
role: str = "roles/owner",
|
|
170
|
+
expand_groups: bool = True
|
|
171
|
+
) -> bool:
|
|
110
172
|
"""
|
|
111
|
-
|
|
173
|
+
Check if a group has a specific role in a GCP project.
|
|
112
174
|
|
|
113
175
|
Args:
|
|
114
|
-
|
|
115
|
-
|
|
176
|
+
project_id: GCP project ID (e.g., 'sky-starfi-mam-res-gcpro-1')
|
|
177
|
+
group_email: Email of the group to check (e.g., 'dev-team@gcporg.com')
|
|
178
|
+
organization_id: GCP organization ID (e.g., '111111111111')
|
|
179
|
+
role: Role to check (e.g., 'roles/owner', 'roles/editor')
|
|
180
|
+
expand_groups: Whether to expand group memberships (default: True)
|
|
116
181
|
|
|
117
182
|
Returns:
|
|
118
|
-
|
|
183
|
+
bool: True if the group has the role in the project, False otherwise
|
|
184
|
+
|
|
185
|
+
Example:
|
|
186
|
+
>>> has_access = check_group_has_role_in_project(
|
|
187
|
+
... project_id='sky-starfi-mam-res-gcpro-1',
|
|
188
|
+
... group_email='dev-team@gcporg.com',
|
|
189
|
+
... organization_id='111111111111',
|
|
190
|
+
... role='roles/owner'
|
|
191
|
+
... )
|
|
119
192
|
"""
|
|
120
|
-
|
|
193
|
+
client = asset_v1.AssetServiceClient()
|
|
194
|
+
|
|
195
|
+
# Construct the full resource name
|
|
196
|
+
scope = f"organizations/{organization_id}"
|
|
197
|
+
full_resource_name = f"//cloudresourcemanager.googleapis.com/projects/{project_id}"
|
|
198
|
+
identity = f"group:{group_email}"
|
|
199
|
+
|
|
200
|
+
# Build the request
|
|
201
|
+
request = asset_v1.AnalyzeIamPolicyRequest(
|
|
202
|
+
analysis_query=asset_v1.IamPolicyAnalysisQuery(
|
|
203
|
+
scope=scope,
|
|
204
|
+
resource_selector=asset_v1.IamPolicyAnalysisQuery.ResourceSelector(
|
|
205
|
+
full_resource_name=full_resource_name
|
|
206
|
+
),
|
|
207
|
+
identity_selector=asset_v1.IamPolicyAnalysisQuery.IdentitySelector(
|
|
208
|
+
identity=identity
|
|
209
|
+
),
|
|
210
|
+
access_selector=asset_v1.IamPolicyAnalysisQuery.AccessSelector(
|
|
211
|
+
roles=[role]
|
|
212
|
+
),
|
|
213
|
+
options=asset_v1.IamPolicyAnalysisQuery.Options(
|
|
214
|
+
expand_groups=expand_groups,
|
|
215
|
+
expand_roles=True,
|
|
216
|
+
)
|
|
217
|
+
)
|
|
218
|
+
)
|
|
121
219
|
|
|
122
220
|
try:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
logger.info(f"
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
221
|
+
# Execute the analysis
|
|
222
|
+
logger.info(f"Checking if group {group_email} has role {role} in project {project_id}")
|
|
223
|
+
response = client.analyze_iam_policy(request=request)
|
|
224
|
+
|
|
225
|
+
# Check if any results were returned
|
|
226
|
+
if response.main_analysis and response.main_analysis.analysis_results:
|
|
227
|
+
logger.info(f"Group {group_email} has role {role} in project {project_id}")
|
|
228
|
+
return True
|
|
229
|
+
|
|
230
|
+
logger.info(f"Group {group_email} does not have role {role} in project {project_id}")
|
|
231
|
+
return False
|
|
232
|
+
|
|
135
233
|
except Exception as e:
|
|
136
|
-
logger.
|
|
137
|
-
|
|
138
|
-
|
|
234
|
+
logger.exception(f"Error analyzing IAM policy: {e}")
|
|
235
|
+
raise
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def _get_all_service_projects(base_paths, prefix):
|
|
239
|
+
service_projects = []
|
|
240
|
+
|
|
241
|
+
for path in base_paths:
|
|
242
|
+
logger.info(f"[INFO] Searching for projects under: {path}")
|
|
243
|
+
|
|
244
|
+
for root, _, _ in os.walk(path):
|
|
245
|
+
if root == path:
|
|
246
|
+
continue
|
|
247
|
+
|
|
248
|
+
for _, _, projects in os.walk(root):
|
|
249
|
+
for project in projects:
|
|
250
|
+
if not project.endswith(".yaml"):
|
|
251
|
+
continue
|
|
252
|
+
if project.startswith(prefix):
|
|
253
|
+
service_projects.append(project.split('.')[0])
|
|
254
|
+
else:
|
|
255
|
+
service_projects.append(f"{prefix}-{project.split('.')[0]}")
|
|
256
|
+
|
|
257
|
+
return list(set(service_projects))
|
|
139
258
|
|
|
140
259
|
|
|
141
260
|
def get_projects_with_role(
|
|
142
261
|
user_email: str,
|
|
143
262
|
organization_id: str,
|
|
144
263
|
role: str = "roles/owner",
|
|
145
|
-
expand_groups: bool = True
|
|
264
|
+
expand_groups: bool = True,
|
|
265
|
+
project_prefix: Optional[str] = None,
|
|
266
|
+
projects_base_paths: Optional[list] = []
|
|
146
267
|
) -> list:
|
|
147
268
|
"""
|
|
148
269
|
Get all projects where a user or service account has a specific role.
|
|
149
|
-
Searches
|
|
270
|
+
Searches for all service projects in the organization.
|
|
150
271
|
|
|
151
272
|
Args:
|
|
152
273
|
user_email: Email of the user or service account to check
|
|
@@ -168,27 +289,12 @@ def get_projects_with_role(
|
|
|
168
289
|
logger.info(f"Fetching all projects in organization {organization_id} (including folders)")
|
|
169
290
|
|
|
170
291
|
try:
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
all_folders = _get_all_folders_recursive(org_parent, folders_client)
|
|
178
|
-
logger.info(f"Found {len(all_folders)} folder(s) in organization")
|
|
179
|
-
|
|
180
|
-
# Create list of all parents to search (organization + all folders)
|
|
181
|
-
parents_to_search = [org_parent] + all_folders
|
|
182
|
-
|
|
183
|
-
# Collect all projects from all parents
|
|
184
|
-
all_projects = []
|
|
185
|
-
for parent in parents_to_search:
|
|
186
|
-
request = resourcemanager_v3.ListProjectsRequest(parent=parent)
|
|
187
|
-
projects = projects_client.list_projects(request=request)
|
|
188
|
-
for project in projects:
|
|
189
|
-
all_projects.append(project.project_id)
|
|
190
|
-
|
|
191
|
-
logger.info(f"Found {len(all_projects)} total project(s) across organization and folders")
|
|
292
|
+
all_projects = _get_all_service_projects(
|
|
293
|
+
base_paths=projects_base_paths,
|
|
294
|
+
prefix=project_prefix
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
logger.info(f"Found {len(all_projects)} total service project(s) across organization {organization_id}")
|
|
192
298
|
|
|
193
299
|
# Filter projects where user has the specified role
|
|
194
300
|
matching_projects = []
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gcp_platforms_auto
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.4
|
|
4
4
|
Summary: A brief description of your package
|
|
5
5
|
Author-email: ofir4858 <ofirshasha10@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -13,7 +13,6 @@ Requires-Dist: requests
|
|
|
13
13
|
Requires-Dist: pyjwt
|
|
14
14
|
Requires-Dist: google-cloud-logging
|
|
15
15
|
Requires-Dist: google-cloud-asset
|
|
16
|
-
Requires-Dist: google-cloud-resource-manager
|
|
17
16
|
Requires-Dist: gitpython
|
|
18
17
|
Requires-Dist: sqlalchemy
|
|
19
18
|
Requires-Dist: pg8000
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
gcp_platforms_auto/__init__.py,sha256=pKouDuMclA8r93k5H9TjGbxNsFwqIYfymjO-owuGGws,526
|
|
2
|
+
gcp_platforms_auto/db.py,sha256=jE5nwmqVHcxT4m6-meUgUz4V4DM8M_sMmeTpvKr2Z2Y,8768
|
|
3
|
+
gcp_platforms_auto/git.py,sha256=NnLDfRzzrzbm9yekepc-qgu8ejYmjNxQ4VDlW46gG2o,5508
|
|
4
|
+
gcp_platforms_auto/iam.py,sha256=wnMZ_jl2YM5dLY8LqtPfEyh_0Osqs1ypsxakJGmwHVw,11614
|
|
5
|
+
gcp_platforms_auto/models.py,sha256=mVg8NKV25kqdTuazqenAp7Ay03N5D8GIh3F_TWP0zyI,853
|
|
6
|
+
gcp_platforms_auto-0.8.4.dist-info/METADATA,sha256=UU0EYfRtyhRgQW_1867j05FBs16hAAan5w_UWKQn15w,600
|
|
7
|
+
gcp_platforms_auto-0.8.4.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
8
|
+
gcp_platforms_auto-0.8.4.dist-info/top_level.txt,sha256=4q-ofPMmvBaTnIbAzs-Wp_OwheAVxxmJ1fW9vl3-kyE,19
|
|
9
|
+
gcp_platforms_auto-0.8.4.dist-info/RECORD,,
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
gcp_platforms_auto/__init__.py,sha256=MhphRLBFhpZSik83woVgJi3NpyGjBRZ4RyOcXu8dqAk,443
|
|
2
|
-
gcp_platforms_auto/db.py,sha256=jE5nwmqVHcxT4m6-meUgUz4V4DM8M_sMmeTpvKr2Z2Y,8768
|
|
3
|
-
gcp_platforms_auto/git.py,sha256=NnLDfRzzrzbm9yekepc-qgu8ejYmjNxQ4VDlW46gG2o,5508
|
|
4
|
-
gcp_platforms_auto/iam.py,sha256=BFf4LitUXzHrDETZHO_sf2zw6XGrR9a_Vg-TBIqE77k,7671
|
|
5
|
-
gcp_platforms_auto/models.py,sha256=mVg8NKV25kqdTuazqenAp7Ay03N5D8GIh3F_TWP0zyI,853
|
|
6
|
-
gcp_platforms_auto-0.8.2.dist-info/METADATA,sha256=_Kn33l2ax-3uMpd3x96La8euXPO3wqv0xKpD25KUT1s,645
|
|
7
|
-
gcp_platforms_auto-0.8.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
8
|
-
gcp_platforms_auto-0.8.2.dist-info/top_level.txt,sha256=4q-ofPMmvBaTnIbAzs-Wp_OwheAVxxmJ1fW9vl3-kyE,19
|
|
9
|
-
gcp_platforms_auto-0.8.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|