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

fix: Rbac modification for Resource Browser Apis #3766

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions api/k8s/application/k8sApplicationRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,13 @@ func (handler *K8sApplicationRestHandlerImpl) GetResource(w http.ResponseWriter,
// RBAC enforcer applying for Helm App
rbacObject, rbacObject2 = handler.enforcerUtilHelm.GetHelmObjectByClusterIdNamespaceAndAppName(request.AppIdentifier.ClusterId, request.AppIdentifier.Namespace, request.AppIdentifier.ReleaseName)
ok := handler.enforcer.Enforce(token, casbin.ResourceHelmApp, casbin.ActionGet, rbacObject) || handler.enforcer.Enforce(token, casbin.ResourceHelmApp, casbin.ActionGet, rbacObject2)
if !ok {
ok, err = handler.k8sCommonService.CheckRbacForCluster(request.ClusterId, token)
if err != nil {
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
}
if !ok {
common.WriteJsonResp(w, errors2.New("unauthorized"), nil, http.StatusForbidden)
return
Expand All @@ -181,6 +188,13 @@ func (handler *K8sApplicationRestHandlerImpl) GetResource(w http.ResponseWriter,
// RBAC enforcer applying for Devtron App
envObject = handler.enforcerUtil.GetEnvRBACNameByAppId(request.DevtronAppIdentifier.AppId, request.DevtronAppIdentifier.EnvId)
hasReadAccessForEnv := handler.enforcer.Enforce(token, casbin.ResourceEnvironment, casbin.ActionGet, envObject)
if !hasReadAccessForEnv {
hasReadAccessForEnv, err = handler.k8sCommonService.CheckRbacForCluster(request.ClusterId, token)
if err != nil {
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
}
if !hasReadAccessForEnv {
common.WriteJsonResp(w, errors2.New("unauthorized"), nil, http.StatusForbidden)
return
Expand Down Expand Up @@ -543,6 +557,13 @@ func (handler *K8sApplicationRestHandlerImpl) ListEvents(w http.ResponseWriter,
// RBAC enforcer applying for Helm App
rbacObject, rbacObject2 := handler.enforcerUtilHelm.GetHelmObjectByClusterIdNamespaceAndAppName(request.AppIdentifier.ClusterId, request.AppIdentifier.Namespace, request.AppIdentifier.ReleaseName)
ok := handler.enforcer.Enforce(token, casbin.ResourceHelmApp, casbin.ActionGet, rbacObject) || handler.enforcer.Enforce(token, casbin.ResourceHelmApp, casbin.ActionGet, rbacObject2)
if !ok {
ok, err = handler.k8sCommonService.CheckRbacForCluster(request.ClusterId, token)
if err != nil {
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
}
if !ok {
common.WriteJsonResp(w, errors2.New("unauthorized"), nil, http.StatusForbidden)
return
Expand All @@ -567,6 +588,13 @@ func (handler *K8sApplicationRestHandlerImpl) ListEvents(w http.ResponseWriter,
//RBAC enforcer applying for Devtron App
envObject := handler.enforcerUtil.GetEnvRBACNameByAppId(request.DevtronAppIdentifier.AppId, request.DevtronAppIdentifier.EnvId)
hasAccessForEnv := handler.enforcer.Enforce(token, casbin.ResourceEnvironment, casbin.ActionGet, envObject)
if !hasAccessForEnv {
hasAccessForEnv, err = handler.k8sCommonService.CheckRbacForCluster(request.ClusterId, token)
if err != nil {
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
}
if !hasAccessForEnv {
common.WriteJsonResp(w, errors2.New("unauthorized"), nil, http.StatusForbidden)
return
Expand Down Expand Up @@ -620,7 +648,13 @@ func (handler *K8sApplicationRestHandlerImpl) GetPodLogs(w http.ResponseWriter,
// RBAC enforcer applying for Helm App
rbacObject, rbacObject2 := handler.enforcerUtilHelm.GetHelmObjectByClusterIdNamespaceAndAppName(request.AppIdentifier.ClusterId, request.AppIdentifier.Namespace, request.AppIdentifier.ReleaseName)
ok := handler.enforcer.Enforce(token, casbin.ResourceHelmApp, casbin.ActionGet, rbacObject) || handler.enforcer.Enforce(token, casbin.ResourceHelmApp, casbin.ActionGet, rbacObject2)

if !ok {
ok, err = handler.k8sCommonService.CheckRbacForCluster(request.ClusterId, token)
if err != nil {
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
}
if !ok {
common.WriteJsonResp(w, errors2.New("unauthorized"), nil, http.StatusForbidden)
return
Expand All @@ -634,7 +668,15 @@ func (handler *K8sApplicationRestHandlerImpl) GetPodLogs(w http.ResponseWriter,
}
// RBAC enforcer applying For Devtron App
envObject := handler.enforcerUtil.GetEnvRBACNameByAppId(request.DevtronAppIdentifier.AppId, request.DevtronAppIdentifier.EnvId)
if !handler.enforcer.Enforce(token, casbin.ResourceEnvironment, casbin.ActionGet, envObject) {
ok := handler.enforcer.Enforce(token, casbin.ResourceEnvironment, casbin.ActionGet, envObject)
if !ok {
ok, err = handler.k8sCommonService.CheckRbacForCluster(request.ClusterId, token)
if err != nil {
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
}
if !ok {
common.WriteJsonResp(w, errors2.New("unauthorized"), nil, http.StatusForbidden)
return
}
Expand Down
57 changes: 10 additions & 47 deletions api/k8s/capacity/k8sCapacityRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"github.com/devtron-labs/devtron/api/restHandler/common"
"github.com/devtron-labs/devtron/pkg/cluster"
"github.com/devtron-labs/devtron/pkg/k8s"
"github.com/devtron-labs/devtron/pkg/k8s/capacity"
"github.com/devtron-labs/devtron/pkg/k8s/capacity/bean"
"github.com/devtron-labs/devtron/pkg/user"
Expand All @@ -13,7 +14,6 @@ import (
"go.uber.org/zap"
"net/http"
"strconv"
"strings"
)

type K8sCapacityRestHandler interface {
Expand All @@ -35,20 +35,23 @@ type K8sCapacityRestHandlerImpl struct {
enforcer casbin.Enforcer
clusterService cluster.ClusterService
environmentService cluster.EnvironmentService
k8sCommonService k8s.K8sCommonService
}

func NewK8sCapacityRestHandlerImpl(logger *zap.SugaredLogger,
k8sCapacityService capacity.K8sCapacityService, userService user.UserService,
enforcer casbin.Enforcer,
clusterService cluster.ClusterService,
environmentService cluster.EnvironmentService) *K8sCapacityRestHandlerImpl {
environmentService cluster.EnvironmentService,
k8sCommonService k8s.K8sCommonService) *K8sCapacityRestHandlerImpl {
return &K8sCapacityRestHandlerImpl{
logger: logger,
k8sCapacityService: k8sCapacityService,
userService: userService,
enforcer: enforcer,
clusterService: clusterService,
environmentService: environmentService,
k8sCommonService: k8sCommonService,
}
}

Expand All @@ -69,7 +72,7 @@ func (handler *K8sCapacityRestHandlerImpl) GetClusterListRaw(w http.ResponseWrit
var authenticatedClusters []*cluster.ClusterBean
var clusterDetailList []*bean.ClusterCapacityDetail
for _, cluster := range clusters {
authenticated, err := handler.CheckRbacForCluster(cluster, token)
authenticated, err := handler.k8sCommonService.CheckRbacForCluster(cluster.Id, token)
if err != nil {
handler.logger.Errorw("error in checking rbac for cluster", "err", err, "clusterId", cluster.Id)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
Expand Down Expand Up @@ -109,7 +112,7 @@ func (handler *K8sCapacityRestHandlerImpl) GetClusterListWithDetail(w http.Respo
// RBAC enforcer applying
var authenticatedClusters []*cluster.ClusterBean
for _, cluster := range clusters {
authenticated, err := handler.CheckRbacForCluster(cluster, token)
authenticated, err := handler.k8sCommonService.CheckRbacForCluster(cluster.Id, token)
if err != nil {
handler.logger.Errorw("error in checking rbac for cluster", "err", err, "clusterId", cluster.Id)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
Expand Down Expand Up @@ -153,7 +156,7 @@ func (handler *K8sCapacityRestHandlerImpl) GetClusterDetail(w http.ResponseWrite
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
authenticated, err := handler.CheckRbacForCluster(cluster, token)
authenticated, err := handler.k8sCommonService.CheckRbacForCluster(cluster.Id, token)
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 @@ -193,7 +196,7 @@ func (handler *K8sCapacityRestHandlerImpl) GetNodeList(w http.ResponseWriter, r
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
authenticated, err := handler.CheckRbacForCluster(cluster, token)
authenticated, err := handler.k8sCommonService.CheckRbacForCluster(cluster.Id, token)
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 @@ -239,7 +242,7 @@ func (handler *K8sCapacityRestHandlerImpl) GetNodeDetail(w http.ResponseWriter,
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}
authenticated, err := handler.CheckRbacForCluster(cluster, token)
authenticated, err := handler.k8sCommonService.CheckRbacForCluster(cluster.Id, token)
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 @@ -402,43 +405,3 @@ func (handler *K8sCapacityRestHandlerImpl) EditNodeTaints(w http.ResponseWriter,
}
common.WriteJsonResp(w, nil, resp, http.StatusOK)
}

func (handler *K8sCapacityRestHandlerImpl) CheckRbacForCluster(cluster *cluster.ClusterBean, token string) (authenticated bool, err error) {
//getting all environments for this cluster
envs, err := handler.environmentService.GetByClusterId(cluster.Id)
if err != nil {
handler.logger.Errorw("error in getting environments by clusterId", "err", err, "clusterId", cluster.Id)
return false, err
}
if len(envs) == 0 {
if ok := handler.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionGet, "*"); !ok {
return false, nil
}
return true, nil
}
emailId, err := handler.userService.GetEmailFromToken(token)
if err != nil {
handler.logger.Errorw("error in getting emailId from token", "err", err)
return false, err
}

var envIdentifierList []string
envIdentifierMap := make(map[string]bool)
for _, env := range envs {
envIdentifier := strings.ToLower(env.EnvironmentIdentifier)
envIdentifierList = append(envIdentifierList, envIdentifier)
envIdentifierMap[envIdentifier] = true
}
if len(envIdentifierList) == 0 {
return false, errors.New("environment identifier list for rbac batch enforcing contains zero environments")
}
// RBAC enforcer applying
rbacResultMap := handler.enforcer.EnforceByEmailInBatch(emailId, casbin.ResourceGlobalEnvironment, casbin.ActionGet, envIdentifierList)
for envIdentifier, _ := range envIdentifierMap {
if rbacResultMap[envIdentifier] {
//if user has view permission to even one environment of this cluster, authorise the request
return true, nil
}
}
return false, nil
}
4 changes: 2 additions & 2 deletions cmd/external-app/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

55 changes: 54 additions & 1 deletion pkg/k8s/K8sCommonService.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ package k8s

import (
"context"
"errors"
"fmt"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
"github.com/caarlos0/env"
"github.com/devtron-labs/devtron/api/bean"
"github.com/devtron-labs/devtron/api/helm-app"
"github.com/devtron-labs/devtron/pkg/cluster"
bean3 "github.com/devtron-labs/devtron/pkg/k8s/application/bean"
"github.com/devtron-labs/devtron/pkg/user"
"github.com/devtron-labs/devtron/pkg/user/casbin"
"github.com/devtron-labs/devtron/util"
"github.com/devtron-labs/devtron/util/k8s"
"go.opentelemetry.io/otel"
Expand All @@ -20,6 +23,7 @@ import (
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/rest"
"strconv"
"strings"
"sync"
"time"
)
Expand All @@ -35,20 +39,26 @@ type K8sCommonService interface {
RotatePods(ctx context.Context, request *RotatePodRequest) (*RotatePodResponse, error)
GetCoreClientByClusterId(clusterId int) (*kubernetes.Clientset, *v1.CoreV1Client, error)
GetK8sServerVersion(clusterId int) (*version.Info, error)
CheckRbacForCluster(clusterId int, token string) (bool, error)
}
type K8sCommonServiceImpl struct {
logger *zap.SugaredLogger
K8sUtil *k8s.K8sUtil
clusterService cluster.ClusterService
K8sApplicationServiceConfig *K8sApplicationServiceConfig
environmentService cluster.EnvironmentService
userService user.UserService
enforcer casbin.Enforcer
}
type K8sApplicationServiceConfig struct {
BatchSize int `env:"BATCH_SIZE" envDefault:"5"`
TimeOutInSeconds int `env:"TIMEOUT_IN_SECONDS" envDefault:"5"`
}

func NewK8sCommonServiceImpl(Logger *zap.SugaredLogger, k8sUtils *k8s.K8sUtil,
clusterService cluster.ClusterService) *K8sCommonServiceImpl {
clusterService cluster.ClusterService, environmentService cluster.EnvironmentService,
userService user.UserService,
enforcer casbin.Enforcer) *K8sCommonServiceImpl {
cfg := &K8sApplicationServiceConfig{}
err := env.Parse(cfg)
if err != nil {
Expand All @@ -59,6 +69,9 @@ func NewK8sCommonServiceImpl(Logger *zap.SugaredLogger, k8sUtils *k8s.K8sUtil,
K8sUtil: k8sUtils,
clusterService: clusterService,
K8sApplicationServiceConfig: cfg,
environmentService: environmentService,
userService: userService,
enforcer: enforcer,
}
}

Expand Down Expand Up @@ -338,3 +351,43 @@ func (impl *K8sCommonServiceImpl) GetCoreClientByClusterId(clusterId int) (*kube
}
return clientSet, v1Client, nil
}

func (impl *K8sCommonServiceImpl) CheckRbacForCluster(clusterId int, token string) (authenticated bool, err error) {
//getting all environments for this cluster
envs, err := impl.environmentService.GetByClusterId(clusterId)
if err != nil {
impl.logger.Errorw("error in getting environments by clusterId", "err", err, "clusterId", clusterId)
return false, err
}
if len(envs) == 0 {
if ok := impl.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionGet, "*"); !ok {
return false, nil
}
return true, nil
}
emailId, err := impl.userService.GetEmailFromToken(token)
if err != nil {
impl.logger.Errorw("error in getting emailId from token", "err", err)
return false, err
}

var envIdentifierList []string
envIdentifierMap := make(map[string]bool)
for _, env := range envs {
envIdentifier := strings.ToLower(env.EnvironmentIdentifier)
envIdentifierList = append(envIdentifierList, envIdentifier)
envIdentifierMap[envIdentifier] = true
}
if len(envIdentifierList) == 0 {
return false, errors.New("environment identifier list for rbac batch enforcing contains zero environments")
}
// RBAC enforcer applying
rbacResultMap := impl.enforcer.EnforceByEmailInBatch(emailId, casbin.ResourceGlobalEnvironment, casbin.ActionGet, envIdentifierList)
for envIdentifier, _ := range envIdentifierMap {
if rbacResultMap[envIdentifier] {
//if user has view permission to even one environment of this cluster, authorise the request
return true, nil
}
}
return false, nil
}
Loading
Loading