1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-31 03:09:44 +02:00

fix(kubernetes): Namespace access permission changes role bindings not created [R8S-366] (#807)

Co-authored-by: andres-portainer <andres-portainer@users.noreply.github.com>
Co-authored-by: Malcolm Lockyer <segfault88@users.noreply.github.com>
This commit is contained in:
Cara Ryan 2025-06-25 09:24:18 +12:00 committed by GitHub
parent ee6d33365e
commit 7fd5b96130
2 changed files with 17 additions and 9 deletions

View file

@ -75,7 +75,7 @@ func (handler *Handler) listRegistries(tx dataservices.DataStoreTx, r *http.Requ
return nil, httperror.InternalServerError("Unable to retrieve registries from the database", err) return nil, httperror.InternalServerError("Unable to retrieve registries from the database", err)
} }
registries, handleError := handler.filterRegistriesByAccess(r, registries, endpoint, user, securityContext.UserMemberships) registries, handleError := handler.filterRegistriesByAccess(tx, r, registries, endpoint, user, securityContext.UserMemberships)
if handleError != nil { if handleError != nil {
return nil, handleError return nil, handleError
} }
@ -87,15 +87,15 @@ func (handler *Handler) listRegistries(tx dataservices.DataStoreTx, r *http.Requ
return registries, err return registries, err
} }
func (handler *Handler) filterRegistriesByAccess(r *http.Request, registries []portainer.Registry, endpoint *portainer.Endpoint, user *portainer.User, memberships []portainer.TeamMembership) ([]portainer.Registry, *httperror.HandlerError) { func (handler *Handler) filterRegistriesByAccess(tx dataservices.DataStoreTx, r *http.Request, registries []portainer.Registry, endpoint *portainer.Endpoint, user *portainer.User, memberships []portainer.TeamMembership) ([]portainer.Registry, *httperror.HandlerError) {
if !endpointutils.IsKubernetesEndpoint(endpoint) { if !endpointutils.IsKubernetesEndpoint(endpoint) {
return security.FilterRegistries(registries, user, memberships, endpoint.ID), nil return security.FilterRegistries(registries, user, memberships, endpoint.ID), nil
} }
return handler.filterKubernetesEndpointRegistries(r, registries, endpoint, user, memberships) return handler.filterKubernetesEndpointRegistries(tx, r, registries, endpoint, user, memberships)
} }
func (handler *Handler) filterKubernetesEndpointRegistries(r *http.Request, registries []portainer.Registry, endpoint *portainer.Endpoint, user *portainer.User, memberships []portainer.TeamMembership) ([]portainer.Registry, *httperror.HandlerError) { func (handler *Handler) filterKubernetesEndpointRegistries(tx dataservices.DataStoreTx, r *http.Request, registries []portainer.Registry, endpoint *portainer.Endpoint, user *portainer.User, memberships []portainer.TeamMembership) ([]portainer.Registry, *httperror.HandlerError) {
namespaceParam, _ := request.RetrieveQueryParameter(r, "namespace", true) namespaceParam, _ := request.RetrieveQueryParameter(r, "namespace", true)
isAdmin, err := security.IsAdmin(r) isAdmin, err := security.IsAdmin(r)
if err != nil { if err != nil {
@ -116,7 +116,7 @@ func (handler *Handler) filterKubernetesEndpointRegistries(r *http.Request, regi
return registries, nil return registries, nil
} }
return handler.filterKubernetesRegistriesByUserRole(r, registries, endpoint, user) return handler.filterKubernetesRegistriesByUserRole(tx, r, registries, endpoint, user)
} }
func (handler *Handler) isNamespaceAuthorized(endpoint *portainer.Endpoint, namespace string, userId portainer.UserID, memberships []portainer.TeamMembership, isAdmin bool) (bool, error) { func (handler *Handler) isNamespaceAuthorized(endpoint *portainer.Endpoint, namespace string, userId portainer.UserID, memberships []portainer.TeamMembership, isAdmin bool) (bool, error) {
@ -169,7 +169,7 @@ func registryAccessPoliciesContainsNamespace(registryAccess portainer.RegistryAc
return false return false
} }
func (handler *Handler) filterKubernetesRegistriesByUserRole(r *http.Request, registries []portainer.Registry, endpoint *portainer.Endpoint, user *portainer.User) ([]portainer.Registry, *httperror.HandlerError) { func (handler *Handler) filterKubernetesRegistriesByUserRole(tx dataservices.DataStoreTx, r *http.Request, registries []portainer.Registry, endpoint *portainer.Endpoint, user *portainer.User) ([]portainer.Registry, *httperror.HandlerError) {
err := handler.requestBouncer.AuthorizedEndpointOperation(r, endpoint) err := handler.requestBouncer.AuthorizedEndpointOperation(r, endpoint)
if errors.Is(err, security.ErrAuthorizationRequired) { if errors.Is(err, security.ErrAuthorizationRequired) {
return nil, httperror.Forbidden("User is not authorized", err) return nil, httperror.Forbidden("User is not authorized", err)
@ -178,7 +178,7 @@ func (handler *Handler) filterKubernetesRegistriesByUserRole(r *http.Request, re
return nil, httperror.InternalServerError("Unable to retrieve info from request context", err) return nil, httperror.InternalServerError("Unable to retrieve info from request context", err)
} }
userNamespaces, err := handler.userNamespaces(endpoint, user) userNamespaces, err := handler.userNamespaces(tx, endpoint, user)
if err != nil { if err != nil {
return nil, httperror.InternalServerError("unable to retrieve user namespaces", err) return nil, httperror.InternalServerError("unable to retrieve user namespaces", err)
} }
@ -186,7 +186,7 @@ func (handler *Handler) filterKubernetesRegistriesByUserRole(r *http.Request, re
return filterRegistriesByNamespaces(registries, endpoint.ID, userNamespaces), nil return filterRegistriesByNamespaces(registries, endpoint.ID, userNamespaces), nil
} }
func (handler *Handler) userNamespaces(endpoint *portainer.Endpoint, user *portainer.User) ([]string, error) { func (handler *Handler) userNamespaces(tx dataservices.DataStoreTx, endpoint *portainer.Endpoint, user *portainer.User) ([]string, error) {
kcl, err := handler.K8sClientFactory.GetPrivilegedKubeClient(endpoint) kcl, err := handler.K8sClientFactory.GetPrivilegedKubeClient(endpoint)
if err != nil { if err != nil {
return nil, err return nil, err
@ -197,7 +197,7 @@ func (handler *Handler) userNamespaces(endpoint *portainer.Endpoint, user *porta
return nil, err return nil, err
} }
userMemberships, err := handler.DataStore.TeamMembership().TeamMembershipsByUserID(user.ID) userMemberships, err := tx.TeamMembership().TeamMembershipsByUserID(user.ID)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -87,6 +87,14 @@ func (factory *ClientFactory) ClearClientCache() {
// Remove the cached kube client so a new one can be created // Remove the cached kube client so a new one can be created
func (factory *ClientFactory) RemoveKubeClient(endpointID portainer.EndpointID) { func (factory *ClientFactory) RemoveKubeClient(endpointID portainer.EndpointID) {
factory.endpointProxyClients.Delete(strconv.Itoa(int(endpointID))) factory.endpointProxyClients.Delete(strconv.Itoa(int(endpointID)))
endpointPrefix := strconv.Itoa(int(endpointID)) + "."
for key := range factory.endpointProxyClients.Items() {
if strings.HasPrefix(key, endpointPrefix) {
factory.endpointProxyClients.Delete(key)
}
}
} }
// GetPrivilegedKubeClient checks if an existing client is already registered for the environment(endpoint) and returns it if one is found. // GetPrivilegedKubeClient checks if an existing client is already registered for the environment(endpoint) and returns it if one is found.