Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: node k8s permissions #6123

Merged
merged 15 commits into from
Nov 28, 2024
63 changes: 55 additions & 8 deletions api/cluster/ClusterRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/devtron-labs/devtron/pkg/cluster/rbac"
"net/http"
"strconv"
"strings"
"time"

"github.com/devtron-labs/devtron/pkg/auth/authorisation/casbin"
Expand Down Expand Up @@ -377,7 +378,7 @@ func (impl ClusterRestHandlerImpl) FindNoteByClusterId(w http.ResponseWriter, r
}
// RBAC enforcer applying
token := r.Header.Get("token")
authenticated, err := impl.clusterRbacService.CheckAuthorization(bean.ClusterName, bean.ClusterId, token, userId, false)
authenticated, err := impl.clusterRbacService.CheckAuthorization(bean.ClusterName, bean.ClusterId, token, userId, true)
if err != nil {
impl.logger.Errorw("error in checking rbac for cluster", "err", err, "clusterId", bean.ClusterId)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
Expand Down Expand Up @@ -477,7 +478,8 @@ func (impl ClusterRestHandlerImpl) UpdateClusterDescription(w http.ResponseWrite
return
}
// RBAC enforcer applying
if ok := impl.enforcer.Enforce(token, casbin.ResourceCluster, casbin.ActionUpdate, clusterDescription.ClusterName); !ok {
authenticated := impl.clusterRbacService.CheckAuthorisationForAllK8sPermissions(token, clusterDescription.ClusterName, casbin.ActionUpdate)
if !authenticated {
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
return
}
Expand Down Expand Up @@ -521,7 +523,8 @@ func (impl ClusterRestHandlerImpl) UpdateClusterNote(w http.ResponseWriter, r *h
return
}
// RBAC enforcer applying
if ok := impl.enforcer.Enforce(token, casbin.ResourceCluster, casbin.ActionUpdate, clusterDescription.ClusterName); !ok {
authenticated := impl.clusterRbacService.CheckAuthorisationForAllK8sPermissions(token, clusterDescription.ClusterName, casbin.ActionUpdate)
if !authenticated {
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
return
}
Expand Down Expand Up @@ -622,17 +625,61 @@ func (impl ClusterRestHandlerImpl) DeleteCluster(w http.ResponseWriter, r *http.

func (impl ClusterRestHandlerImpl) GetAllClusterNamespaces(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("token")
userId, err := impl.userService.GetLoggedInUser(r)
if userId == 0 || err != nil {
impl.logger.Errorw("err, GetAllClusterNamespaces", "error", err, "userId", userId)
common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized)
return
}
clusterNamespaces := impl.clusterService.GetAllClusterNamespaces()

// RBAC enforcer applying
for clusterName, _ := range clusterNamespaces {
if ok := impl.enforcer.Enforce(token, casbin.ResourceCluster, casbin.ActionGet, clusterName); !ok {
delete(clusterNamespaces, clusterName)
}
filteredClusterNamespaces, err := impl.HandleRbacForClusterNamespace(userId, token, clusterNamespaces)
if err != nil {
impl.logger.Errorw("error in GetAllClusterNamespaces", "err", err)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
//RBAC enforcer Ends

common.WriteJsonResp(w, nil, clusterNamespaces, http.StatusOK)
common.WriteJsonResp(w, nil, filteredClusterNamespaces, http.StatusOK)
}

func (impl ClusterRestHandlerImpl) HandleRbacForClusterNamespace(userId int32, token string, clusterNamespaces map[string][]string) (map[string][]string, error) {
filteredClusterNamespaces := make(map[string][]string)
if ok := impl.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionGet, "*"); ok {
return clusterNamespaces, nil
}
roles, err := impl.clusterService.FetchRolesFromGroup(userId)
if err != nil {
impl.logger.Errorw("error on fetching user roles for cluster list", "err", err)
return nil, err
}

clusterAndNameSpaceVsAllowedMap := make(map[string]bool, len(roles))
clusterNameVsAllAllowedMap := make(map[string]bool, len(roles))
for _, role := range roles {
clusterAndNameSpaceVsAllowedMap[strings.ToLower(role.Cluster+"_"+role.Namespace)] = true
if role.Namespace == "" {
clusterNameVsAllAllowedMap[role.Cluster] = true
} else {
clusterNameVsAllAllowedMap[role.Cluster] = false
}
}

for clusterName, allNamespaces := range clusterNamespaces {
if val, exist := clusterNameVsAllAllowedMap[clusterName]; val {
filteredClusterNamespaces[clusterName] = allNamespaces
} else if exist {
for _, namespace := range allNamespaces {
if val2, exist2 := clusterAndNameSpaceVsAllowedMap[strings.ToLower(clusterName+"_"+namespace)]; exist2 && val2 {
filteredClusterNamespaces[clusterName] = append(filteredClusterNamespaces[clusterName], namespace)
}
}
}
}
return filteredClusterNamespaces, nil

}

func (impl ClusterRestHandlerImpl) GetClusterNamespaces(w http.ResponseWriter, r *http.Request) {
Expand Down
3 changes: 2 additions & 1 deletion api/k8s/application/k8sApplicationRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,8 @@ func (handler *K8sApplicationRestHandlerImpl) GetTerminalSession(w http.Response

} else if resourceRequestBean.AppIdentifier == nil && resourceRequestBean.DevtronAppIdentifier == nil && resourceRequestBean.ExternalFluxAppIdentifier == nil && resourceRequestBean.ExternalArgoApplicationName == "" && resourceRequestBean.ClusterId > 0 {
//RBAC enforcer applying for Resource Browser
if !handler.handleRbac(r, w, *resourceRequestBean, token, casbin.ActionUpdate) {
resource, object := handler.enforcerUtil.GetRbacResourceAndObjectForNodeByClusterId(resourceRequestBean.ClusterId, bean2.ALL)
if !(handler.enforcer.Enforce(token, resource, casbin.ActionUpdate, object) || handler.handleRbac(r, w, *resourceRequestBean, token, casbin.ActionUpdate)) {
return
}
//RBAC enforcer Ends
Expand Down
56 changes: 38 additions & 18 deletions api/k8s/capacity/k8sCapacityRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ func (handler *K8sCapacityRestHandlerImpl) GetClusterDetail(w http.ResponseWrite
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
authenticated, err := handler.clusterRbacService.CheckAuthorization(cluster.ClusterName, cluster.Id, token, userId, false)
authenticated, err := handler.clusterRbacService.CheckAuthorization(cluster.ClusterName, cluster.Id, token, userId, true)
if err != nil {
handler.logger.Errorw("error in checking rbac for cluster", "err", err, "clusterId", clusterId)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
Expand Down Expand Up @@ -219,12 +219,7 @@ func (handler *K8sCapacityRestHandlerImpl) GetNodeList(w http.ResponseWriter, r
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
authenticated, err := handler.clusterRbacService.CheckAuthorization(cluster.ClusterName, cluster.Id, token, userId, false)
if err != nil {
handler.logger.Errorw("error in checking rbac for cluster", "err", err, "clusterId", clusterId)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
authenticated := handler.clusterRbacService.CheckAuthorisationForNode(token, cluster.ClusterName, "", casbin.ActionGet)
if !authenticated {
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
return
Expand Down Expand Up @@ -265,12 +260,7 @@ func (handler *K8sCapacityRestHandlerImpl) GetNodeDetail(w http.ResponseWriter,
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
authenticated, err := handler.clusterRbacService.CheckAuthorization(cluster.ClusterName, cluster.Id, token, userId, false)
if err != nil {
handler.logger.Errorw("error in checking rbac for cluster", "err", err, "clusterId", clusterId)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
authenticated := handler.clusterRbacService.CheckAuthorisationForNode(token, cluster.ClusterName, name, casbin.ActionGet)
if !authenticated {
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
return
Expand Down Expand Up @@ -300,7 +290,13 @@ func (handler *K8sCapacityRestHandlerImpl) UpdateNodeManifest(w http.ResponseWri
}
// RBAC enforcer applying
token := r.Header.Get("token")
if ok := handler.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionUpdate, "*"); !ok {
authenticated, err := handler.clusterRbacService.CheckAuthorisationForNodeWithClusterId(token, manifestUpdateReq.ClusterId, manifestUpdateReq.Name, casbin.ActionUpdate)
if err != nil {
handler.logger.Errorw("error in checking rbac for cluster", "err", err, "clusterId", manifestUpdateReq.ClusterId)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
if !authenticated {
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
return
}
Expand Down Expand Up @@ -329,7 +325,13 @@ func (handler *K8sCapacityRestHandlerImpl) DeleteNode(w http.ResponseWriter, r *
}
// RBAC enforcer applying
token := r.Header.Get("token")
if ok := handler.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionDelete, "*"); !ok {
authenticated, err := handler.clusterRbacService.CheckAuthorisationForNodeWithClusterId(token, nodeDelReq.ClusterId, nodeDelReq.Name, casbin.ActionDelete)
if err != nil {
handler.logger.Errorw("error in checking rbac for cluster", "err", err, "clusterId", nodeDelReq.ClusterId)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
if !authenticated {
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
return
}
Expand Down Expand Up @@ -367,7 +369,13 @@ func (handler *K8sCapacityRestHandlerImpl) CordonOrUnCordonNode(w http.ResponseW
}
// RBAC enforcer applying
token := r.Header.Get("token")
if ok := handler.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionUpdate, "*"); !ok {
authenticated, err := handler.clusterRbacService.CheckAuthorisationForNodeWithClusterId(token, nodeCordonReq.ClusterId, nodeCordonReq.Name, casbin.ActionUpdate)
if err != nil {
handler.logger.Errorw("error in checking rbac for cluster", "err", err, "clusterId", nodeCordonReq.ClusterId)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
if !authenticated {
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
return
}
Expand Down Expand Up @@ -396,7 +404,13 @@ func (handler *K8sCapacityRestHandlerImpl) DrainNode(w http.ResponseWriter, r *h
}
// RBAC enforcer applying
token := r.Header.Get("token")
if ok := handler.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionUpdate, "*"); !ok {
authenticated, err := handler.clusterRbacService.CheckAuthorisationForNodeWithClusterId(token, nodeDrainReq.ClusterId, nodeDrainReq.Name, casbin.ActionUpdate)
if err != nil {
handler.logger.Errorw("error in checking rbac for cluster", "err", err, "clusterId", nodeDrainReq.ClusterId)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
if !authenticated {
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
return
}
Expand Down Expand Up @@ -425,7 +439,13 @@ func (handler *K8sCapacityRestHandlerImpl) EditNodeTaints(w http.ResponseWriter,
}
// RBAC enforcer applying
token := r.Header.Get("token")
if ok := handler.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionUpdate, "*"); !ok {
authenticated, err := handler.clusterRbacService.CheckAuthorisationForNodeWithClusterId(token, nodeTaintReq.ClusterId, nodeTaintReq.Name, casbin.ActionUpdate)
if err != nil {
handler.logger.Errorw("error in checking rbac for cluster", "err", err, "clusterId", nodeTaintReq.ClusterId)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
if !authenticated {
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
return
}
Expand Down
Loading
Loading