Skip to content

Commit 6ee5041

Browse files
committed
Users namespace identification based on role bindings
Signed-off-by: jyejare <[email protected]>
1 parent 2b8e653 commit 6ee5041

File tree

1 file changed

+65
-3
lines changed

1 file changed

+65
-3
lines changed

sdk/python/feast/permissions/auth/kubernetes_token_parser.py

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,12 @@ def _extract_groups_and_namespaces_from_token(
144144

145145
# Extract namespaces from the user info
146146
if response.status.user:
147-
# For service accounts, the namespace is typically in the username
148-
# For regular users, we might need to extract from groups or other fields
149147
username = getattr(response.status.user, "username", "") or ""
148+
150149
if ":" in username and username.startswith(
151150
"system:serviceaccount:"
152151
):
153-
# Extract namespace from service account username
152+
# Service account logic - extract namespace from username
154153
parts = username.split(":")
155154
if len(parts) >= 4:
156155
service_account_namespace = parts[
@@ -163,6 +162,15 @@ def _extract_groups_and_namespaces_from_token(
163162
service_account_namespace
164163
)
165164
groups.extend(namespace_groups)
165+
else:
166+
# Regular user logic - extract namespaces from dashboard-permissions RoleBindings
167+
user_namespaces = self._extract_user_data_science_projects(
168+
username
169+
)
170+
namespaces.extend(user_namespaces)
171+
logger.info(
172+
f"Found {len(user_namespaces)} data science projects for user {username}: {user_namespaces}"
173+
)
166174

167175
# Also check if there are namespace-specific groups
168176
for group in groups:
@@ -181,6 +189,10 @@ def _extract_groups_and_namespaces_from_token(
181189
except Exception as e:
182190
logger.error(f"Failed to perform Token Access Review: {e}")
183191
# We dont need to extract groups and namespaces from jwt decoding, not ideal for kubernetes auth
192+
193+
# Remove duplicates
194+
groups = sorted(list(set(groups)))
195+
namespaces = sorted(list(set(namespaces)))
184196
return groups, namespaces
185197

186198
def _extract_namespace_access_groups(self, namespace: str) -> list[str]:
@@ -232,6 +244,56 @@ def _extract_namespace_access_groups(self, namespace: str) -> list[str]:
232244

233245
return groups
234246

247+
def _extract_user_data_science_projects(self, username: str) -> list[str]:
248+
"""
249+
Extract data science project namespaces where a user has been added via dashboard-permissions RoleBindings.
250+
251+
This method queries all RoleBindings where the user is a subject and filters for
252+
'dashboard-permissions-*' RoleBindings, which indicate the user has been added to that data science project.
253+
254+
Args:
255+
username: The username to search for in RoleBindings
256+
257+
Returns:
258+
list[str]: List of namespace names where the user has dashboard permissions
259+
"""
260+
user_namespaces = []
261+
try:
262+
# Query all RoleBindings where the user is a subject
263+
# This is much more efficient than scanning all namespaces
264+
all_role_bindings = self.rbac_v1.list_role_binding_for_all_namespaces()
265+
266+
for rb in all_role_bindings.items:
267+
# Check if this is a dashboard-permissions RoleBinding
268+
if (
269+
rb.metadata.name.startswith("dashboard-permissions-")
270+
and rb.metadata.labels
271+
and rb.metadata.labels.get("opendatahub.io/dashboard") == "true"
272+
):
273+
# Check if the user is a subject in this RoleBinding
274+
for subject in rb.subjects or []:
275+
if subject.kind == "User" and subject.name == username:
276+
namespace_name = rb.metadata.namespace
277+
user_namespaces.append(namespace_name)
278+
logger.debug(
279+
f"Found user {username} in dashboard-permissions RoleBinding "
280+
f"{rb.metadata.name} in namespace {namespace_name}"
281+
)
282+
break # Found the user in this RoleBinding, no need to check other subjects
283+
284+
# Remove duplicates and sort
285+
user_namespaces = sorted(list(set(user_namespaces)))
286+
logger.info(
287+
f"User {username} has dashboard permissions in {len(user_namespaces)} namespaces: {user_namespaces}"
288+
)
289+
290+
except Exception as e:
291+
logger.error(
292+
f"Failed to extract user data science projects for {username}: {e}"
293+
)
294+
295+
return user_namespaces
296+
235297
def _cluster_role_binding_grants_namespace_access(
236298
self, cluster_role_binding, namespace: str
237299
) -> bool:

0 commit comments

Comments
 (0)